@hexis-ai/engram-server 0.13.0 → 0.15.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/adapters/memory-key-store.d.ts +9 -0
- package/dist/adapters/memory-key-store.js +15 -0
- package/dist/adapters/memory.js +6 -0
- package/dist/adapters/postgres-key-store.d.ts +1 -0
- package/dist/adapters/postgres-key-store.js +7 -2
- package/dist/adapters/postgres-org-store.d.ts +0 -1
- package/dist/adapters/postgres-org-store.js +2 -3
- package/dist/adapters/postgres.js +19 -3
- package/dist/admin.d.ts +16 -16
- package/dist/admin.js +15 -102
- package/dist/key-store.d.ts +8 -0
- package/dist/main.js +6 -6
- package/dist/migrations/0008-trigger-metadata.d.ts +2 -0
- package/dist/migrations/0008-trigger-metadata.js +15 -0
- package/dist/migrations/index.js +2 -0
- package/dist/openapi.js +0 -89
- package/dist/org-store.d.ts +0 -6
- package/dist/schemas.d.ts +4 -0
- package/dist/schemas.js +4 -0
- package/dist/services/orgs.d.ts +10 -6
- package/dist/services/orgs.js +11 -7
- package/dist/storage.d.ts +2 -0
- package/dist/storage.js +6 -0
- package/openapi.json +40 -254
- package/package.json +3 -3
|
@@ -6,11 +6,20 @@ export declare class InMemoryKeyStore implements KeyStore {
|
|
|
6
6
|
private readonly workspaces;
|
|
7
7
|
private readonly keys;
|
|
8
8
|
private readonly byHash;
|
|
9
|
+
/** Mirror of engram_workspaces.org_id. Lookup-only — fakes / org-stores
|
|
10
|
+
* in tests read this to answer membership queries without re-tracking
|
|
11
|
+
* the binding themselves. */
|
|
12
|
+
private readonly orgIds;
|
|
9
13
|
createWorkspace(input: {
|
|
10
14
|
id?: string;
|
|
11
15
|
name?: string;
|
|
12
16
|
metadata?: Record<string, unknown>;
|
|
17
|
+
orgId?: string;
|
|
13
18
|
}): Promise<Workspace>;
|
|
19
|
+
/** Org id stamped on a workspace at creation, or undefined if not org-scoped. */
|
|
20
|
+
getWorkspaceOrgId(workspaceId: string): string | undefined;
|
|
21
|
+
/** All (workspaceId, orgId) pairs. Read-only view for fakes. */
|
|
22
|
+
workspaceOrgBindings(): ReadonlyMap<string, string>;
|
|
14
23
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
15
24
|
listWorkspaces(): Promise<Workspace[]>;
|
|
16
25
|
updateWorkspace(id: string, patch: {
|
|
@@ -6,6 +6,10 @@ export class InMemoryKeyStore {
|
|
|
6
6
|
workspaces = new Map();
|
|
7
7
|
keys = new Map();
|
|
8
8
|
byHash = new Map();
|
|
9
|
+
/** Mirror of engram_workspaces.org_id. Lookup-only — fakes / org-stores
|
|
10
|
+
* in tests read this to answer membership queries without re-tracking
|
|
11
|
+
* the binding themselves. */
|
|
12
|
+
orgIds = new Map();
|
|
9
13
|
async createWorkspace(input) {
|
|
10
14
|
const id = resolveWorkspaceId(input);
|
|
11
15
|
const existing = this.workspaces.get(id);
|
|
@@ -18,8 +22,18 @@ export class InMemoryKeyStore {
|
|
|
18
22
|
createdAt: new Date().toISOString(),
|
|
19
23
|
};
|
|
20
24
|
this.workspaces.set(id, ws);
|
|
25
|
+
if (input.orgId !== undefined)
|
|
26
|
+
this.orgIds.set(id, input.orgId);
|
|
21
27
|
return ws;
|
|
22
28
|
}
|
|
29
|
+
/** Org id stamped on a workspace at creation, or undefined if not org-scoped. */
|
|
30
|
+
getWorkspaceOrgId(workspaceId) {
|
|
31
|
+
return this.orgIds.get(workspaceId);
|
|
32
|
+
}
|
|
33
|
+
/** All (workspaceId, orgId) pairs. Read-only view for fakes. */
|
|
34
|
+
workspaceOrgBindings() {
|
|
35
|
+
return this.orgIds;
|
|
36
|
+
}
|
|
23
37
|
async getWorkspace(id) {
|
|
24
38
|
return this.workspaces.get(id) ?? null;
|
|
25
39
|
}
|
|
@@ -40,6 +54,7 @@ export class InMemoryKeyStore {
|
|
|
40
54
|
}
|
|
41
55
|
async deleteWorkspace(id) {
|
|
42
56
|
this.workspaces.delete(id);
|
|
57
|
+
this.orgIds.delete(id);
|
|
43
58
|
for (const [keyId, row] of this.keys) {
|
|
44
59
|
if (row.workspaceId === id) {
|
|
45
60
|
this.byHash.delete(row.keyHash);
|
package/dist/adapters/memory.js
CHANGED
|
@@ -42,6 +42,12 @@ export class InMemoryAdapter {
|
|
|
42
42
|
...(init.trigger_event_id != null
|
|
43
43
|
? { trigger_event_id: init.trigger_event_id }
|
|
44
44
|
: {}),
|
|
45
|
+
...(init.trigger_purpose != null
|
|
46
|
+
? { trigger_purpose: init.trigger_purpose }
|
|
47
|
+
: {}),
|
|
48
|
+
...(init.trigger_resume_hint != null
|
|
49
|
+
? { trigger_resume_hint: init.trigger_resume_hint }
|
|
50
|
+
: {}),
|
|
45
51
|
},
|
|
46
52
|
events: new Map(),
|
|
47
53
|
});
|
|
@@ -12,6 +12,7 @@ export declare class PostgresKeyStore implements KeyStore {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
name?: string;
|
|
14
14
|
metadata?: Record<string, unknown>;
|
|
15
|
+
orgId?: string;
|
|
15
16
|
}): Promise<Workspace>;
|
|
16
17
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
17
18
|
listWorkspaces(): Promise<Workspace[]>;
|
|
@@ -16,8 +16,13 @@ export class PostgresKeyStore {
|
|
|
16
16
|
async createWorkspace(input) {
|
|
17
17
|
const id = resolveWorkspaceId(input);
|
|
18
18
|
await this.sql `
|
|
19
|
-
INSERT INTO engram_workspaces (id, name, metadata)
|
|
20
|
-
VALUES (
|
|
19
|
+
INSERT INTO engram_workspaces (id, name, metadata, org_id)
|
|
20
|
+
VALUES (
|
|
21
|
+
${id},
|
|
22
|
+
${input.name ?? null},
|
|
23
|
+
${(input.metadata ?? {})},
|
|
24
|
+
${input.orgId ?? null}
|
|
25
|
+
)
|
|
21
26
|
ON CONFLICT (id) DO NOTHING
|
|
22
27
|
`;
|
|
23
28
|
const ws = await this.getWorkspace(id);
|
|
@@ -27,7 +27,6 @@ export declare class PostgresOrgStore implements OrgStore {
|
|
|
27
27
|
email: string;
|
|
28
28
|
} | null>;
|
|
29
29
|
listOrgsForUser(userId: string): Promise<OrgMembershipRow[]>;
|
|
30
|
-
setWorkspaceOrg(workspaceId: string, orgId: string): Promise<void>;
|
|
31
30
|
listWorkspacesForOrg(orgId: string): Promise<{
|
|
32
31
|
id: string;
|
|
33
32
|
name: string | null;
|
|
@@ -89,9 +89,8 @@ export class PostgresOrgStore {
|
|
|
89
89
|
return rows.map(toMember);
|
|
90
90
|
}
|
|
91
91
|
// ---------- workspace ↔ org link -----------------------------
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
92
|
+
// engram_workspaces.org_id is written by KeyStore.createWorkspace in
|
|
93
|
+
// the same INSERT as the workspace row. This store only reads.
|
|
95
94
|
async listWorkspacesForOrg(orgId) {
|
|
96
95
|
const { rows } = await this.pool.query(`SELECT id, name FROM engram_workspaces WHERE org_id = $1 ORDER BY created_at`, [orgId]);
|
|
97
96
|
return rows;
|
|
@@ -31,7 +31,8 @@ export class PostgresAdapter {
|
|
|
31
31
|
INSERT INTO engram_sessions (
|
|
32
32
|
workspace_id, id, title, channel, participants, viewable_by,
|
|
33
33
|
created_at, updated_at, status, summary, model,
|
|
34
|
-
trigger_conversation_id, trigger_event_id
|
|
34
|
+
trigger_conversation_id, trigger_event_id,
|
|
35
|
+
trigger_purpose, trigger_resume_hint
|
|
35
36
|
)
|
|
36
37
|
VALUES (
|
|
37
38
|
${this.workspaceId},
|
|
@@ -46,7 +47,9 @@ export class PostgresAdapter {
|
|
|
46
47
|
${init.summary ?? null},
|
|
47
48
|
${init.model ?? null},
|
|
48
49
|
${init.trigger_conversation_id ?? null},
|
|
49
|
-
${init.trigger_event_id ?? null}
|
|
50
|
+
${init.trigger_event_id ?? null},
|
|
51
|
+
${init.trigger_purpose ?? null},
|
|
52
|
+
${init.trigger_resume_hint ?? null}
|
|
50
53
|
)
|
|
51
54
|
ON CONFLICT (workspace_id, id) DO NOTHING
|
|
52
55
|
`;
|
|
@@ -97,7 +100,8 @@ export class PostgresAdapter {
|
|
|
97
100
|
const rows = await this.sql `
|
|
98
101
|
SELECT id, title, channel, participants, viewable_by, created_at,
|
|
99
102
|
updated_at, status, summary, model,
|
|
100
|
-
trigger_conversation_id, trigger_event_id
|
|
103
|
+
trigger_conversation_id, trigger_event_id,
|
|
104
|
+
trigger_purpose, trigger_resume_hint
|
|
101
105
|
FROM engram_sessions
|
|
102
106
|
WHERE workspace_id = ${this.workspaceId} AND id = ${sessionId}
|
|
103
107
|
LIMIT 1
|
|
@@ -122,6 +126,8 @@ export class PostgresAdapter {
|
|
|
122
126
|
const model = pickPatch(patch, "model");
|
|
123
127
|
const tcId = pickPatch(patch, "trigger_conversation_id");
|
|
124
128
|
const teId = pickPatch(patch, "trigger_event_id");
|
|
129
|
+
const tPurpose = pickPatch(patch, "trigger_purpose");
|
|
130
|
+
const tResume = pickPatch(patch, "trigger_resume_hint");
|
|
125
131
|
const rows = await this.sql `
|
|
126
132
|
UPDATE engram_sessions SET
|
|
127
133
|
title = CASE WHEN ${title.provided} THEN ${title.value} ELSE title END,
|
|
@@ -133,6 +139,10 @@ export class PostgresAdapter {
|
|
|
133
139
|
THEN ${tcId.value} ELSE trigger_conversation_id END,
|
|
134
140
|
trigger_event_id = CASE WHEN ${teId.provided}
|
|
135
141
|
THEN ${teId.value} ELSE trigger_event_id END,
|
|
142
|
+
trigger_purpose = CASE WHEN ${tPurpose.provided}
|
|
143
|
+
THEN ${tPurpose.value} ELSE trigger_purpose END,
|
|
144
|
+
trigger_resume_hint = CASE WHEN ${tResume.provided}
|
|
145
|
+
THEN ${tResume.value} ELSE trigger_resume_hint END,
|
|
136
146
|
updated_at = now()
|
|
137
147
|
WHERE workspace_id = ${this.workspaceId} AND id = ${sessionId}
|
|
138
148
|
RETURNING id
|
|
@@ -474,6 +484,12 @@ function toSessionRow(r) {
|
|
|
474
484
|
...(r.trigger_event_id !== null
|
|
475
485
|
? { trigger_event_id: r.trigger_event_id }
|
|
476
486
|
: {}),
|
|
487
|
+
...(r.trigger_purpose !== null
|
|
488
|
+
? { trigger_purpose: r.trigger_purpose }
|
|
489
|
+
: {}),
|
|
490
|
+
...(r.trigger_resume_hint !== null
|
|
491
|
+
? { trigger_resume_hint: r.trigger_resume_hint }
|
|
492
|
+
: {}),
|
|
477
493
|
};
|
|
478
494
|
}
|
|
479
495
|
function toAliasInfo(r) {
|
package/dist/admin.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import {
|
|
2
|
+
import type { KeyStore } from "./key-store";
|
|
3
3
|
import type { OrgStore } from "./org-store";
|
|
4
4
|
export interface AdminOptions {
|
|
5
5
|
/** Bearer token required for every /admin/v1 request. */
|
|
6
6
|
token: string;
|
|
7
7
|
keyStore: KeyStore;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
* (
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Org store. Required — every admin endpoint is org-scoped.
|
|
10
|
+
* (The previous opt-out, where admin.ts also exposed a non-org
|
|
11
|
+
* `/admin/v1/workspaces` surface for `orgStore`-less deployments,
|
|
12
|
+
* was removed in v0.15.)
|
|
13
13
|
*/
|
|
14
|
-
orgStore
|
|
14
|
+
orgStore: OrgStore;
|
|
15
15
|
}
|
|
16
16
|
interface Env {
|
|
17
17
|
Variables: {
|
|
@@ -24,20 +24,20 @@ interface Env {
|
|
|
24
24
|
* Auth model: a single platform-level bearer token
|
|
25
25
|
* (\`ENGRAM_ADMIN_TOKEN\`). Never crosses with workspace api-keys.
|
|
26
26
|
*
|
|
27
|
-
* Surface
|
|
27
|
+
* Surface:
|
|
28
28
|
*
|
|
29
|
-
* POST /orgs
|
|
30
|
-
* GET /orgs
|
|
31
|
-
* GET /orgs/:id
|
|
32
|
-
* DELETE /orgs/:id
|
|
33
|
-
* POST /orgs/:id/members
|
|
29
|
+
* POST /orgs create org
|
|
30
|
+
* GET /orgs list orgs
|
|
31
|
+
* GET /orgs/:id get org
|
|
32
|
+
* DELETE /orgs/:id delete org (CASCADE)
|
|
33
|
+
* POST /orgs/:id/members add member (email|userId)
|
|
34
34
|
* GET /orgs/:id/members
|
|
35
35
|
* DELETE /orgs/:id/members/:userId
|
|
36
|
-
* POST /orgs/:id/workspaces
|
|
36
|
+
* POST /orgs/:id/workspaces create workspace + key
|
|
37
37
|
* GET /orgs/:id/workspaces
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* GET /orgs/:id/workspaces/:wsId/keys list workspace keys
|
|
39
|
+
* POST /orgs/:id/workspaces/:wsId/keys issue a new key
|
|
40
|
+
* DELETE /orgs/:id/workspaces/:wsId/keys/:keyId revoke a key
|
|
41
41
|
*/
|
|
42
42
|
export declare function createAdminRouter(opts: AdminOptions): Hono<Env>;
|
|
43
43
|
export {};
|
package/dist/admin.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { isValidWorkspaceId } from "./key-store";
|
|
3
2
|
import { createWorkspaceSchema, issueKeySchema, parseJsonBody } from "./schemas";
|
|
4
3
|
import { addMember, createOrg, createWorkspaceUnderOrg, deleteOrg, getOrgOrThrow, OrgServiceError, removeMember, requireWorkspaceInOrg, revokeWorkspaceKey, } from "./services/orgs";
|
|
5
4
|
/**
|
|
@@ -8,23 +7,25 @@ import { addMember, createOrg, createWorkspaceUnderOrg, deleteOrg, getOrgOrThrow
|
|
|
8
7
|
* Auth model: a single platform-level bearer token
|
|
9
8
|
* (\`ENGRAM_ADMIN_TOKEN\`). Never crosses with workspace api-keys.
|
|
10
9
|
*
|
|
11
|
-
* Surface
|
|
10
|
+
* Surface:
|
|
12
11
|
*
|
|
13
|
-
* POST /orgs
|
|
14
|
-
* GET /orgs
|
|
15
|
-
* GET /orgs/:id
|
|
16
|
-
* DELETE /orgs/:id
|
|
17
|
-
* POST /orgs/:id/members
|
|
12
|
+
* POST /orgs create org
|
|
13
|
+
* GET /orgs list orgs
|
|
14
|
+
* GET /orgs/:id get org
|
|
15
|
+
* DELETE /orgs/:id delete org (CASCADE)
|
|
16
|
+
* POST /orgs/:id/members add member (email|userId)
|
|
18
17
|
* GET /orgs/:id/members
|
|
19
18
|
* DELETE /orgs/:id/members/:userId
|
|
20
|
-
* POST /orgs/:id/workspaces
|
|
19
|
+
* POST /orgs/:id/workspaces create workspace + key
|
|
21
20
|
* GET /orgs/:id/workspaces
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* GET /orgs/:id/workspaces/:wsId/keys list workspace keys
|
|
22
|
+
* POST /orgs/:id/workspaces/:wsId/keys issue a new key
|
|
23
|
+
* DELETE /orgs/:id/workspaces/:wsId/keys/:keyId revoke a key
|
|
25
24
|
*/
|
|
26
25
|
export function createAdminRouter(opts) {
|
|
27
26
|
const app = new Hono();
|
|
27
|
+
const { orgStore } = opts;
|
|
28
|
+
const deps = { orgStore, keyStore: opts.keyStore };
|
|
28
29
|
app.use("*", async (c, next) => {
|
|
29
30
|
const supplied = c.req.header("x-admin-token") ??
|
|
30
31
|
c.req.header("authorization")?.match(/^Bearer\s+(.+)$/i)?.[1];
|
|
@@ -33,94 +34,6 @@ export function createAdminRouter(opts) {
|
|
|
33
34
|
}
|
|
34
35
|
await next();
|
|
35
36
|
});
|
|
36
|
-
// -------------------- workspaces (legacy / api-key-only) ----
|
|
37
|
-
// Kept for backwards compatibility; new callers should create
|
|
38
|
-
// workspaces under an org so they're reachable from the web UI.
|
|
39
|
-
app.post("/workspaces", async (c) => {
|
|
40
|
-
const body = await parseJsonBody(c, createWorkspaceSchema);
|
|
41
|
-
if (body instanceof Response)
|
|
42
|
-
return body;
|
|
43
|
-
if (body.id !== undefined && !isValidWorkspaceId(body.id)) {
|
|
44
|
-
return c.json({ error: "invalid_workspace_id" }, 400);
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
const ws = await opts.keyStore.createWorkspace({
|
|
48
|
-
...(body.id !== undefined ? { id: body.id } : {}),
|
|
49
|
-
...(body.name !== undefined ? { name: body.name } : {}),
|
|
50
|
-
...(body.metadata !== undefined ? { metadata: body.metadata } : {}),
|
|
51
|
-
});
|
|
52
|
-
if (body.issueKey === false) {
|
|
53
|
-
return c.json({ workspace: ws });
|
|
54
|
-
}
|
|
55
|
-
const key = await opts.keyStore.issueKey(ws.id, {
|
|
56
|
-
...(body.keyName !== undefined ? { name: body.keyName } : {}),
|
|
57
|
-
});
|
|
58
|
-
return c.json({ workspace: ws, key });
|
|
59
|
-
}
|
|
60
|
-
catch (e) {
|
|
61
|
-
return c.json({ error: e.message }, 400);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
app.get("/workspaces", async (c) => {
|
|
65
|
-
const workspaces = await opts.keyStore.listWorkspaces();
|
|
66
|
-
return c.json({ workspaces });
|
|
67
|
-
});
|
|
68
|
-
app.get("/workspaces/:id", async (c) => {
|
|
69
|
-
const ws = await opts.keyStore.getWorkspace(c.req.param("id"));
|
|
70
|
-
if (!ws)
|
|
71
|
-
return c.json({ error: "workspace_not_found" }, 404);
|
|
72
|
-
return c.json(ws);
|
|
73
|
-
});
|
|
74
|
-
app.delete("/workspaces/:id", async (c) => {
|
|
75
|
-
const id = c.req.param("id");
|
|
76
|
-
const ws = await opts.keyStore.getWorkspace(id);
|
|
77
|
-
if (!ws)
|
|
78
|
-
return c.json({ error: "workspace_not_found" }, 404);
|
|
79
|
-
await opts.keyStore.deleteWorkspace(id);
|
|
80
|
-
return c.body(null, 204);
|
|
81
|
-
});
|
|
82
|
-
app.post("/workspaces/:id/keys", async (c) => {
|
|
83
|
-
const workspaceId = c.req.param("id");
|
|
84
|
-
const ws = await opts.keyStore.getWorkspace(workspaceId);
|
|
85
|
-
if (!ws)
|
|
86
|
-
return c.json({ error: "workspace_not_found" }, 404);
|
|
87
|
-
const raw = await c.req.json().catch(() => ({}));
|
|
88
|
-
const parsed = issueKeySchema.safeParse(raw);
|
|
89
|
-
if (!parsed.success) {
|
|
90
|
-
return c.json({ error: "invalid_body", issues: parsed.error.issues }, 400);
|
|
91
|
-
}
|
|
92
|
-
const key = await opts.keyStore.issueKey(workspaceId, {
|
|
93
|
-
...(parsed.data.name !== undefined ? { name: parsed.data.name } : {}),
|
|
94
|
-
});
|
|
95
|
-
return c.json(key);
|
|
96
|
-
});
|
|
97
|
-
app.get("/workspaces/:id/keys", async (c) => {
|
|
98
|
-
const workspaceId = c.req.param("id");
|
|
99
|
-
const ws = await opts.keyStore.getWorkspace(workspaceId);
|
|
100
|
-
if (!ws)
|
|
101
|
-
return c.json({ error: "workspace_not_found" }, 404);
|
|
102
|
-
const keys = await opts.keyStore.listKeys(workspaceId);
|
|
103
|
-
return c.json({ keys });
|
|
104
|
-
});
|
|
105
|
-
app.delete("/workspaces/:id/keys/:keyId", async (c) => {
|
|
106
|
-
const workspaceId = c.req.param("id");
|
|
107
|
-
const keyId = c.req.param("keyId");
|
|
108
|
-
try {
|
|
109
|
-
await opts.keyStore.revokeKey(workspaceId, keyId);
|
|
110
|
-
}
|
|
111
|
-
catch (e) {
|
|
112
|
-
if (e.message === "key_not_found") {
|
|
113
|
-
return c.json({ error: "key_not_found" }, 404);
|
|
114
|
-
}
|
|
115
|
-
throw e;
|
|
116
|
-
}
|
|
117
|
-
return c.body(null, 204);
|
|
118
|
-
});
|
|
119
|
-
// -------------------- orgs (org-scoped admin surface) -------
|
|
120
|
-
const orgStore = opts.orgStore;
|
|
121
|
-
if (!orgStore)
|
|
122
|
-
return app;
|
|
123
|
-
const deps = { orgStore, keyStore: opts.keyStore };
|
|
124
37
|
app.post("/orgs", async (c) => runService(c, async () => {
|
|
125
38
|
const body = (await c.req.json().catch(() => ({})));
|
|
126
39
|
const org = await createOrg(deps, body);
|
|
@@ -158,9 +71,9 @@ export function createAdminRouter(opts) {
|
|
|
158
71
|
return c.body(null, 204);
|
|
159
72
|
}));
|
|
160
73
|
// ----- org workspaces ---------------------------------------
|
|
161
|
-
// Stands up a tenant
|
|
162
|
-
//
|
|
163
|
-
//
|
|
74
|
+
// Stands up a tenant. createWorkspaceUnderOrg writes the workspace
|
|
75
|
+
// + org binding in a single INSERT (atomic) and then issues the
|
|
76
|
+
// initial API key (separate insert; retry-safe via ON CONFLICT).
|
|
164
77
|
app.post("/orgs/:id/workspaces", async (c) => runService(c, async () => {
|
|
165
78
|
const orgId = c.req.param("id");
|
|
166
79
|
await getOrgOrThrow(deps, orgId);
|
package/dist/key-store.d.ts
CHANGED
|
@@ -29,10 +29,18 @@ export interface KeyResolution {
|
|
|
29
29
|
keyId: string;
|
|
30
30
|
}
|
|
31
31
|
export interface KeyStore {
|
|
32
|
+
/**
|
|
33
|
+
* Persist a workspace row. `orgId`, when supplied, lands in the same
|
|
34
|
+
* INSERT so the workspace and its org binding are committed atomically
|
|
35
|
+
* (no orphaned workspace if a follow-up `setWorkspaceOrg` would have
|
|
36
|
+
* failed). Legacy callers without an org still work — `org_id` stays
|
|
37
|
+
* NULL.
|
|
38
|
+
*/
|
|
32
39
|
createWorkspace(input: {
|
|
33
40
|
id?: string;
|
|
34
41
|
name?: string;
|
|
35
42
|
metadata?: Record<string, unknown>;
|
|
43
|
+
orgId?: string;
|
|
36
44
|
}): Promise<Workspace>;
|
|
37
45
|
getWorkspace(id: string): Promise<Workspace | null>;
|
|
38
46
|
listWorkspaces(): Promise<Workspace[]>;
|
package/dist/main.js
CHANGED
|
@@ -22,6 +22,10 @@ const CORS_ORIGINS = (process.env.ENGRAM_CORS_ORIGINS ?? "")
|
|
|
22
22
|
.split(",")
|
|
23
23
|
.map((s) => s.trim())
|
|
24
24
|
.filter(Boolean);
|
|
25
|
+
if (!orgStore) {
|
|
26
|
+
console.error("[engram-server] orgStore is required (DATABASE_URL + ENGRAM_AUTH_* env vars) — every admin endpoint is now org-scoped");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
25
29
|
const app = createServer({
|
|
26
30
|
auth: async (key) => {
|
|
27
31
|
const r = await keyStore.resolveKey(key);
|
|
@@ -31,14 +35,10 @@ const app = createServer({
|
|
|
31
35
|
},
|
|
32
36
|
...(authHandler ? { authHandler } : {}),
|
|
33
37
|
...(cookieAuth ? { cookieAuth } : {}),
|
|
34
|
-
|
|
38
|
+
orgStore,
|
|
35
39
|
keyStore,
|
|
36
40
|
...(CORS_ORIGINS.length > 0 ? { corsOrigins: CORS_ORIGINS } : {}),
|
|
37
|
-
admin: {
|
|
38
|
-
token: ADMIN_TOKEN,
|
|
39
|
-
keyStore,
|
|
40
|
-
...(orgStore ? { orgStore } : {}),
|
|
41
|
-
},
|
|
41
|
+
admin: { token: ADMIN_TOKEN, keyStore, orgStore },
|
|
42
42
|
});
|
|
43
43
|
console.log(`[engram-server] listening on :${PORT}`);
|
|
44
44
|
export default { port: PORT, fetch: app.fetch };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const name = "0008-trigger-metadata";
|
|
2
|
+
export declare const sql = "\n-- Hosts that open a side-conversation with a stated goal (monet's\n-- start_conversation tool) need to thread two free-text fields through\n-- engram for the agent's resume flow:\n--\n-- trigger_purpose what this side-conv exists to accomplish\n-- trigger_resume_hint the condition that should resume the parent\n--\n-- Both are opaque to engram \u2014 we store and serve them verbatim. Nullable\n-- because most sessions aren't side-conversations.\n\nALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_purpose TEXT;\nALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_resume_hint TEXT;\n";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const name = "0008-trigger-metadata";
|
|
2
|
+
export const sql = `
|
|
3
|
+
-- Hosts that open a side-conversation with a stated goal (monet's
|
|
4
|
+
-- start_conversation tool) need to thread two free-text fields through
|
|
5
|
+
-- engram for the agent's resume flow:
|
|
6
|
+
--
|
|
7
|
+
-- trigger_purpose what this side-conv exists to accomplish
|
|
8
|
+
-- trigger_resume_hint the condition that should resume the parent
|
|
9
|
+
--
|
|
10
|
+
-- Both are opaque to engram — we store and serve them verbatim. Nullable
|
|
11
|
+
-- because most sessions aren't side-conversations.
|
|
12
|
+
|
|
13
|
+
ALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_purpose TEXT;
|
|
14
|
+
ALTER TABLE engram_sessions ADD COLUMN IF NOT EXISTS trigger_resume_hint TEXT;
|
|
15
|
+
`;
|
package/dist/migrations/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as m0004 from "./0004-schema-completion";
|
|
|
5
5
|
import * as m0005 from "./0005-session-updated-at";
|
|
6
6
|
import * as m0006 from "./0006-auth";
|
|
7
7
|
import * as m0007 from "./0007-orgs";
|
|
8
|
+
import * as m0008 from "./0008-trigger-metadata";
|
|
8
9
|
/**
|
|
9
10
|
* Schema migrations, applied in array order. Add a new file under
|
|
10
11
|
* `migrations/NNNN-<slug>.ts` exporting `name` and `sql`, then append it
|
|
@@ -20,4 +21,5 @@ export const MIGRATIONS = [
|
|
|
20
21
|
{ name: m0005.name, sql: m0005.sql },
|
|
21
22
|
{ name: m0006.name, sql: m0006.sql },
|
|
22
23
|
{ name: m0007.name, sql: m0007.sql },
|
|
24
|
+
{ name: m0008.name, sql: m0008.sql },
|
|
23
25
|
];
|
package/dist/openapi.js
CHANGED
|
@@ -71,14 +71,6 @@ const TAG_DEFS = [
|
|
|
71
71
|
name: "Orgs (admin)",
|
|
72
72
|
description: "プラットフォーム管理者トークンでの org 管理",
|
|
73
73
|
},
|
|
74
|
-
{
|
|
75
|
-
name: "Workspaces (admin)",
|
|
76
|
-
description: "ワークスペースの管理(管理者トークン必須)",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "API Keys (admin)",
|
|
80
|
-
description: "ワークスペース API キーの発行・無効化(管理者トークン必須)",
|
|
81
|
-
},
|
|
82
74
|
];
|
|
83
75
|
/**
|
|
84
76
|
* Stamp `tag` onto every operation in a path-item. The path declares its
|
|
@@ -634,87 +626,6 @@ function buildPaths() {
|
|
|
634
626
|
},
|
|
635
627
|
},
|
|
636
628
|
}),
|
|
637
|
-
"/admin/v1/workspaces": tagged("Workspaces (admin)", {
|
|
638
|
-
post: {
|
|
639
|
-
summary: "ワークスペースを作成する(デフォルトで初期キーも発行する)。",
|
|
640
|
-
security: adminAuth,
|
|
641
|
-
requestBody: jsonBody("CreateWorkspace"),
|
|
642
|
-
responses: {
|
|
643
|
-
"200": res("ワークスペース(issueKey=false でない限りキーも含む)"),
|
|
644
|
-
"400": res("リクエストボディまたはワークスペース id が不正"),
|
|
645
|
-
"401": res("認証エラー"),
|
|
646
|
-
},
|
|
647
|
-
},
|
|
648
|
-
get: {
|
|
649
|
-
summary: "全ワークスペースを一覧取得する。",
|
|
650
|
-
security: adminAuth,
|
|
651
|
-
responses: {
|
|
652
|
-
"200": res("ワークスペース一覧"),
|
|
653
|
-
"401": res("認証エラー"),
|
|
654
|
-
},
|
|
655
|
-
},
|
|
656
|
-
}),
|
|
657
|
-
"/admin/v1/workspaces/{id}": tagged("Workspaces (admin)", {
|
|
658
|
-
get: {
|
|
659
|
-
summary: "単一のワークスペースを取得する。",
|
|
660
|
-
security: adminAuth,
|
|
661
|
-
parameters: [pathParam("id", "ワークスペース id。")],
|
|
662
|
-
responses: {
|
|
663
|
-
"200": res("ワークスペース"),
|
|
664
|
-
"404": res("ワークスペースが見つからない"),
|
|
665
|
-
"401": res("認証エラー"),
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
delete: {
|
|
669
|
-
summary: "ワークスペースを削除する(キー・セッション・イベントにカスケードする)。",
|
|
670
|
-
security: adminAuth,
|
|
671
|
-
parameters: [pathParam("id", "ワークスペース id。")],
|
|
672
|
-
responses: {
|
|
673
|
-
"204": res("削除完了"),
|
|
674
|
-
"404": res("ワークスペースが見つからない"),
|
|
675
|
-
"401": res("認証エラー"),
|
|
676
|
-
},
|
|
677
|
-
},
|
|
678
|
-
}),
|
|
679
|
-
"/admin/v1/workspaces/{id}/keys": tagged("API Keys (admin)", {
|
|
680
|
-
post: {
|
|
681
|
-
summary: "ワークスペースに新しい API キーを発行する。",
|
|
682
|
-
security: adminAuth,
|
|
683
|
-
parameters: [pathParam("id", "ワークスペース id。")],
|
|
684
|
-
requestBody: jsonBody("IssueKey", false),
|
|
685
|
-
responses: {
|
|
686
|
-
"200": res("発行されたキー(生のキーは一度のみ返却)"),
|
|
687
|
-
"400": res("リクエストボディが不正"),
|
|
688
|
-
"404": res("ワークスペースが見つからない"),
|
|
689
|
-
"401": res("認証エラー"),
|
|
690
|
-
},
|
|
691
|
-
},
|
|
692
|
-
get: {
|
|
693
|
-
summary: "ワークスペースの API キー一覧を取得する(ハッシュのみ)。",
|
|
694
|
-
security: adminAuth,
|
|
695
|
-
parameters: [pathParam("id", "ワークスペース id。")],
|
|
696
|
-
responses: {
|
|
697
|
-
"200": res("キー一覧"),
|
|
698
|
-
"404": res("ワークスペースが見つからない"),
|
|
699
|
-
"401": res("認証エラー"),
|
|
700
|
-
},
|
|
701
|
-
},
|
|
702
|
-
}),
|
|
703
|
-
"/admin/v1/workspaces/{id}/keys/{keyId}": tagged("API Keys (admin)", {
|
|
704
|
-
delete: {
|
|
705
|
-
summary: "API キーを無効化する。",
|
|
706
|
-
security: adminAuth,
|
|
707
|
-
parameters: [
|
|
708
|
-
pathParam("id", "ワークスペース id。"),
|
|
709
|
-
pathParam("keyId", "キー id。"),
|
|
710
|
-
],
|
|
711
|
-
responses: {
|
|
712
|
-
"204": res("無効化完了(冪等)"),
|
|
713
|
-
"404": res("キーが見つからない"),
|
|
714
|
-
"401": res("認証エラー"),
|
|
715
|
-
},
|
|
716
|
-
},
|
|
717
|
-
}),
|
|
718
629
|
};
|
|
719
630
|
}
|
|
720
631
|
/**
|
package/dist/org-store.d.ts
CHANGED
|
@@ -48,12 +48,6 @@ export interface OrgStore {
|
|
|
48
48
|
} | null>;
|
|
49
49
|
/** Orgs the given user is a member of. */
|
|
50
50
|
listOrgsForUser(userId: string): Promise<OrgMembershipRow[]>;
|
|
51
|
-
/**
|
|
52
|
-
* Set the org an already-existing workspace belongs to. Called
|
|
53
|
-
* by the admin endpoint that creates a workspace under an org
|
|
54
|
-
* (key issuance and engram_workspaces.org_id are written together).
|
|
55
|
-
*/
|
|
56
|
-
setWorkspaceOrg(workspaceId: string, orgId: string): Promise<void>;
|
|
57
51
|
/** Workspaces in the given org. */
|
|
58
52
|
listWorkspacesForOrg(orgId: string): Promise<{
|
|
59
53
|
id: string;
|
package/dist/schemas.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare const sessionInitSchema: z.ZodObject<{
|
|
|
24
24
|
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
25
25
|
trigger_conversation_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
26
26
|
trigger_event_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
|
+
trigger_purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
28
|
+
trigger_resume_hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
27
29
|
}, z.core.$strip>;
|
|
28
30
|
export declare const sessionUpdateSchema: z.ZodObject<{
|
|
29
31
|
title: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -37,6 +39,8 @@ export declare const sessionUpdateSchema: z.ZodObject<{
|
|
|
37
39
|
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
38
40
|
trigger_conversation_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
41
|
trigger_event_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
42
|
+
trigger_purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
43
|
+
trigger_resume_hint: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
44
|
}, z.core.$strip>;
|
|
41
45
|
export declare const sessionEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
42
46
|
type: z.ZodLiteral<"step">;
|
package/dist/schemas.js
CHANGED
|
@@ -20,6 +20,8 @@ export const sessionInitSchema = z.object({
|
|
|
20
20
|
model: z.string().nullable().optional(),
|
|
21
21
|
trigger_conversation_id: z.string().nullable().optional(),
|
|
22
22
|
trigger_event_id: z.string().nullable().optional(),
|
|
23
|
+
trigger_purpose: z.string().nullable().optional(),
|
|
24
|
+
trigger_resume_hint: z.string().nullable().optional(),
|
|
23
25
|
});
|
|
24
26
|
export const sessionUpdateSchema = z.object({
|
|
25
27
|
title: z.string().nullable().optional(),
|
|
@@ -29,6 +31,8 @@ export const sessionUpdateSchema = z.object({
|
|
|
29
31
|
model: z.string().nullable().optional(),
|
|
30
32
|
trigger_conversation_id: z.string().nullable().optional(),
|
|
31
33
|
trigger_event_id: z.string().nullable().optional(),
|
|
34
|
+
trigger_purpose: z.string().nullable().optional(),
|
|
35
|
+
trigger_resume_hint: z.string().nullable().optional(),
|
|
32
36
|
});
|
|
33
37
|
const stepEventSchema = z.object({
|
|
34
38
|
type: z.literal("step"),
|
package/dist/services/orgs.d.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* (`/admin/v1/*`) and the cookie-auth self-service surface (`/v1/orgs/*`).
|
|
4
4
|
*
|
|
5
5
|
* Auth and HTTP framing stay in the route modules. This file owns:
|
|
6
|
-
* - the multi-step orchestrations (
|
|
7
|
-
* +
|
|
6
|
+
* - the multi-step orchestrations (createWorkspaceUnderOrg writes
|
|
7
|
+
* the workspace + org binding atomically and then issues a key;
|
|
8
|
+
* email→userId lookup + upsertMember)
|
|
8
9
|
* - the safety invariants (workspace id validation, last-owner
|
|
9
10
|
* protection on member removal)
|
|
10
11
|
* - the canonical error → status mapping (OrgServiceError.status)
|
|
@@ -70,12 +71,15 @@ export interface CreateWorkspaceResult {
|
|
|
70
71
|
key?: IssuedKey;
|
|
71
72
|
}
|
|
72
73
|
/**
|
|
73
|
-
* Stand up a new workspace under an org
|
|
74
|
-
*
|
|
74
|
+
* Stand up a new workspace under an org. The workspace + org binding
|
|
75
|
+
* commit atomically because the KeyStore writes `org_id` in the same
|
|
76
|
+
* INSERT as the workspace row. Issuing the initial API key remains a
|
|
77
|
+
* follow-up call (idempotent — a retry of the workspace POST returns
|
|
78
|
+
* the existing row via ON CONFLICT DO NOTHING).
|
|
75
79
|
*
|
|
76
80
|
* Validates the workspace id shape up front so a bad id fails before
|
|
77
|
-
* touching
|
|
78
|
-
*
|
|
81
|
+
* touching the store. Returns the workspace with `orgId` stamped on so
|
|
82
|
+
* callers don't need a second lookup.
|
|
79
83
|
*/
|
|
80
84
|
export declare function createWorkspaceUnderOrg(deps: OrgServiceDeps, orgId: string, body: CreateWorkspaceInput): Promise<CreateWorkspaceResult>;
|
|
81
85
|
export declare function updateOrgWorkspace(deps: OrgServiceDeps, orgId: string, wsId: string, body: {
|
package/dist/services/orgs.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* (`/admin/v1/*`) and the cookie-auth self-service surface (`/v1/orgs/*`).
|
|
4
4
|
*
|
|
5
5
|
* Auth and HTTP framing stay in the route modules. This file owns:
|
|
6
|
-
* - the multi-step orchestrations (
|
|
7
|
-
* +
|
|
6
|
+
* - the multi-step orchestrations (createWorkspaceUnderOrg writes
|
|
7
|
+
* the workspace + org binding atomically and then issues a key;
|
|
8
|
+
* email→userId lookup + upsertMember)
|
|
8
9
|
* - the safety invariants (workspace id validation, last-owner
|
|
9
10
|
* protection on member removal)
|
|
10
11
|
* - the canonical error → status mapping (OrgServiceError.status)
|
|
@@ -92,12 +93,15 @@ export async function removeMember(deps, orgId, userId) {
|
|
|
92
93
|
await deps.orgStore.removeMember(orgId, userId);
|
|
93
94
|
}
|
|
94
95
|
/**
|
|
95
|
-
* Stand up a new workspace under an org
|
|
96
|
-
*
|
|
96
|
+
* Stand up a new workspace under an org. The workspace + org binding
|
|
97
|
+
* commit atomically because the KeyStore writes `org_id` in the same
|
|
98
|
+
* INSERT as the workspace row. Issuing the initial API key remains a
|
|
99
|
+
* follow-up call (idempotent — a retry of the workspace POST returns
|
|
100
|
+
* the existing row via ON CONFLICT DO NOTHING).
|
|
97
101
|
*
|
|
98
102
|
* Validates the workspace id shape up front so a bad id fails before
|
|
99
|
-
* touching
|
|
100
|
-
*
|
|
103
|
+
* touching the store. Returns the workspace with `orgId` stamped on so
|
|
104
|
+
* callers don't need a second lookup.
|
|
101
105
|
*/
|
|
102
106
|
export async function createWorkspaceUnderOrg(deps, orgId, body) {
|
|
103
107
|
if (body.id !== undefined && !isValidWorkspaceId(body.id)) {
|
|
@@ -108,8 +112,8 @@ export async function createWorkspaceUnderOrg(deps, orgId, body) {
|
|
|
108
112
|
...(body.id !== undefined ? { id: body.id } : {}),
|
|
109
113
|
...(body.name !== undefined ? { name: body.name } : {}),
|
|
110
114
|
...(body.metadata !== undefined ? { metadata: body.metadata } : {}),
|
|
115
|
+
orgId,
|
|
111
116
|
});
|
|
112
|
-
await deps.orgStore.setWorkspaceOrg(ws.id, orgId);
|
|
113
117
|
if (body.issueKey === false) {
|
|
114
118
|
return { workspace: { ...ws, orgId } };
|
|
115
119
|
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -147,6 +147,8 @@ export interface SessionRow {
|
|
|
147
147
|
model?: string;
|
|
148
148
|
trigger_conversation_id?: string;
|
|
149
149
|
trigger_event_id?: string;
|
|
150
|
+
trigger_purpose?: string;
|
|
151
|
+
trigger_resume_hint?: string;
|
|
150
152
|
}
|
|
151
153
|
export declare function foldEvents(row: SessionRow, events: SessionEvent[], now: Date): Session;
|
|
152
154
|
/**
|
package/dist/storage.js
CHANGED
|
@@ -35,6 +35,12 @@ export function foldEvents(row, events, now) {
|
|
|
35
35
|
...(row.trigger_event_id !== undefined
|
|
36
36
|
? { trigger_event_id: row.trigger_event_id }
|
|
37
37
|
: {}),
|
|
38
|
+
...(row.trigger_purpose !== undefined
|
|
39
|
+
? { trigger_purpose: row.trigger_purpose }
|
|
40
|
+
: {}),
|
|
41
|
+
...(row.trigger_resume_hint !== undefined
|
|
42
|
+
? { trigger_resume_hint: row.trigger_resume_hint }
|
|
43
|
+
: {}),
|
|
38
44
|
updated_at: row.updatedAt,
|
|
39
45
|
};
|
|
40
46
|
}
|
package/openapi.json
CHANGED
|
@@ -37,14 +37,6 @@
|
|
|
37
37
|
{
|
|
38
38
|
"name": "Orgs (admin)",
|
|
39
39
|
"description": "プラットフォーム管理者トークンでの org 管理"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"name": "Workspaces (admin)",
|
|
43
|
-
"description": "ワークスペースの管理(管理者トークン必須)"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"name": "API Keys (admin)",
|
|
47
|
-
"description": "ワークスペース API キーの発行・無効化(管理者トークン必須)"
|
|
48
40
|
}
|
|
49
41
|
],
|
|
50
42
|
"servers": [
|
|
@@ -145,6 +137,26 @@
|
|
|
145
137
|
"type": "null"
|
|
146
138
|
}
|
|
147
139
|
]
|
|
140
|
+
},
|
|
141
|
+
"trigger_purpose": {
|
|
142
|
+
"anyOf": [
|
|
143
|
+
{
|
|
144
|
+
"type": "string"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"type": "null"
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"trigger_resume_hint": {
|
|
152
|
+
"anyOf": [
|
|
153
|
+
{
|
|
154
|
+
"type": "string"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "null"
|
|
158
|
+
}
|
|
159
|
+
]
|
|
148
160
|
}
|
|
149
161
|
},
|
|
150
162
|
"additionalProperties": false
|
|
@@ -219,6 +231,26 @@
|
|
|
219
231
|
"type": "null"
|
|
220
232
|
}
|
|
221
233
|
]
|
|
234
|
+
},
|
|
235
|
+
"trigger_purpose": {
|
|
236
|
+
"anyOf": [
|
|
237
|
+
{
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"type": "null"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
"trigger_resume_hint": {
|
|
246
|
+
"anyOf": [
|
|
247
|
+
{
|
|
248
|
+
"type": "string"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"type": "null"
|
|
252
|
+
}
|
|
253
|
+
]
|
|
222
254
|
}
|
|
223
255
|
},
|
|
224
256
|
"additionalProperties": false
|
|
@@ -2462,252 +2494,6 @@
|
|
|
2462
2494
|
"Orgs (admin)"
|
|
2463
2495
|
]
|
|
2464
2496
|
}
|
|
2465
|
-
},
|
|
2466
|
-
"/admin/v1/workspaces": {
|
|
2467
|
-
"post": {
|
|
2468
|
-
"summary": "ワークスペースを作成する(デフォルトで初期キーも発行する)。",
|
|
2469
|
-
"security": [
|
|
2470
|
-
{
|
|
2471
|
-
"adminToken": []
|
|
2472
|
-
}
|
|
2473
|
-
],
|
|
2474
|
-
"requestBody": {
|
|
2475
|
-
"required": true,
|
|
2476
|
-
"content": {
|
|
2477
|
-
"application/json": {
|
|
2478
|
-
"schema": {
|
|
2479
|
-
"$ref": "#/components/schemas/CreateWorkspace"
|
|
2480
|
-
}
|
|
2481
|
-
}
|
|
2482
|
-
}
|
|
2483
|
-
},
|
|
2484
|
-
"responses": {
|
|
2485
|
-
"200": {
|
|
2486
|
-
"description": "ワークスペース(issueKey=false でない限りキーも含む)"
|
|
2487
|
-
},
|
|
2488
|
-
"400": {
|
|
2489
|
-
"description": "リクエストボディまたはワークスペース id が不正"
|
|
2490
|
-
},
|
|
2491
|
-
"401": {
|
|
2492
|
-
"description": "認証エラー"
|
|
2493
|
-
}
|
|
2494
|
-
},
|
|
2495
|
-
"tags": [
|
|
2496
|
-
"Workspaces (admin)"
|
|
2497
|
-
]
|
|
2498
|
-
},
|
|
2499
|
-
"get": {
|
|
2500
|
-
"summary": "全ワークスペースを一覧取得する。",
|
|
2501
|
-
"security": [
|
|
2502
|
-
{
|
|
2503
|
-
"adminToken": []
|
|
2504
|
-
}
|
|
2505
|
-
],
|
|
2506
|
-
"responses": {
|
|
2507
|
-
"200": {
|
|
2508
|
-
"description": "ワークスペース一覧"
|
|
2509
|
-
},
|
|
2510
|
-
"401": {
|
|
2511
|
-
"description": "認証エラー"
|
|
2512
|
-
}
|
|
2513
|
-
},
|
|
2514
|
-
"tags": [
|
|
2515
|
-
"Workspaces (admin)"
|
|
2516
|
-
]
|
|
2517
|
-
}
|
|
2518
|
-
},
|
|
2519
|
-
"/admin/v1/workspaces/{id}": {
|
|
2520
|
-
"get": {
|
|
2521
|
-
"summary": "単一のワークスペースを取得する。",
|
|
2522
|
-
"security": [
|
|
2523
|
-
{
|
|
2524
|
-
"adminToken": []
|
|
2525
|
-
}
|
|
2526
|
-
],
|
|
2527
|
-
"parameters": [
|
|
2528
|
-
{
|
|
2529
|
-
"name": "id",
|
|
2530
|
-
"in": "path",
|
|
2531
|
-
"required": true,
|
|
2532
|
-
"schema": {
|
|
2533
|
-
"type": "string"
|
|
2534
|
-
},
|
|
2535
|
-
"description": "ワークスペース id。"
|
|
2536
|
-
}
|
|
2537
|
-
],
|
|
2538
|
-
"responses": {
|
|
2539
|
-
"200": {
|
|
2540
|
-
"description": "ワークスペース"
|
|
2541
|
-
},
|
|
2542
|
-
"401": {
|
|
2543
|
-
"description": "認証エラー"
|
|
2544
|
-
},
|
|
2545
|
-
"404": {
|
|
2546
|
-
"description": "ワークスペースが見つからない"
|
|
2547
|
-
}
|
|
2548
|
-
},
|
|
2549
|
-
"tags": [
|
|
2550
|
-
"Workspaces (admin)"
|
|
2551
|
-
]
|
|
2552
|
-
},
|
|
2553
|
-
"delete": {
|
|
2554
|
-
"summary": "ワークスペースを削除する(キー・セッション・イベントにカスケードする)。",
|
|
2555
|
-
"security": [
|
|
2556
|
-
{
|
|
2557
|
-
"adminToken": []
|
|
2558
|
-
}
|
|
2559
|
-
],
|
|
2560
|
-
"parameters": [
|
|
2561
|
-
{
|
|
2562
|
-
"name": "id",
|
|
2563
|
-
"in": "path",
|
|
2564
|
-
"required": true,
|
|
2565
|
-
"schema": {
|
|
2566
|
-
"type": "string"
|
|
2567
|
-
},
|
|
2568
|
-
"description": "ワークスペース id。"
|
|
2569
|
-
}
|
|
2570
|
-
],
|
|
2571
|
-
"responses": {
|
|
2572
|
-
"204": {
|
|
2573
|
-
"description": "削除完了"
|
|
2574
|
-
},
|
|
2575
|
-
"401": {
|
|
2576
|
-
"description": "認証エラー"
|
|
2577
|
-
},
|
|
2578
|
-
"404": {
|
|
2579
|
-
"description": "ワークスペースが見つからない"
|
|
2580
|
-
}
|
|
2581
|
-
},
|
|
2582
|
-
"tags": [
|
|
2583
|
-
"Workspaces (admin)"
|
|
2584
|
-
]
|
|
2585
|
-
}
|
|
2586
|
-
},
|
|
2587
|
-
"/admin/v1/workspaces/{id}/keys": {
|
|
2588
|
-
"post": {
|
|
2589
|
-
"summary": "ワークスペースに新しい API キーを発行する。",
|
|
2590
|
-
"security": [
|
|
2591
|
-
{
|
|
2592
|
-
"adminToken": []
|
|
2593
|
-
}
|
|
2594
|
-
],
|
|
2595
|
-
"parameters": [
|
|
2596
|
-
{
|
|
2597
|
-
"name": "id",
|
|
2598
|
-
"in": "path",
|
|
2599
|
-
"required": true,
|
|
2600
|
-
"schema": {
|
|
2601
|
-
"type": "string"
|
|
2602
|
-
},
|
|
2603
|
-
"description": "ワークスペース id。"
|
|
2604
|
-
}
|
|
2605
|
-
],
|
|
2606
|
-
"requestBody": {
|
|
2607
|
-
"required": false,
|
|
2608
|
-
"content": {
|
|
2609
|
-
"application/json": {
|
|
2610
|
-
"schema": {
|
|
2611
|
-
"$ref": "#/components/schemas/IssueKey"
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
}
|
|
2615
|
-
},
|
|
2616
|
-
"responses": {
|
|
2617
|
-
"200": {
|
|
2618
|
-
"description": "発行されたキー(生のキーは一度のみ返却)"
|
|
2619
|
-
},
|
|
2620
|
-
"400": {
|
|
2621
|
-
"description": "リクエストボディが不正"
|
|
2622
|
-
},
|
|
2623
|
-
"401": {
|
|
2624
|
-
"description": "認証エラー"
|
|
2625
|
-
},
|
|
2626
|
-
"404": {
|
|
2627
|
-
"description": "ワークスペースが見つからない"
|
|
2628
|
-
}
|
|
2629
|
-
},
|
|
2630
|
-
"tags": [
|
|
2631
|
-
"API Keys (admin)"
|
|
2632
|
-
]
|
|
2633
|
-
},
|
|
2634
|
-
"get": {
|
|
2635
|
-
"summary": "ワークスペースの API キー一覧を取得する(ハッシュのみ)。",
|
|
2636
|
-
"security": [
|
|
2637
|
-
{
|
|
2638
|
-
"adminToken": []
|
|
2639
|
-
}
|
|
2640
|
-
],
|
|
2641
|
-
"parameters": [
|
|
2642
|
-
{
|
|
2643
|
-
"name": "id",
|
|
2644
|
-
"in": "path",
|
|
2645
|
-
"required": true,
|
|
2646
|
-
"schema": {
|
|
2647
|
-
"type": "string"
|
|
2648
|
-
},
|
|
2649
|
-
"description": "ワークスペース id。"
|
|
2650
|
-
}
|
|
2651
|
-
],
|
|
2652
|
-
"responses": {
|
|
2653
|
-
"200": {
|
|
2654
|
-
"description": "キー一覧"
|
|
2655
|
-
},
|
|
2656
|
-
"401": {
|
|
2657
|
-
"description": "認証エラー"
|
|
2658
|
-
},
|
|
2659
|
-
"404": {
|
|
2660
|
-
"description": "ワークスペースが見つからない"
|
|
2661
|
-
}
|
|
2662
|
-
},
|
|
2663
|
-
"tags": [
|
|
2664
|
-
"API Keys (admin)"
|
|
2665
|
-
]
|
|
2666
|
-
}
|
|
2667
|
-
},
|
|
2668
|
-
"/admin/v1/workspaces/{id}/keys/{keyId}": {
|
|
2669
|
-
"delete": {
|
|
2670
|
-
"summary": "API キーを無効化する。",
|
|
2671
|
-
"security": [
|
|
2672
|
-
{
|
|
2673
|
-
"adminToken": []
|
|
2674
|
-
}
|
|
2675
|
-
],
|
|
2676
|
-
"parameters": [
|
|
2677
|
-
{
|
|
2678
|
-
"name": "id",
|
|
2679
|
-
"in": "path",
|
|
2680
|
-
"required": true,
|
|
2681
|
-
"schema": {
|
|
2682
|
-
"type": "string"
|
|
2683
|
-
},
|
|
2684
|
-
"description": "ワークスペース id。"
|
|
2685
|
-
},
|
|
2686
|
-
{
|
|
2687
|
-
"name": "keyId",
|
|
2688
|
-
"in": "path",
|
|
2689
|
-
"required": true,
|
|
2690
|
-
"schema": {
|
|
2691
|
-
"type": "string"
|
|
2692
|
-
},
|
|
2693
|
-
"description": "キー id。"
|
|
2694
|
-
}
|
|
2695
|
-
],
|
|
2696
|
-
"responses": {
|
|
2697
|
-
"204": {
|
|
2698
|
-
"description": "無効化完了(冪等)"
|
|
2699
|
-
},
|
|
2700
|
-
"401": {
|
|
2701
|
-
"description": "認証エラー"
|
|
2702
|
-
},
|
|
2703
|
-
"404": {
|
|
2704
|
-
"description": "キーが見つからない"
|
|
2705
|
-
}
|
|
2706
|
-
},
|
|
2707
|
-
"tags": [
|
|
2708
|
-
"API Keys (admin)"
|
|
2709
|
-
]
|
|
2710
|
-
}
|
|
2711
2497
|
}
|
|
2712
2498
|
}
|
|
2713
2499
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hexis-ai/engram-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Engram server: ingest agent session events, persist via a pluggable adapter, expose search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"engram",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"dev": "bun --hot src/dev.ts"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@hexis-ai/engram-core": "^0.
|
|
53
|
-
"@hexis-ai/engram-sdk": "^0.
|
|
52
|
+
"@hexis-ai/engram-core": "^0.3.0",
|
|
53
|
+
"@hexis-ai/engram-sdk": "^0.16.0",
|
|
54
54
|
"better-auth": "^1.6.11",
|
|
55
55
|
"hono": "^4.6.0",
|
|
56
56
|
"pg": "^8.13.0",
|