@opengeni/api-router 2.10.0-canary.3 → 2.10.0-canary.4

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/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  createOpenGeniSlackBotInteractionClient,
8
8
  startSlackInteractionPump,
9
9
  startTemporalScheduleCleanupPump
10
- } from "./chunk-CZGPIPDA.js";
10
+ } from "./chunk-NWSVDE7O.js";
11
11
 
12
12
  // src/index.ts
13
13
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/api-router",
3
- "version": "2.10.0-canary.3",
3
+ "version": "2.10.0-canary.4",
4
4
  "description": "OpenGeni HTTP surface: the Hono adapter/router (createApp), routes, MCP HTTP transport, and HTTP access adapters over @opengeni/core. An engine-distribution surface — its runtime closure includes engine-internal packages.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,24 +43,24 @@
43
43
  "@hono/zod-validator": "^0.7.6",
44
44
  "@llamaindex/liteparse": "2.14.2",
45
45
  "@modelcontextprotocol/sdk": "^1.29.0",
46
- "@opengeni/agent-proto": "^0.5.1-canary.12",
47
- "@opengeni/artifact-tool": "^0.3.19-canary.3",
48
- "@opengeni/capabilities": "^0.3.2-canary.3",
49
- "@opengeni/codemode": "^0.4.27-canary.3",
50
- "@opengeni/codex": "^0.2.21-canary.3",
51
- "@opengeni/config": "^1.0.0-canary.3",
52
- "@opengeni/contracts": "^2.13.0-canary.3",
53
- "@opengeni/core": "^2.7.5-canary.3",
54
- "@opengeni/db": "^4.0.0-canary.3",
55
- "@opengeni/documents": "^0.8.19-canary.3",
56
- "@opengeni/events": "^0.4.17-canary.3",
57
- "@opengeni/github": "^0.7.3-canary.3",
58
- "@opengeni/network": "^0.3.0-canary.3",
59
- "@opengeni/observability": "^0.8.19-canary.3",
60
- "@opengeni/runtime": "^2.3.0-canary.3",
61
- "@opengeni/storage": "^0.2.120-canary.3",
62
- "@opengeni/tool-gateway": "^0.1.0-canary.3",
63
- "@opengeni/xai-subscription": "^0.1.3-canary.3",
46
+ "@opengeni/agent-proto": "^0.5.1-canary.13",
47
+ "@opengeni/artifact-tool": "^0.3.19-canary.4",
48
+ "@opengeni/capabilities": "^0.3.2-canary.4",
49
+ "@opengeni/codemode": "^0.4.27-canary.4",
50
+ "@opengeni/codex": "^0.2.21-canary.4",
51
+ "@opengeni/config": "^1.0.0-canary.4",
52
+ "@opengeni/contracts": "^2.13.0-canary.4",
53
+ "@opengeni/core": "^2.7.5-canary.4",
54
+ "@opengeni/db": "^4.0.0-canary.4",
55
+ "@opengeni/documents": "^0.8.19-canary.4",
56
+ "@opengeni/events": "^0.4.17-canary.4",
57
+ "@opengeni/github": "^0.7.3-canary.4",
58
+ "@opengeni/network": "^0.3.0-canary.4",
59
+ "@opengeni/observability": "^0.8.19-canary.4",
60
+ "@opengeni/runtime": "^2.3.0-canary.4",
61
+ "@opengeni/storage": "^0.2.120-canary.4",
62
+ "@opengeni/tool-gateway": "^0.1.0-canary.4",
63
+ "@opengeni/xai-subscription": "^0.1.3-canary.4",
64
64
  "@temporalio/client": "^1.17.0",
65
65
  "better-auth": "^1.6.14",
66
66
  "hono": "^4.12.18",
@@ -1214,7 +1214,7 @@ export function registerCodexRoutes(app: Hono, deps: ApiRouteDeps): void {
1214
1214
  accountId: grant.accountId,
1215
1215
  workspaceId,
1216
1216
  subjectId: grant.subjectId,
1217
- mode: sourceBeforeConnect.workspaceKind === "personal" ? "automatic" : "workspace",
1217
+ mode: "workspace",
1218
1218
  effectiveSourceBeforeMutation: sourceBeforeConnect.effectiveSource,
1219
1219
  });
1220
1220
  const rotation = await getCodexRotationSettings(tx, workspaceId);
@@ -14,6 +14,7 @@ import {
14
14
  } from "@opengeni/db";
