@hexis-ai/engram-server 0.3.0 → 0.4.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.js +9 -11
- package/dist/adapters/memory.d.ts +1 -0
- package/dist/adapters/memory.js +11 -1
- package/dist/adapters/postgres-key-store.js +5 -11
- package/dist/adapters/postgres.d.ts +1 -0
- package/dist/adapters/postgres.js +15 -0
- package/dist/key-store.d.ts +29 -0
- package/dist/key-store.js +26 -0
- package/dist/openapi.js +187 -115
- package/dist/routes/sessions.d.ts +5 -4
- package/dist/routes/sessions.js +12 -4
- package/dist/server.js +1 -0
- package/dist/storage.d.ts +8 -0
- package/openapi.json +227 -116
- package/package.json +2 -2
package/dist/openapi.js
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
*
|
|
12
12
|
* `info.version` is the API version (the `/v1` surface), not the npm package
|
|
13
13
|
* version — it changes only when the wire contract changes.
|
|
14
|
+
*
|
|
15
|
+
* The human-readable strings (`summary`, `description`, response and
|
|
16
|
+
* parameter descriptions) are written in Japanese — the API reference is
|
|
17
|
+
* read by the Hexis team. Identifiers, paths, schema names and status
|
|
18
|
+
* codes stay as-is.
|
|
14
19
|
*/
|
|
15
20
|
import { z } from "zod";
|
|
16
21
|
import { createWorkspaceSchema, eventBatchSchema, issueKeySchema, personCreateSchema, personUpdateSchema, searchRequestSchema, sessionInitSchema, } from "./schemas";
|
|
@@ -37,212 +42,276 @@ const res = (description) => ({ description });
|
|
|
37
42
|
/** Default security: a workspace API key. `/admin/v1` paths override this. */
|
|
38
43
|
const workspaceAuth = [{ workspaceKey: [] }];
|
|
39
44
|
const adminAuth = [{ adminToken: [] }];
|
|
40
|
-
|
|
45
|
+
// ---------------------------------------------------------------------
|
|
46
|
+
// Tags — group the rendered reference (Scalar, on monet-web /docs/engram)
|
|
47
|
+
// into a per-domain sidebar instead of one flat list of 19 operations.
|
|
48
|
+
//
|
|
49
|
+
// The tag *definitions* (sidebar order + Japanese descriptions) live
|
|
50
|
+
// in TAG_DEFS; `tagged()` stamps a tag onto every operation in a
|
|
51
|
+
// path-item, so each path in buildPaths() declares its tag once,
|
|
52
|
+
// inline. test/openapi.test.ts guards that no operation slips through
|
|
53
|
+
// untagged and no operation references an undefined tag.
|
|
54
|
+
// ---------------------------------------------------------------------
|
|
55
|
+
/** Every tag, in sidebar order, with a Japanese description. */
|
|
56
|
+
const TAG_DEFS = [
|
|
57
|
+
{ name: "Me", description: "識別プローブ" },
|
|
58
|
+
{ name: "Sessions", description: "セッションの作成・取得・イベント追加" },
|
|
59
|
+
{ name: "Search", description: "ワークスペースコーパスへのスコアリング検索" },
|
|
60
|
+
{ name: "Persons", description: "person の作成・更新・検索" },
|
|
61
|
+
{
|
|
62
|
+
name: "Workspaces (admin)",
|
|
63
|
+
description: "ワークスペースの管理(管理者トークン必須)",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "API Keys (admin)",
|
|
67
|
+
description: "ワークスペース API キーの発行・無効化(管理者トークン必須)",
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
/**
|
|
71
|
+
* Stamp `tag` onto every operation in a path-item. The path declares its
|
|
72
|
+
* tag once — `tagged("Sessions", { post: {…}, get: {…} })` — rather than
|
|
73
|
+
* repeating `tags` on each method.
|
|
74
|
+
*/
|
|
75
|
+
function tagged(tag, pathItem) {
|
|
76
|
+
const out = {};
|
|
77
|
+
for (const [method, op] of Object.entries(pathItem)) {
|
|
78
|
+
out[method] = { ...op, tags: [tag] };
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
const limitParam = queryParam("limit", "ページサイズ。サーバー側で上限が適用される。", {
|
|
41
83
|
type: "integer",
|
|
42
84
|
minimum: 1,
|
|
43
85
|
});
|
|
44
|
-
const channelParam = queryParam("channel", "
|
|
86
|
+
const channelParam = queryParam("channel", "セッションのチャンネルで絞り込む。");
|
|
45
87
|
function buildPaths() {
|
|
46
88
|
return {
|
|
47
|
-
"/v1/me": {
|
|
89
|
+
"/v1/me": tagged("Me", {
|
|
48
90
|
get: {
|
|
49
|
-
summary: "
|
|
50
|
-
responses: {
|
|
91
|
+
summary: "識別プローブ — 呼び出し元のキーが解決するワークスペースを返す。",
|
|
92
|
+
responses: {
|
|
93
|
+
"200": res("ワークスペース id"),
|
|
94
|
+
"401": res("認証エラー"),
|
|
95
|
+
},
|
|
51
96
|
},
|
|
52
|
-
},
|
|
53
|
-
"/v1/sessions": {
|
|
97
|
+
}),
|
|
98
|
+
"/v1/sessions": tagged("Sessions", {
|
|
54
99
|
post: {
|
|
55
|
-
summary: "
|
|
100
|
+
summary: "セッションを作成する。",
|
|
56
101
|
requestBody: jsonBody("SessionInit"),
|
|
57
102
|
responses: {
|
|
58
|
-
"200": res("
|
|
59
|
-
"400": res("
|
|
60
|
-
"401": res("
|
|
103
|
+
"200": res("作成されたセッション id"),
|
|
104
|
+
"400": res("リクエストボディが不正"),
|
|
105
|
+
"401": res("認証エラー"),
|
|
61
106
|
},
|
|
62
107
|
},
|
|
63
108
|
get: {
|
|
64
|
-
summary: "
|
|
109
|
+
summary: "最近のセッション一覧と、それに紐づく persons マップを取得する。",
|
|
65
110
|
parameters: [limitParam, channelParam],
|
|
66
|
-
responses: {
|
|
111
|
+
responses: {
|
|
112
|
+
"200": res("セッション一覧のエンベロープ"),
|
|
113
|
+
"401": res("認証エラー"),
|
|
114
|
+
},
|
|
67
115
|
},
|
|
68
|
-
},
|
|
69
|
-
"/v1/sessions/{id}": {
|
|
116
|
+
}),
|
|
117
|
+
"/v1/sessions/{id}": tagged("Sessions", {
|
|
70
118
|
get: {
|
|
71
|
-
summary: "
|
|
72
|
-
parameters: [pathParam("id", "
|
|
119
|
+
summary: "単一セッションと、それに紐づく persons マップを取得する。",
|
|
120
|
+
parameters: [pathParam("id", "セッション id。")],
|
|
73
121
|
responses: {
|
|
74
|
-
"200": res("
|
|
75
|
-
"404": res("
|
|
76
|
-
"401": res("
|
|
122
|
+
"200": res("セッションのエンベロープ"),
|
|
123
|
+
"404": res("セッションが見つからない"),
|
|
124
|
+
"401": res("認証エラー"),
|
|
77
125
|
},
|
|
78
126
|
},
|
|
79
|
-
},
|
|
80
|
-
"/v1/sessions/{id}/events": {
|
|
127
|
+
}),
|
|
128
|
+
"/v1/sessions/{id}/events": tagged("Sessions", {
|
|
81
129
|
post: {
|
|
82
|
-
summary: "
|
|
83
|
-
parameters: [pathParam("id", "
|
|
130
|
+
summary: "セッションにイベントを追加する。",
|
|
131
|
+
parameters: [pathParam("id", "セッション id。")],
|
|
84
132
|
requestBody: jsonBody("EventBatch"),
|
|
85
133
|
responses: {
|
|
86
|
-
"204": res("
|
|
87
|
-
"400": res("
|
|
88
|
-
"404": res("
|
|
89
|
-
"401": res("
|
|
134
|
+
"204": res("追加完了"),
|
|
135
|
+
"400": res("リクエストボディが不正"),
|
|
136
|
+
"404": res("セッションが見つからない"),
|
|
137
|
+
"401": res("認証エラー"),
|
|
90
138
|
},
|
|
91
139
|
},
|
|
92
|
-
|
|
93
|
-
|
|
140
|
+
get: {
|
|
141
|
+
summary: "セッションの生イベントログを seq 順で取得する(fold せず、各イベントの時刻つき)。",
|
|
142
|
+
parameters: [pathParam("id", "セッション id。")],
|
|
143
|
+
responses: {
|
|
144
|
+
"200": res("イベントログ"),
|
|
145
|
+
"404": res("セッションが見つからない"),
|
|
146
|
+
"401": res("認証エラー"),
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
}),
|
|
150
|
+
"/v1/search": tagged("Search", {
|
|
94
151
|
post: {
|
|
95
|
-
summary: "
|
|
152
|
+
summary: "クエリセッションに対してワークスペースのコーパスをスコアリングする。",
|
|
96
153
|
requestBody: jsonBody("SearchRequest"),
|
|
97
154
|
responses: {
|
|
98
|
-
"200": res("
|
|
99
|
-
"400": res("
|
|
100
|
-
"404": res("
|
|
101
|
-
"401": res("
|
|
155
|
+
"200": res("スコアリング結果と persons マップ"),
|
|
156
|
+
"400": res("リクエストボディが不正"),
|
|
157
|
+
"404": res("クエリセッションが見つからない"),
|
|
158
|
+
"401": res("認証エラー"),
|
|
102
159
|
},
|
|
103
160
|
},
|
|
104
|
-
},
|
|
105
|
-
"/v1/persons": {
|
|
161
|
+
}),
|
|
162
|
+
"/v1/persons": tagged("Persons", {
|
|
106
163
|
post: {
|
|
107
|
-
summary: "
|
|
164
|
+
summary: "person を作成する(id はサーバーが採番する)。",
|
|
108
165
|
requestBody: jsonBody("PersonCreate"),
|
|
109
166
|
responses: {
|
|
110
|
-
"201": res("
|
|
111
|
-
"400": res("
|
|
112
|
-
"401": res("
|
|
167
|
+
"201": res("作成された person"),
|
|
168
|
+
"400": res("リクエストボディが不正"),
|
|
169
|
+
"401": res("認証エラー"),
|
|
113
170
|
},
|
|
114
171
|
},
|
|
115
172
|
get: {
|
|
116
|
-
summary: "
|
|
117
|
-
parameters: [
|
|
118
|
-
|
|
173
|
+
summary: "person の一覧取得、またはフリーテキスト検索を行う。",
|
|
174
|
+
parameters: [
|
|
175
|
+
limitParam,
|
|
176
|
+
queryParam("q", "id と display_name に対するフリーテキストクエリ。"),
|
|
177
|
+
],
|
|
178
|
+
responses: {
|
|
179
|
+
"200": res("person 一覧"),
|
|
180
|
+
"401": res("認証エラー"),
|
|
181
|
+
},
|
|
119
182
|
},
|
|
120
|
-
},
|
|
121
|
-
"/v1/persons/{id}": {
|
|
183
|
+
}),
|
|
184
|
+
"/v1/persons/{id}": tagged("Persons", {
|
|
122
185
|
put: {
|
|
123
|
-
summary: "
|
|
124
|
-
parameters: [pathParam("id", "
|
|
186
|
+
summary: "呼び出し元が指定した id で person を upsert する。",
|
|
187
|
+
parameters: [pathParam("id", "person id。")],
|
|
125
188
|
requestBody: jsonBody("PersonCreate"),
|
|
126
189
|
responses: {
|
|
127
|
-
"200": res("
|
|
128
|
-
"400": res("
|
|
129
|
-
"401": res("
|
|
190
|
+
"200": res("upsert された person"),
|
|
191
|
+
"400": res("リクエストボディが不正"),
|
|
192
|
+
"401": res("認証エラー"),
|
|
130
193
|
},
|
|
131
194
|
},
|
|
132
195
|
patch: {
|
|
133
|
-
summary: "
|
|
134
|
-
parameters: [pathParam("id", "
|
|
196
|
+
summary: "person のプロフィール項目を部分更新する。",
|
|
197
|
+
parameters: [pathParam("id", "person id。")],
|
|
135
198
|
requestBody: jsonBody("PersonUpdate"),
|
|
136
199
|
responses: {
|
|
137
|
-
"200": res("
|
|
138
|
-
"400": res("
|
|
139
|
-
"404": res("person
|
|
140
|
-
"401": res("
|
|
200
|
+
"200": res("更新された person"),
|
|
201
|
+
"400": res("リクエストボディが不正"),
|
|
202
|
+
"404": res("person が見つからない"),
|
|
203
|
+
"401": res("認証エラー"),
|
|
141
204
|
},
|
|
142
205
|
},
|
|
143
206
|
get: {
|
|
144
|
-
summary: "
|
|
145
|
-
parameters: [pathParam("id", "
|
|
207
|
+
summary: "単一の person を取得する。",
|
|
208
|
+
parameters: [pathParam("id", "person id。")],
|
|
146
209
|
responses: {
|
|
147
210
|
"200": res("person"),
|
|
148
|
-
"404": res("person
|
|
149
|
-
"401": res("
|
|
211
|
+
"404": res("person が見つからない"),
|
|
212
|
+
"401": res("認証エラー"),
|
|
150
213
|
},
|
|
151
214
|
},
|
|
152
|
-
},
|
|
153
|
-
"/v1/persons/{id}/sessions": {
|
|
215
|
+
}),
|
|
216
|
+
"/v1/persons/{id}/sessions": tagged("Persons", {
|
|
154
217
|
get: {
|
|
155
|
-
summary: "
|
|
218
|
+
summary: "この person が参加している(または閲覧可能な)セッション一覧。",
|
|
156
219
|
parameters: [
|
|
157
|
-
pathParam("id", "
|
|
220
|
+
pathParam("id", "person id。"),
|
|
158
221
|
limitParam,
|
|
159
222
|
channelParam,
|
|
160
|
-
queryParam("scope", "`participant
|
|
223
|
+
queryParam("scope", "`participant`(デフォルト)または `viewable`。", {
|
|
161
224
|
type: "string",
|
|
162
225
|
enum: ["participant", "viewable"],
|
|
163
226
|
}),
|
|
164
227
|
],
|
|
165
|
-
responses: {
|
|
228
|
+
responses: {
|
|
229
|
+
"200": res("セッション一覧のエンベロープ"),
|
|
230
|
+
"401": res("認証エラー"),
|
|
231
|
+
},
|
|
166
232
|
},
|
|
167
|
-
},
|
|
168
|
-
"/admin/v1/workspaces": {
|
|
233
|
+
}),
|
|
234
|
+
"/admin/v1/workspaces": tagged("Workspaces (admin)", {
|
|
169
235
|
post: {
|
|
170
|
-
summary: "
|
|
236
|
+
summary: "ワークスペースを作成する(デフォルトで初期キーも発行する)。",
|
|
171
237
|
security: adminAuth,
|
|
172
238
|
requestBody: jsonBody("CreateWorkspace"),
|
|
173
239
|
responses: {
|
|
174
|
-
"200": res("
|
|
175
|
-
"400": res("
|
|
176
|
-
"401": res("
|
|
240
|
+
"200": res("ワークスペース(issueKey=false でない限りキーも含む)"),
|
|
241
|
+
"400": res("リクエストボディまたはワークスペース id が不正"),
|
|
242
|
+
"401": res("認証エラー"),
|
|
177
243
|
},
|
|
178
244
|
},
|
|
179
245
|
get: {
|
|
180
|
-
summary: "
|
|
246
|
+
summary: "全ワークスペースを一覧取得する。",
|
|
181
247
|
security: adminAuth,
|
|
182
|
-
responses: {
|
|
248
|
+
responses: {
|
|
249
|
+
"200": res("ワークスペース一覧"),
|
|
250
|
+
"401": res("認証エラー"),
|
|
251
|
+
},
|
|
183
252
|
},
|
|
184
|
-
},
|
|
185
|
-
"/admin/v1/workspaces/{id}": {
|
|
253
|
+
}),
|
|
254
|
+
"/admin/v1/workspaces/{id}": tagged("Workspaces (admin)", {
|
|
186
255
|
get: {
|
|
187
|
-
summary: "
|
|
256
|
+
summary: "単一のワークスペースを取得する。",
|
|
188
257
|
security: adminAuth,
|
|
189
|
-
parameters: [pathParam("id", "
|
|
258
|
+
parameters: [pathParam("id", "ワークスペース id。")],
|
|
190
259
|
responses: {
|
|
191
|
-
"200": res("
|
|
192
|
-
"404": res("
|
|
193
|
-
"401": res("
|
|
260
|
+
"200": res("ワークスペース"),
|
|
261
|
+
"404": res("ワークスペースが見つからない"),
|
|
262
|
+
"401": res("認証エラー"),
|
|
194
263
|
},
|
|
195
264
|
},
|
|
196
265
|
delete: {
|
|
197
|
-
summary: "
|
|
266
|
+
summary: "ワークスペースを削除する(キー・セッション・イベントにカスケードする)。",
|
|
198
267
|
security: adminAuth,
|
|
199
|
-
parameters: [pathParam("id", "
|
|
268
|
+
parameters: [pathParam("id", "ワークスペース id。")],
|
|
200
269
|
responses: {
|
|
201
|
-
"204": res("
|
|
202
|
-
"404": res("
|
|
203
|
-
"401": res("
|
|
270
|
+
"204": res("削除完了"),
|
|
271
|
+
"404": res("ワークスペースが見つからない"),
|
|
272
|
+
"401": res("認証エラー"),
|
|
204
273
|
},
|
|
205
274
|
},
|
|
206
|
-
},
|
|
207
|
-
"/admin/v1/workspaces/{id}/keys": {
|
|
275
|
+
}),
|
|
276
|
+
"/admin/v1/workspaces/{id}/keys": tagged("API Keys (admin)", {
|
|
208
277
|
post: {
|
|
209
|
-
summary: "
|
|
278
|
+
summary: "ワークスペースに新しい API キーを発行する。",
|
|
210
279
|
security: adminAuth,
|
|
211
|
-
parameters: [pathParam("id", "
|
|
280
|
+
parameters: [pathParam("id", "ワークスペース id。")],
|
|
212
281
|
requestBody: jsonBody("IssueKey", false),
|
|
213
282
|
responses: {
|
|
214
|
-
"200": res("
|
|
215
|
-
"400": res("
|
|
216
|
-
"404": res("
|
|
217
|
-
"401": res("
|
|
283
|
+
"200": res("発行されたキー(生のキーは一度のみ返却)"),
|
|
284
|
+
"400": res("リクエストボディが不正"),
|
|
285
|
+
"404": res("ワークスペースが見つからない"),
|
|
286
|
+
"401": res("認証エラー"),
|
|
218
287
|
},
|
|
219
288
|
},
|
|
220
289
|
get: {
|
|
221
|
-
summary: "
|
|
290
|
+
summary: "ワークスペースの API キー一覧を取得する(ハッシュのみ)。",
|
|
222
291
|
security: adminAuth,
|
|
223
|
-
parameters: [pathParam("id", "
|
|
292
|
+
parameters: [pathParam("id", "ワークスペース id。")],
|
|
224
293
|
responses: {
|
|
225
|
-
"200": res("
|
|
226
|
-
"404": res("
|
|
227
|
-
"401": res("
|
|
294
|
+
"200": res("キー一覧"),
|
|
295
|
+
"404": res("ワークスペースが見つからない"),
|
|
296
|
+
"401": res("認証エラー"),
|
|
228
297
|
},
|
|
229
298
|
},
|
|
230
|
-
},
|
|
231
|
-
"/admin/v1/workspaces/{id}/keys/{keyId}": {
|
|
299
|
+
}),
|
|
300
|
+
"/admin/v1/workspaces/{id}/keys/{keyId}": tagged("API Keys (admin)", {
|
|
232
301
|
delete: {
|
|
233
|
-
summary: "
|
|
302
|
+
summary: "API キーを無効化する。",
|
|
234
303
|
security: adminAuth,
|
|
235
304
|
parameters: [
|
|
236
|
-
pathParam("id", "
|
|
237
|
-
pathParam("keyId", "
|
|
305
|
+
pathParam("id", "ワークスペース id。"),
|
|
306
|
+
pathParam("keyId", "キー id。"),
|
|
238
307
|
],
|
|
239
308
|
responses: {
|
|
240
|
-
"204": res("
|
|
241
|
-
"404": res("
|
|
242
|
-
"401": res("
|
|
309
|
+
"204": res("無効化完了(冪等)"),
|
|
310
|
+
"404": res("キーが見つからない"),
|
|
311
|
+
"401": res("認証エラー"),
|
|
243
312
|
},
|
|
244
313
|
},
|
|
245
|
-
},
|
|
314
|
+
}),
|
|
246
315
|
};
|
|
247
316
|
}
|
|
248
317
|
/**
|
|
@@ -256,12 +325,14 @@ export function buildOpenApiDocument() {
|
|
|
256
325
|
info: {
|
|
257
326
|
title: "engram-server",
|
|
258
327
|
version: "1.0",
|
|
259
|
-
description: "
|
|
260
|
-
"
|
|
261
|
-
"
|
|
328
|
+
description: "AI エージェント向けのクロスセッション検索。リクエストボディは" +
|
|
329
|
+
"サーバーの Zod スキーマ(src/schemas.ts)から導出される。" +
|
|
330
|
+
"レスポンススキーマは現状ステータスコードのみの記述で、" +
|
|
331
|
+
"本格的な記述は今後対応予定。",
|
|
262
332
|
},
|
|
333
|
+
tags: TAG_DEFS.map((t) => ({ ...t })),
|
|
263
334
|
servers: [
|
|
264
|
-
{ url: "/", description: "
|
|
335
|
+
{ url: "/", description: "デプロイされた engram-server からの相対パス" },
|
|
265
336
|
],
|
|
266
337
|
security: workspaceAuth,
|
|
267
338
|
components: {
|
|
@@ -269,13 +340,14 @@ export function buildOpenApiDocument() {
|
|
|
269
340
|
workspaceKey: {
|
|
270
341
|
type: "http",
|
|
271
342
|
scheme: "bearer",
|
|
272
|
-
description: "
|
|
343
|
+
description: "ワークスペース API キー(`eng_…`)。`X-Api-Key` ヘッダーでも受け付ける。",
|
|
273
344
|
},
|
|
274
345
|
adminToken: {
|
|
275
346
|
type: "apiKey",
|
|
276
347
|
in: "header",
|
|
277
348
|
name: "X-Admin-Token",
|
|
278
|
-
description: "
|
|
349
|
+
description: "`/admin/v1/*` 用のプラットフォーム管理者トークン。" +
|
|
350
|
+
"`Authorization: Bearer` でも受け付ける。",
|
|
279
351
|
},
|
|
280
352
|
},
|
|
281
353
|
schemas: {
|
|
@@ -3,9 +3,10 @@ import type { Env } from "../context";
|
|
|
3
3
|
import { type RouteConfig } from "./helpers";
|
|
4
4
|
/**
|
|
5
5
|
* Session routes. Mount under `/v1`:
|
|
6
|
-
* POST /v1/sessions
|
|
7
|
-
* POST /v1/sessions/:id/events
|
|
8
|
-
* GET /v1/sessions/:id
|
|
9
|
-
* GET /v1/sessions
|
|
6
|
+
* POST /v1/sessions create a session
|
|
7
|
+
* POST /v1/sessions/:id/events append events
|
|
8
|
+
* GET /v1/sessions/:id fetch one session + its persons map
|
|
9
|
+
* GET /v1/sessions/:id/events fetch the raw, ordered event log
|
|
10
|
+
* GET /v1/sessions list recent sessions + persons map
|
|
10
11
|
*/
|
|
11
12
|
export declare function sessionsRoutes(cfg: RouteConfig): Hono<Env>;
|
package/dist/routes/sessions.js
CHANGED
|
@@ -3,10 +3,11 @@ import { eventBatchSchema, parseJsonBody, sessionInitSchema } from "../schemas";
|
|
|
3
3
|
import { clampLimit, resolvePersonMap } from "./helpers";
|
|
4
4
|
/**
|
|
5
5
|
* Session routes. Mount under `/v1`:
|
|
6
|
-
* POST /v1/sessions
|
|
7
|
-
* POST /v1/sessions/:id/events
|
|
8
|
-
* GET /v1/sessions/:id
|
|
9
|
-
* GET /v1/sessions
|
|
6
|
+
* POST /v1/sessions create a session
|
|
7
|
+
* POST /v1/sessions/:id/events append events
|
|
8
|
+
* GET /v1/sessions/:id fetch one session + its persons map
|
|
9
|
+
* GET /v1/sessions/:id/events fetch the raw, ordered event log
|
|
10
|
+
* GET /v1/sessions list recent sessions + persons map
|
|
10
11
|
*/
|
|
11
12
|
export function sessionsRoutes(cfg) {
|
|
12
13
|
const app = new Hono();
|
|
@@ -40,6 +41,13 @@ export function sessionsRoutes(cfg) {
|
|
|
40
41
|
const persons = await resolvePersonMap(c.var.ctx.storage, [s]);
|
|
41
42
|
return c.json({ session: s, persons });
|
|
42
43
|
});
|
|
44
|
+
app.get("/sessions/:id/events", async (c) => {
|
|
45
|
+
const id = c.req.param("id");
|
|
46
|
+
const events = await c.var.ctx.storage.getSessionEvents(id);
|
|
47
|
+
if (events === null)
|
|
48
|
+
return c.json({ error: "session_not_found" }, 404);
|
|
49
|
+
return c.json({ events });
|
|
50
|
+
});
|
|
43
51
|
app.get("/sessions", async (c) => {
|
|
44
52
|
const limit = clampLimit(c, cfg.defaultListLimit, cfg.maxListLimit);
|
|
45
53
|
const channel = c.req.query("channel") || undefined;
|
package/dist/server.js
CHANGED
|
@@ -53,6 +53,7 @@ export function createServer(opts) {
|
|
|
53
53
|
sessions: "POST/GET /v1/sessions",
|
|
54
54
|
sessionById: "GET /v1/sessions/:id",
|
|
55
55
|
events: "POST /v1/sessions/:id/events",
|
|
56
|
+
sessionEvents: "GET /v1/sessions/:id/events",
|
|
56
57
|
search: "POST /v1/search",
|
|
57
58
|
persons: "POST/GET /v1/persons",
|
|
58
59
|
personById: "GET/PUT/PATCH /v1/persons/:id",
|
package/dist/storage.d.ts
CHANGED
|
@@ -18,6 +18,14 @@ export interface StorageAdapter {
|
|
|
18
18
|
appendEvents(sessionId: string, events: SessionEvent[]): Promise<void>;
|
|
19
19
|
/** Materialize a session (events folded into Session shape). */
|
|
20
20
|
getSession(sessionId: string): Promise<Session | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Raw event log for a session, ordered by `seq`. Unlike `getSession`,
|
|
23
|
+
* this does not fold events — callers get per-event timestamps and the
|
|
24
|
+
* participant / title / end events as recorded. Returns `null` when the
|
|
25
|
+
* session doesn't exist (distinct from an existing session with no
|
|
26
|
+
* events, which returns `[]`).
|
|
27
|
+
*/
|
|
28
|
+
getSessionEvents(sessionId: string): Promise<SessionEvent[] | null>;
|
|
21
29
|
/** List recent sessions. */
|
|
22
30
|
listSessions(opts: {
|
|
23
31
|
limit: number;
|