@opengeni/core 0.24.1 → 0.28.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.
@@ -1,5 +1,6 @@
1
1
  import type { Context } from "hono";
2
2
  import type { ManagedAuth } from "./managed-auth-type.js";
3
+ import type { Database } from "@opengeni/db";
3
4
  /**
4
5
  * Read a Better Auth session without bypassing its sliding-cookie renewal.
5
6
  *
@@ -7,7 +8,10 @@ import type { ManagedAuth } from "./managed-auth-type.js";
7
8
  * Programmatic callers must explicitly request and forward the returned cookie
8
9
  * headers; the HTTP handler does this automatically, but direct API calls do not.
9
10
  */
10
- export declare function getManagedSession(c: Context, auth: ManagedAuth): Promise<{
11
+ export declare function getManagedSession(c: Context, auth: ManagedAuth, options?: {
12
+ db?: Database;
13
+ allowIdentityRecovery?: boolean;
14
+ }): Promise<{
11
15
  session: {
12
16
  id: string;
13
17
  createdAt: Date;
@@ -28,8 +28,9 @@ export type FleetContext = {
28
28
  };
29
29
  /**
30
30
  * Build a session-scoped {@link FleetContext}: load the session (workspace-
31
- * scoped), reject a session with no box (backend:none the fleet is only
32
- * meaningful for a sandboxed session), and project its group backend/id. Shared
31
+ * scoped) and project its group backend/id. A backend:none session has no home
32
+ * box, but it may still discover, run on, and attach an owned Connected Machine.
33
+ * Shared
33
34
  * by the worker-signed MCP fleet tools and the user-authenticated swap REST
34
35
  * route so both resolve the SAME context (no drift). The `accountId`/`workspaceId`/
35
36
  * `sessionId` come from the trusted grant/route; the backend + group id come from
@@ -108,9 +109,11 @@ export type FleetSwapResult = {
108
109
  code?: BackendUnresolvableCode | "concurrent_swap" | "recovery_in_progress" | "recovery_degraded" | "recovery_unrecoverable";
109
110
  };
110
111
  /**
111
- * List the fleet: the session's own Modal group box (a synthetic entry) + the
112
- * workspace's first-class selfhosted sandboxes (each probed for liveness), each
113
- * with an `active` marker derived from the session's active pointer.
112
+ * List the fleet: the session's own group box when it has one (a synthetic
113
+ * entry) + the workspace's first-class selfhosted sandboxes (each probed for
114
+ * liveness), each with an `active` marker derived from the session's active
115
+ * pointer. A backend:none session has no synthetic home entry; a null pointer
116
+ * then means no compute is attached.
114
117
  */
115
118
  export declare function listFleet(services: FleetServices, ctx: FleetContext): Promise<FleetListResult>;
116
119
  /**
@@ -1,5 +1,5 @@
1
1
  import { SessionAuthorizationActor, SessionAuthorizationListScope, type AccessGrant, type SessionAuthorizationOperation, type SessionAuthorizationSurface, type SessionAuthorizationTarget } from "@opengeni/contracts";
2
- import { type Database } from "@opengeni/db";
2
+ import { type Database, type SessionRlsActorContext } from "@opengeni/db";
3
3
  import type { AppDependencies } from "./dependencies.js";
4
4
  export type SessionAuthorizationDependencies = Pick<AppDependencies, "db" | "sessionAuthorization">;
5
5
  /** Maximum time an omitted host hint leaves a live session stream unchecked. */
@@ -19,6 +19,8 @@ export type ResolvedSessionAuthorization = {
19
19
  relatedSessionAccess: "target" | "root";
20
20
  reauthorizeAfterMs: number | null;
21
21
  };
22
+ export declare function sessionRlsActorForAuthorization(authorization: ResolvedSessionAuthorization): SessionRlsActorContext;
23
+ export declare function withResolvedSessionAuthorization<T>(authorization: ResolvedSessionAuthorization, fn: () => Promise<T>): Promise<T>;
22
24
  /**
23
25
  * Prove that a first-party request belongs to the exact currently active
24
26
  * attempt of the named caller session. Unlike the optional embedding-host ACL
@@ -16,6 +16,8 @@ export type TranscriptionLimits = {
16
16
  export type TranscriptionRequest = {
17
17
  workspaceId: string;
18
18
  accountId: string;
19
+ /** Authenticated human/service subject used for provider-account authority. */
20
+ subjectId: string;
19
21
  audio: Uint8Array;
20
22
  mimeType: string;
21
23
  /** Optional client-reported duration; enforced as a soft ceiling before upstream. */
@@ -48,6 +50,7 @@ export declare function statusForVoiceInputError(code: VoiceInputErrorCode): num
48
50
  /** Optional workspace scope for readiness checks during provider selection. */
49
51
  export type TranscriptionAvailabilityContext = {
50
52
  workspaceId?: string | undefined;
53
+ subjectId?: string | undefined;
51
54
  };
52
55
  /**
53
56
  * Extensible transcription provider port. Implementations own credentials and
@@ -69,6 +72,8 @@ export type TranscriptionProvider = {
69
72
  mimeType: string;
70
73
  filename: string;
71
74
  workspaceId: string;
75
+ accountId: string;
76
+ subjectId: string;
72
77
  requestId: string;
73
78
  signal?: AbortSignal | undefined;
74
79
  }): Promise<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/core",
3
- "version": "0.24.1",
3
+ "version": "0.28.0",
4
4
  "description": "OpenGeni framework-agnostic core: the domain, access, and billing layers (neutral access, off-HTTP V2 surface). Behavior-preserving extraction from apps/api — keeps Hono's HTTPException for error throwing (typed-errors cleanup deferred).",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,6 +29,10 @@
29
29
  "./editable-artifact-live": {
30
30
  "types": "./dist/editable-artifact-live.d.ts",
31
31
  "import": "./dist/editable-artifact-live.js"
32
+ },
33
+ "./canonical-human-identities": {
34
+ "types": "./dist/canonical-human-identities.d.ts",
35
+ "import": "./dist/canonical-human-identities.js"
32
36
  }
33
37
  },
34
38
  "publishConfig": {
@@ -42,15 +46,15 @@
42
46
  },
43
47
  "dependencies": {
44
48
  "@modelcontextprotocol/sdk": "^1.29.0",
45
- "@opengeni/codex": "^0.2.15",
46
- "@opengeni/config": "^0.13.2",
47
- "@opengeni/contracts": "^0.44.1",
48
- "@opengeni/db": "^0.31.1",
49
- "@opengeni/documents": "^0.5.32",
50
- "@opengeni/events": "^0.3.103",
51
- "@opengeni/observability": "^0.6.2",
52
- "@opengeni/runtime": "^0.19.2",
53
- "@opengeni/storage": "^0.2.87",
49
+ "@opengeni/codex": "^0.2.16",
50
+ "@opengeni/config": "^0.16.1",
51
+ "@opengeni/contracts": "^0.50.0",
52
+ "@opengeni/db": "^0.36.0",
53
+ "@opengeni/documents": "^0.5.38",
54
+ "@opengeni/events": "^0.3.109",
55
+ "@opengeni/observability": "^0.7.5",
56
+ "@opengeni/runtime": "^0.23.0",
57
+ "@opengeni/storage": "^0.2.93",
54
58
  "hono": "^4.12.18"
55
59
  },
56
60
  "engines": {
@@ -20,6 +20,7 @@ import type { ManagedAuth } from "../managed-auth-type";
20
20
  import { getManagedSession } from "../managed-session";
21
21
 
22
22
  const bearerPrefix = "Bearer ";
23
+ const accessContextByRequest = new WeakMap<Request, Promise<AccessContext | null>>();
23
24
 
24
25
  export type AccessDeps = {
25
26
  db: Database;
@@ -28,7 +29,12 @@ export type AccessDeps = {
28
29
  };
29
30
 
30
31
  export async function requireAccessContext(c: Context, deps: AccessDeps): Promise<AccessContext> {
31
- const context = await resolveAccessContext(c, deps);
32
+ let pending = accessContextByRequest.get(c.req.raw);
33
+ if (!pending) {
34
+ pending = resolveAccessContext(c, deps);
35
+ accessContextByRequest.set(c.req.raw, pending);
36
+ }
37
+ const context = await pending;
32
38
  if (!context) {
33
39
  throw new HTTPException(401, { message: "authentication required" });
34
40
  }
@@ -252,7 +258,7 @@ async function resolveAccessContext(c: Context, deps: AccessDeps): Promise<Acces
252
258
  }
253
259
 
254
260
  if (deps.managedAuth) {
255
- const session = await getManagedSession(c, deps.managedAuth);
261
+ const session = await getManagedSession(c, deps.managedAuth, { db: deps.db });
256
262
  if (session?.user) {
257
263
  return await ensureManagedAccessForUser(deps.db, {
258
264
  userId: session.user.id,
@@ -355,6 +361,12 @@ async function delegatedAccessContext(
355
361
  ...(payload.firstPartyMcpTools !== undefined
356
362
  ? { firstPartyMcpTools: payload.firstPartyMcpTools }
357
363
  : {}),
364
+ ...(payload.nestedAgentDepth !== undefined
365
+ ? { nestedAgentDepth: payload.nestedAgentDepth }
366
+ : {}),
367
+ ...(payload.effectiveMaxNestedAgentDepth !== undefined
368
+ ? { effectiveMaxNestedAgentDepth: payload.effectiveMaxNestedAgentDepth }
369
+ : {}),
358
370
  // Caller identity: the turn that minted this token. Tools classify the
359
371
  // CALLER from this instead of re-reading the live active pointer.
360
372
  ...(payload.turnId ? { turnId: payload.turnId } : {}),
@@ -0,0 +1,27 @@
1
+ import type { Database } from "@opengeni/db";
2
+ import type { Context } from "hono";
3
+ import { HTTPException } from "hono/http-exception";
4
+ import type { ManagedAuth } from "./managed-auth-type";
5
+ import { getManagedSession } from "./managed-session";
6
+
7
+ export type CanonicalHumanRequestIdentity = {
8
+ authUserId: string;
9
+ authSessionId: string;
10
+ };
11
+
12
+ export async function requireCanonicalHumanRequestIdentity(
13
+ context: Context,
14
+ input: { db: Database; managedAuth?: ManagedAuth | null; allowRecovery?: boolean },
15
+ ): Promise<CanonicalHumanRequestIdentity> {
16
+ if (!input.managedAuth) {
17
+ throw new HTTPException(404, { message: "Canonical human identity is unavailable" });
18
+ }
19
+ const session = await getManagedSession(context, input.managedAuth, {
20
+ db: input.db,
21
+ ...(input.allowRecovery === undefined ? {} : { allowIdentityRecovery: input.allowRecovery }),
22
+ });
23
+ if (!session?.user || typeof session.session?.id !== "string") {
24
+ throw new HTTPException(401, { message: "Managed human authentication required" });
25
+ }
26
+ return { authUserId: session.user.id, authSessionId: session.session.id };
27
+ }
@@ -138,11 +138,15 @@ export type AppDependencies = {
138
138
  managedAuth?: ManagedAuth | null;
139
139
  /** Injectable Codex HTTP transport for deterministic API/provider tests. */
140
140
  codexFetch?: typeof fetch;
141
+ /** Injectable xAI OAuth/subscription transport for deterministic API/provider tests. */
142
+ xaiFetch?: typeof fetch;
141
143
  /** Injectable Slack Web API transport for deterministic bot-connection tests. */
142
144
  slackFetch?: typeof fetch;
143
145
  /** Injectable Google OAuth/Drive transport for deterministic connector tests. */
144
146
  googleDriveFetch?: typeof fetch;
145
- /** Injectable provider-preset OAuth/API transport for deterministic integration tests. */
147
+ /** Injectable Fiken API transport for deterministic connector tests. */
148
+ fikenFetch?: typeof fetch;
149
+ /** Injectable Integration Definition OAuth/API transport for deterministic tests. */
146
150
  apiIntegrationOAuthFetch?: typeof fetch;
147
151
  atlassianFetch?: typeof fetch;
148
152
  /** Injectable MCP OAuth setup deadline for deterministic stalled-provider tests. */