15
15
  import {
16
16
  requireAccessGrant,
17
+ requireWorkspaceSettingsGrant,
17
18
  VIDEO_GENERATION_MODEL_CATALOG,
18
19
  videoGenerationModelSupportsFundingSource,
19
20
  videoGenerationCapabilitiesForPolicy,
@@ -58,7 +59,7 @@ export function registerVideoGenerationRoutes(app: Hono, deps: ApiRouteDeps): vo
58
59
 
59
60
  app.put("/v1/workspaces/:workspaceId/video-generation/policy", async (c) => {
60
61
  const workspaceId = c.req.param("workspaceId");
61
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
62
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
62
63
  const payload = UpdateVideoGenerationPolicyRequest.parse(await c.req.json());
63
64
  const [connection, supergrokConfigured] = await Promise.all([
64
65
  getWorkspaceVercelAiGatewayConnectionMetadata(deps.db, workspaceId),
@@ -181,7 +181,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
181
181
  const workspaceId = context.req.param("workspaceId");
182
182
  await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
183
183
  if (!deps.objectStorage)
184
- throw new HTTPException(503, { message: "Object storage is not configured" });
184
+ throw new HTTPException(503, {
185
+ message: "Object storage is not configured",
186
+ });
185
187
  const ref = await getWorkspaceArtifactContentRef(
186
188
  deps.db,
187
189
  workspaceId,
@@ -193,13 +195,20 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
193
195
 
194
196
  app.get(base, async (context) => {
195
197
  const workspaceId = context.req.param("workspaceId");
196
- await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
198
+ const grant = await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
197
199
  const query = WorkspaceArtifactListQuery.safeParse({
198
200
  limit: context.req.query("limit"),
199
201
  cursor: context.req.query("cursor"),
200
202
  status: context.req.query("status"),
203
+ sourceSessionId: context.req.query("sourceSessionId"),
201
204
  });
202
205
  if (!query.success) throw new HTTPException(422, { message: "Invalid artifact list query" });
206
+ if (
207
+ query.data.sourceSessionId &&
208
+ !(await canReadProvenanceSession(deps, grant, query.data.sourceSessionId))
209
+ ) {
210
+ throw new HTTPException(404, { message: "Session not found" });
211
+ }
203
212
  try {
204
213
  return context.json(
205
214
  WorkspaceArtifactListResponse.parse(
@@ -208,6 +217,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
208
217
  limit: query.data.limit,
209
218
  ...(query.data.cursor ? { cursor: query.data.cursor } : {}),
210
219
  ...(query.data.status ? { status: query.data.status } : {}),
220
+ ...(query.data.sourceSessionId
221
+ ? { sourceSessionId: query.data.sourceSessionId }
222
+ : {}),
211
223
  }),
212
224
  ),
213
225
  ),
@@ -281,7 +293,9 @@ export function registerWorkspaceArtifactRoutes(app: Hono, deps: ApiRouteDeps):
281
293
  const workspaceId = context.req.param("workspaceId");
282
294
  await requireAccessGrant(context, deps, workspaceId, "artifacts:read");
283
295
  if (!deps.objectStorage)
284
- throw new HTTPException(503, { message: "Object storage is not configured" });
296
+ throw new HTTPException(503, {
297
+ message: "Object storage is not configured",
298
+ });
285
299
  const ref = await getWorkspaceArtifactContentRef(
286
300
  deps.db,
287
301
  workspaceId,
@@ -12,6 +12,7 @@ import {
12
12
  import {
13
13
  publishGovernedLearningEventToSlack,
14
14
  requireAccessGrant,
15
+ requireWorkspaceSettingsGrant,
15
16
  type ApiRouteDeps,
16
17
  } from "@opengeni/core";
17
18
  import {
@@ -122,7 +123,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
122
123
 
123
124
  app.post(`${base}/revisions`, async (context) => {
124
125
  const workspaceId = context.req.param("workspaceId");
125
- const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:admin");
126
+ const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
126
127
  const request = await parseBody(context, CreateWorkspaceLearningPolicyRevisionRequest);
127
128
  try {
128
129
  return context.json(
@@ -149,7 +150,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
149
150
  const workspaceId = context.req.param("workspaceId");
150
151
  const revisionId = z.string().uuid().safeParse(context.req.param("revisionId"));
151
152
  if (!revisionId.success) throw new HTTPException(422, { message: "Invalid revision id" });
152
- const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:admin");
153
+ const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
153
154
  const request = await parseBody(context, ActivateWorkspaceLearningPolicyRevisionRequest);
154
155
  try {
155
156
  return context.json(
@@ -174,7 +175,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
174
175
 
175
176
  app.post(`${base}/rollback`, async (context) => {
176
177
  const workspaceId = context.req.param("workspaceId");
177
- const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:admin");
178
+ const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
178
179
  const request = await parseBody(context, RollbackWorkspaceLearningPolicyRevisionRequest);
179
180
  try {
180
181
  return context.json(
@@ -206,7 +207,7 @@ export function registerWorkspaceLearningRoutes(app: Hono, deps: ApiRouteDeps):
206
207
  if (!activationReceiptId.success) {
207
208
  throw new HTTPException(422, { message: "Invalid activation receipt id" });
208
209
  }
209
- const grant = await requireAccessGrant(context, deps, workspaceId, "workspace:admin");
210
+ const grant = await requireWorkspaceSettingsGrant(context, deps, workspaceId);
210
211
  const request = await parseBody(context, UndoGovernedLearningActivationHttpRequest);
211
212
  try {
212
213
  const undo = await undoGovernedLearningActivation(deps.db, {
@@ -88,6 +88,7 @@ import {
88
88
  hasPermission,
89
89
  requireAccessContext,
90
90
  requireAccessGrant,
91
+ requireWorkspaceSettingsGrant,
91
92
  requireFreshAccessGrant,
92
93
  resolveWorkspaceCatalogSettings,
93
94
  } from "@opengeni/core";
@@ -370,7 +371,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
370
371
  // deep-merges (top-level) a settings patch, preserving unknown/future keys.
371
372
  app.patch("/v1/workspaces/:workspaceId/settings", async (c) => {
372
373
  const workspaceId = c.req.param("workspaceId");
373
- await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
374
+ await requireWorkspaceSettingsGrant(c, deps, workspaceId);
374
375
  const parsed = UpdateWorkspaceSettingsRequest.safeParse(await c.req.json());
375
376
  if (!parsed.success) {
376
377
  throw new HTTPException(400, {
@@ -479,7 +480,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
479
480
 
480
481
  app.post("/v1/workspaces/:workspaceId/gateway-custom-models", async (c) => {
481
482
  const workspaceId = c.req.param("workspaceId");
482
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
483
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
483
484
  const parsed = CreateWorkspaceGatewayCustomModelRequest.safeParse(
484
485
  await c.req.json().catch(() => null),
485
486
  );
@@ -555,7 +556,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
555
556
 
556
557
  app.delete("/v1/workspaces/:workspaceId/gateway-custom-models/:customModelId", async (c) => {
557
558
  const workspaceId = c.req.param("workspaceId");
558
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
559
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
559
560
  const customModelId = c.req.param("customModelId");
560
561
  if (
561
562
  !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
@@ -616,7 +617,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
616
617
 
617
618
  app.post("/v1/workspaces/:workspaceId/openrouter-custom-models", async (c) => {
618
619
  const workspaceId = c.req.param("workspaceId");
619
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
620
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
620
621
  const parsed = CreateWorkspaceOpenRouterCustomModelRequest.safeParse(
621
622
  await c.req.json().catch(() => null),
622
623
  );
@@ -694,7 +695,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
694
695
 
695
696
  app.delete("/v1/workspaces/:workspaceId/openrouter-custom-models/:customModelId", async (c) => {
696
697
  const workspaceId = c.req.param("workspaceId");
697
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
698
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
698
699
  const customModelId = c.req.param("customModelId");
699
700
  if (
700
701
  !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
@@ -807,12 +808,12 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
807
808
  });
808
809
 
809
810
  // Full replace (PUT, not merge): null/omitted = unrestricted for that
810
- // dimension; an empty array is a valid explicit total block. Admin access —
811
- // this decides whether turns can reach paid providers, so it is the same
812
- // trust level as billing-affecting workspace settings.
811
+ // dimension; an empty array is a valid explicit total block. Settings access
812
+ // admits workspace administrators and the verified Personal owner, without
813
+ // widening membership or API-key delegation authority.
813
814
  app.put("/v1/workspaces/:workspaceId/model-policy", async (c) => {
814
815
  const workspaceId = c.req.param("workspaceId");
815
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
816
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
816
817
  const payload = UpdateWorkspaceModelPolicyRequest.parse(await c.req.json());
817
818
  const catalog = await resolveWorkspaceCatalogSettings(deps.db, deps.settings, {
818
819
  accountId: grant.accountId,
@@ -829,7 +830,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
829
830
 
830
831
  app.post("/v1/workspaces/:workspaceId/pause-timer", async (c) => {
831
832
  const workspaceId = c.req.param("workspaceId");
832
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
833
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
833
834
  if (workspaceControlUtf8Bytes(grant.subjectId) > WORKSPACE_CONTROL_ACTOR_MAX_BYTES) {
834
835
  throw new HTTPException(400, { message: "workspace-control actor is too large" });
835
836
  }
@@ -862,7 +863,7 @@ export function registerWorkspaceRoutes(app: Hono, deps: ApiRouteDeps): void {
862
863
 
863
864
  app.post("/v1/workspaces/:workspaceId/inference-control", async (c) => {
864
865
  const workspaceId = c.req.param("workspaceId");
865
- const grant = await requireAccessGrant(c, deps, workspaceId, "workspace:admin");
866
+ const grant = await requireWorkspaceSettingsGrant(c, deps, workspaceId);
866
867
  if (workspaceControlUtf8Bytes(grant.subjectId) > WORKSPACE_CONTROL_ACTOR_MAX_BYTES) {
867
868
  throw new HTTPException(400, {
868
869
  message: "workspace-control actor is too large",