@opengeni/core 2.4.0-canary.2 → 2.5.2-canary.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/access/index.d.ts +2 -0
- package/dist/application/composer-submit.d.ts +24 -0
- package/dist/application/session-commands.d.ts +4 -2
- package/dist/canonical-human-identities.d.ts +7 -2
- package/dist/canonical-human-identities.js +17 -4
- package/dist/canonical-human-identities.js.map +1 -1
- package/dist/chunk-YGOMUGYS.js +226 -0
- package/dist/chunk-YGOMUGYS.js.map +1 -0
- package/dist/chunk-ZVZJTMSV.js +369 -0
- package/dist/chunk-ZVZJTMSV.js.map +1 -0
- package/dist/dependencies.d.ts +3 -0
- package/dist/domain/sessions.d.ts +4 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +134 -47
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.d.ts +113 -0
- package/dist/managed-auth-session-sets.js +49 -0
- package/dist/managed-auth-session-sets.js.map +1 -0
- package/dist/managed-session.d.ts +47 -3
- package/package.json +14 -10
- package/src/access/index.ts +8 -1
- package/src/application/composer-submit.ts +76 -0
- package/src/application/session-commands.ts +80 -48
- package/src/canonical-human-identities.ts +22 -3
- package/src/dependencies.ts +3 -0
- package/src/domain/sessions.ts +22 -0
- package/src/index.ts +14 -1
- package/src/managed-auth-session-sets.ts +344 -0
- package/src/managed-session.ts +488 -1
- package/dist/chunk-IBOEYG6N.js +0 -34
- package/dist/chunk-IBOEYG6N.js.map +0 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ManagedAuthSessionSetMode, ManagedAuthSessionSetProjection } from "@opengeni/contracts/managed-auth-session-sets";
|
|
2
|
+
import { type Database, type ManagedAuthDatabaseProjection, type ManagedAuthSelectedSession } from "@opengeni/db";
|
|
3
|
+
export declare const MANAGED_AUTH_SESSION_SET_COOKIE: "opengeni.session_set";
|
|
4
|
+
export declare const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE: "opengeni.login_transaction";
|
|
5
|
+
export declare const MANAGED_AUTH_CSRF_HEADER: "x-opengeni-session-csrf";
|
|
6
|
+
export declare const MANAGED_AUTH_ACTOR_EPOCH_HEADER: "x-opengeni-actor-epoch";
|
|
7
|
+
export declare const MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH: "/v1/auth/session-set/transactions";
|
|
8
|
+
export type ManagedAuthResolvedSession = {
|
|
9
|
+
session: {
|
|
10
|
+
id: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
};
|
|
14
|
+
user: {
|
|
15
|
+
id: string;
|
|
16
|
+
email: string;
|
|
17
|
+
name: string;
|
|
18
|
+
emailVerified: boolean;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
/** Provider-neutral boundary; provider credentials and tokens never cross its output. */
|
|
23
|
+
export interface ManagedAuthSessionAdapter {
|
|
24
|
+
authenticate(input: {
|
|
25
|
+
provider: "email_password";
|
|
26
|
+
transactionId: string;
|
|
27
|
+
credentials: {
|
|
28
|
+
email: string;
|
|
29
|
+
password: string;
|
|
30
|
+
};
|
|
31
|
+
headers: Headers;
|
|
32
|
+
}): Promise<{
|
|
33
|
+
authSessionId: string;
|
|
34
|
+
}>;
|
|
35
|
+
/** Verify an ambient provider cookie without sliding expiry or emitting cookies. */
|
|
36
|
+
resolveAmbientSession(headers: Headers): Promise<ManagedAuthResolvedSession | null>;
|
|
37
|
+
resolveSelectedSession(input: ManagedAuthSelectedSession): Promise<ManagedAuthResolvedSession | null>;
|
|
38
|
+
refreshSelectedSession(input: ManagedAuthSelectedSession): Promise<ManagedAuthResolvedSession | null>;
|
|
39
|
+
revokeSession(input: {
|
|
40
|
+
authSessionId: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
/** Dual-mode exact selected-session cookie plus stale provider-cache invalidations. */
|
|
43
|
+
createLegacySelectedSessionCookies(input: ManagedAuthSelectedSession | null, currentCookieHeader?: string | null): Promise<string[]>;
|
|
44
|
+
}
|
|
45
|
+
export declare class ManagedAuthActorChangeError extends Error {
|
|
46
|
+
readonly name = "ManagedAuthActorChangeError";
|
|
47
|
+
readonly code = "actor_change_required";
|
|
48
|
+
constructor();
|
|
49
|
+
}
|
|
50
|
+
export declare class ManagedAuthRequestAdmissionError extends Error {
|
|
51
|
+
readonly name = "ManagedAuthRequestAdmissionError";
|
|
52
|
+
readonly code = "origin_rejected";
|
|
53
|
+
}
|
|
54
|
+
export declare class ManagedAuthCompletionOutcomeUnknownError extends Error {
|
|
55
|
+
readonly name = "ManagedAuthCompletionOutcomeUnknownError";
|
|
56
|
+
readonly code = "operation_outcome_unknown";
|
|
57
|
+
constructor(options?: ErrorOptions);
|
|
58
|
+
}
|
|
59
|
+
export declare function requireManagedAuthActorFence(input: {
|
|
60
|
+
mode: ManagedAuthSessionSetMode;
|
|
61
|
+
actorEpoch: string;
|
|
62
|
+
expectedActorEpoch: string | null;
|
|
63
|
+
selectedAuthSessionId: string | null;
|
|
64
|
+
legacyAmbientSessionId?: string | null;
|
|
65
|
+
}): void;
|
|
66
|
+
export declare function managedAuthRandomAuthority(): string;
|
|
67
|
+
export declare function managedAuthSha256(value: string): string;
|
|
68
|
+
export declare function managedAuthCsrfHash(authority: string): string;
|
|
69
|
+
export declare function managedAuthCsrfToken(signingSecret: string, authority: string, generation: string): string;
|
|
70
|
+
export declare function managedAuthTransactionSecret(signingSecret: string, authority: string, operationId: string): string;
|
|
71
|
+
export declare function managedAuthDerivedUuid(namespace: string, value: string): string;
|
|
72
|
+
export declare function managedAuthRequestDigest(value: unknown): string;
|
|
73
|
+
export declare function managedAuthSecretRequestDigest(signingSecret: string, value: unknown): string;
|
|
74
|
+
export declare function withManagedAuthCsrfToken(projection: ManagedAuthDatabaseProjection, signingSecret: string, authority: string): ManagedAuthSessionSetProjection;
|
|
75
|
+
export declare function requireManagedAuthMutationAdmission(input: {
|
|
76
|
+
request: Request;
|
|
77
|
+
allowedOrigins: readonly string[];
|
|
78
|
+
authority: string;
|
|
79
|
+
signingSecret: string;
|
|
80
|
+
expectedGeneration: string;
|
|
81
|
+
}): void;
|
|
82
|
+
export declare function resolveManagedAuthSelectedSession(input: {
|
|
83
|
+
db: Database;
|
|
84
|
+
adapter: ManagedAuthSessionAdapter;
|
|
85
|
+
authority: string;
|
|
86
|
+
mode: ManagedAuthSessionSetMode;
|
|
87
|
+
expectedActorEpoch: string | null;
|
|
88
|
+
legacyAmbientSessionId?: string | null;
|
|
89
|
+
allowRecovery?: boolean;
|
|
90
|
+
}): Promise<{
|
|
91
|
+
session: ManagedAuthResolvedSession | null;
|
|
92
|
+
projection: ManagedAuthDatabaseProjection;
|
|
93
|
+
} | null>;
|
|
94
|
+
export declare function authenticateAndAdoptManagedAuthSession(input: {
|
|
95
|
+
db: Database;
|
|
96
|
+
adapter: ManagedAuthSessionAdapter;
|
|
97
|
+
isolatedHeaders: Headers;
|
|
98
|
+
authority: string;
|
|
99
|
+
csrfHash: string;
|
|
100
|
+
operationId: string;
|
|
101
|
+
requestDigest: string;
|
|
102
|
+
expectedGeneration: string;
|
|
103
|
+
expectedActorEpoch: string;
|
|
104
|
+
transactionId: string;
|
|
105
|
+
transactionSecret: string;
|
|
106
|
+
email: string;
|
|
107
|
+
password: string;
|
|
108
|
+
mode: ManagedAuthSessionSetMode;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
projection: ManagedAuthDatabaseProjection;
|
|
111
|
+
returnIntent: string | null;
|
|
112
|
+
}>;
|
|
113
|
+
export declare function isolatedManagedAuthHeaders(request: Request): Headers;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MANAGED_AUTH_ACTOR_EPOCH_HEADER,
|
|
3
|
+
MANAGED_AUTH_CSRF_HEADER,
|
|
4
|
+
MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE,
|
|
5
|
+
MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH,
|
|
6
|
+
MANAGED_AUTH_SESSION_SET_COOKIE,
|
|
7
|
+
ManagedAuthActorChangeError,
|
|
8
|
+
ManagedAuthCompletionOutcomeUnknownError,
|
|
9
|
+
ManagedAuthRequestAdmissionError,
|
|
10
|
+
authenticateAndAdoptManagedAuthSession,
|
|
11
|
+
isolatedManagedAuthHeaders,
|
|
12
|
+
managedAuthCsrfHash,
|
|
13
|
+
managedAuthCsrfToken,
|
|
14
|
+
managedAuthDerivedUuid,
|
|
15
|
+
managedAuthRandomAuthority,
|
|
16
|
+
managedAuthRequestDigest,
|
|
17
|
+
managedAuthSecretRequestDigest,
|
|
18
|
+
managedAuthSha256,
|
|
19
|
+
managedAuthTransactionSecret,
|
|
20
|
+
requireManagedAuthActorFence,
|
|
21
|
+
requireManagedAuthMutationAdmission,
|
|
22
|
+
resolveManagedAuthSelectedSession,
|
|
23
|
+
withManagedAuthCsrfToken
|
|
24
|
+
} from "./chunk-YGOMUGYS.js";
|
|
25
|
+
export {
|
|
26
|
+
MANAGED_AUTH_ACTOR_EPOCH_HEADER,
|
|
27
|
+
MANAGED_AUTH_CSRF_HEADER,
|
|
28
|
+
MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE,
|
|
29
|
+
MANAGED_AUTH_LOGIN_TRANSACTION_COOKIE_PATH,
|
|
30
|
+
MANAGED_AUTH_SESSION_SET_COOKIE,
|
|
31
|
+
ManagedAuthActorChangeError,
|
|
32
|
+
ManagedAuthCompletionOutcomeUnknownError,
|
|
33
|
+
ManagedAuthRequestAdmissionError,
|
|
34
|
+
authenticateAndAdoptManagedAuthSession,
|
|
35
|
+
isolatedManagedAuthHeaders,
|
|
36
|
+
managedAuthCsrfHash,
|
|
37
|
+
managedAuthCsrfToken,
|
|
38
|
+
managedAuthDerivedUuid,
|
|
39
|
+
managedAuthRandomAuthority,
|
|
40
|
+
managedAuthRequestDigest,
|
|
41
|
+
managedAuthSecretRequestDigest,
|
|
42
|
+
managedAuthSha256,
|
|
43
|
+
managedAuthTransactionSecret,
|
|
44
|
+
requireManagedAuthActorFence,
|
|
45
|
+
requireManagedAuthMutationAdmission,
|
|
46
|
+
resolveManagedAuthSelectedSession,
|
|
47
|
+
withManagedAuthCsrfToken
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=managed-auth-session-sets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { Context } from "hono";
|
|
2
2
|
import type { ManagedAuth } from "./managed-auth-type.js";
|
|
3
3
|
import type { Database } from "@opengeni/db";
|
|
4
|
+
import type { ManagedAuthSessionSetMode } from "@opengeni/contracts/managed-auth-session-sets";
|
|
5
|
+
import { type ManagedAuthSessionAdapter } from "./managed-auth-session-sets.js";
|
|
6
|
+
type ActorMutationLeaseRuntime = {
|
|
7
|
+
monotonicNow: () => number;
|
|
8
|
+
schedule: (callback: () => void, delayMs: number) => ReturnType<typeof setTimeout>;
|
|
9
|
+
cancel: (timer: ReturnType<typeof setTimeout>) => void;
|
|
10
|
+
terminate: () => void;
|
|
11
|
+
};
|
|
4
12
|
/**
|
|
5
13
|
* Read a Better Auth session without bypassing its sliding-cookie renewal.
|
|
6
14
|
*
|
|
@@ -9,9 +17,11 @@ import type { Database } from "@opengeni/db";
|
|
|
9
17
|
* headers; the HTTP handler does this automatically, but direct API calls do not.
|
|
10
18
|
*/
|
|
11
19
|
export declare function getManagedSession(c: Context, auth: ManagedAuth, options?: {
|
|
12
|
-
db?: Database;
|
|
13
|
-
allowIdentityRecovery?: boolean;
|
|
14
|
-
|
|
20
|
+
db?: Database | undefined;
|
|
21
|
+
allowIdentityRecovery?: boolean | undefined;
|
|
22
|
+
sessionSetMode?: ManagedAuthSessionSetMode | undefined;
|
|
23
|
+
sessionAdapter?: ManagedAuthSessionAdapter | null | undefined;
|
|
24
|
+
}): Promise<import("./managed-auth-session-sets.js").ManagedAuthResolvedSession | {
|
|
15
25
|
session: {
|
|
16
26
|
id: string;
|
|
17
27
|
createdAt: Date;
|
|
@@ -55,3 +65,37 @@ export declare function getManagedSession(c: Context, auth: ManagedAuth, options
|
|
|
55
65
|
image?: string | null | undefined;
|
|
56
66
|
};
|
|
57
67
|
} | null>;
|
|
68
|
+
/** Safe response provenance for a request authenticated through session-set authority. */
|
|
69
|
+
export declare function getManagedAuthRequestActorEpoch(request: Request): string | null;
|
|
70
|
+
/** Release the multi-replica actor fence after the outer HTTP handler settles. */
|
|
71
|
+
export declare function releaseManagedAuthRequestActorLease(request: Request): Promise<void>;
|
|
72
|
+
/** Cooperative cancellation signal for actor-scoped provider/external I/O. */
|
|
73
|
+
export declare function getManagedAuthRequestActorAbortSignal(request: Request): AbortSignal | null;
|
|
74
|
+
/** @internal Deterministic lease-clock seam used only by direct lifecycle tests. */
|
|
75
|
+
export declare function installManagedAuthActorLeaseRuntimeForTest(overrides: Partial<ActorMutationLeaseRuntime>): () => void;
|
|
76
|
+
/**
|
|
77
|
+
* Exact post-handler fence. A finite unsafe response is not released unless
|
|
78
|
+
* its request-owned lease is still live at the same actor epoch.
|
|
79
|
+
*/
|
|
80
|
+
export declare function validateManagedAuthRequestActorLease(request: Request): Promise<void>;
|
|
81
|
+
export declare class ManagedAuthActorLeaseOutcomeUnknownError extends Error {
|
|
82
|
+
readonly name = "ManagedAuthActorLeaseOutcomeUnknownError";
|
|
83
|
+
readonly code = "operation_outcome_unknown";
|
|
84
|
+
constructor(options?: ErrorOptions);
|
|
85
|
+
}
|
|
86
|
+
/** A known-applied same-request canonical transition intentionally consumes its lease. */
|
|
87
|
+
export declare function markManagedAuthRequestActorTransitionApplied(request: Request): void;
|
|
88
|
+
export type ManagedAuthActorMutationLeaseStamp = {
|
|
89
|
+
authorityHash: string;
|
|
90
|
+
actorEpoch: string;
|
|
91
|
+
requestId: string;
|
|
92
|
+
};
|
|
93
|
+
export type ManagedAuthActorAdmissionStamp = {
|
|
94
|
+
authorityHash: string;
|
|
95
|
+
actorEpoch: string;
|
|
96
|
+
};
|
|
97
|
+
/** Verified server-owned actor evidence available to both reads and mutations. */
|
|
98
|
+
export declare function getManagedAuthRequestActorAdmissionStamp(request: Request): ManagedAuthActorAdmissionStamp | null;
|
|
99
|
+
/** Exact request-owned fence passed into a same-transaction actor transition. */
|
|
100
|
+
export declare function getManagedAuthRequestActorLeaseStamp(request: Request): ManagedAuthActorMutationLeaseStamp | null;
|
|
101
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.2-canary.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": {
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./dist/canonical-human-identities.d.ts",
|
|
35
35
|
"import": "./dist/canonical-human-identities.js"
|
|
36
36
|
},
|
|
37
|
+
"./managed-auth-session-sets": {
|
|
38
|
+
"types": "./dist/managed-auth-session-sets.d.ts",
|
|
39
|
+
"import": "./dist/managed-auth-session-sets.js"
|
|
40
|
+
},
|
|
37
41
|
"./connection-authority": {
|
|
38
42
|
"types": "./dist/domain/connection-authority.d.ts",
|
|
39
43
|
"import": "./dist/domain/connection-authority.js"
|
|
@@ -50,15 +54,15 @@
|
|
|
50
54
|
},
|
|
51
55
|
"dependencies": {
|
|
52
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
53
|
-
"@opengeni/codex": "^0.2.19-canary.
|
|
54
|
-
"@opengeni/config": "^0.
|
|
55
|
-
"@opengeni/contracts": "^2.
|
|
56
|
-
"@opengeni/db": "^3.
|
|
57
|
-
"@opengeni/documents": "^0.8.
|
|
58
|
-
"@opengeni/events": "^0.4.
|
|
59
|
-
"@opengeni/observability": "^0.8.
|
|
60
|
-
"@opengeni/runtime": "^1.4.
|
|
61
|
-
"@opengeni/storage": "^0.2.
|
|
57
|
+
"@opengeni/codex": "^0.2.19-canary.4",
|
|
58
|
+
"@opengeni/config": "^0.21.0-canary.0",
|
|
59
|
+
"@opengeni/contracts": "^2.6.0-canary.0",
|
|
60
|
+
"@opengeni/db": "^3.5.2-canary.0",
|
|
61
|
+
"@opengeni/documents": "^0.8.5-canary.0",
|
|
62
|
+
"@opengeni/events": "^0.4.3-canary.0",
|
|
63
|
+
"@opengeni/observability": "^0.8.8-canary.0",
|
|
64
|
+
"@opengeni/runtime": "^1.4.1-canary.0",
|
|
65
|
+
"@opengeni/storage": "^0.2.109-canary.0",
|
|
62
66
|
"hono": "^4.12.18",
|
|
63
67
|
"zod": "^4.2.1"
|
|
64
68
|
},
|
package/src/access/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import type { Context } from "hono";
|
|
|
18
18
|
import { HTTPException } from "hono/http-exception";
|
|
19
19
|
import type { ManagedAuth } from "../managed-auth-type";
|
|
20
20
|
import { getManagedSession } from "../managed-session";
|
|
21
|
+
import type { ManagedAuthSessionAdapter } from "../managed-auth-session-sets";
|
|
21
22
|
|
|
22
23
|
const bearerPrefix = "Bearer ";
|
|
23
24
|
const accessContextByRequest = new WeakMap<Request, Promise<AccessContext | null>>();
|
|
@@ -61,6 +62,7 @@ export type AccessDeps = {
|
|
|
61
62
|
db: Database;
|
|
62
63
|
settings: Settings;
|
|
63
64
|
managedAuth?: ManagedAuth | null;
|
|
65
|
+
managedAuthSessionAdapter?: ManagedAuthSessionAdapter | null;
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
export async function requireAccessContext(c: Context, deps: AccessDeps): Promise<AccessContext> {
|
|
@@ -377,7 +379,11 @@ async function resolveAccessContext(c: Context, deps: AccessDeps): Promise<Acces
|
|
|
377
379
|
}
|
|
378
380
|
|
|
379
381
|
if (deps.managedAuth) {
|
|
380
|
-
const session = await getManagedSession(c, deps.managedAuth, {
|
|
382
|
+
const session = await getManagedSession(c, deps.managedAuth, {
|
|
383
|
+
db: deps.db,
|
|
384
|
+
sessionSetMode: deps.settings.managedAuthSessionSetMode,
|
|
385
|
+
sessionAdapter: deps.managedAuthSessionAdapter,
|
|
386
|
+
});
|
|
381
387
|
if (session?.user) {
|
|
382
388
|
// THE canonical managed-cookie (Better Auth) branch, and the only place
|
|
383
389
|
// that may stamp a context as such. Every `return` above this point leaves
|
|
@@ -389,6 +395,7 @@ async function resolveAccessContext(c: Context, deps: AccessDeps): Promise<Acces
|
|
|
389
395
|
name: session.user.name,
|
|
390
396
|
emailVerified: session.user.emailVerified,
|
|
391
397
|
provisionFallbackOrganization: false,
|
|
398
|
+
bindPendingInvitations: false,
|
|
392
399
|
});
|
|
393
400
|
canonicalManagedCookieContexts.add(context);
|
|
394
401
|
return context;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AccessGrant,
|
|
3
|
+
ResourceRef,
|
|
4
|
+
SubmitComposerDraftRequest,
|
|
5
|
+
SubmitComposerDraftResponse,
|
|
6
|
+
} from "@opengeni/contracts";
|
|
7
|
+
import type { AccessGrantAuthorization } from "../access";
|
|
8
|
+
import type { AcceptSessionUserMessageDependencies } from "../dependencies";
|
|
9
|
+
import { acceptSessionUserMessageWithOutcome } from "../domain/sessions";
|
|
10
|
+
|
|
11
|
+
export type SubmitComposerDraftForRequestOptions = {
|
|
12
|
+
authorization?: AccessGrantAuthorization | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Trusted host-owned resources admitted with this command without writing
|
|
15
|
+
* them into the actor's browser-visible draft first. The saved draft remains
|
|
16
|
+
* the exact content fence for actor-owned text, annotations, resources, and
|
|
17
|
+
* execution policy; these resources participate in the accepted command's
|
|
18
|
+
* idempotency hash, validation, turn, and durable session resource set.
|
|
19
|
+
*/
|
|
20
|
+
additionalResources?: ResourceRef[] | undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Atomically accept one established-session composer draft.
|
|
25
|
+
*
|
|
26
|
+
* This is the application boundary shared by the stock HTTP adapter and an
|
|
27
|
+
* in-process embedding host. A host may prepare its own durable business state
|
|
28
|
+
* before calling this function and project the returned receipt afterward, but
|
|
29
|
+
* OpenGeni remains the sole authority for draft validation/rotation, event
|
|
30
|
+
* append, turn creation, routing, and idempotent replay.
|
|
31
|
+
*/
|
|
32
|
+
export async function submitComposerDraftForRequest(
|
|
33
|
+
deps: AcceptSessionUserMessageDependencies,
|
|
34
|
+
grant: AccessGrant,
|
|
35
|
+
workspaceId: string,
|
|
36
|
+
sessionId: string,
|
|
37
|
+
input: SubmitComposerDraftRequest,
|
|
38
|
+
options: SubmitComposerDraftForRequestOptions = {},
|
|
39
|
+
): Promise<SubmitComposerDraftResponse> {
|
|
40
|
+
const additionalResources = options.additionalResources ?? [];
|
|
41
|
+
const result = await acceptSessionUserMessageWithOutcome(deps, grant, workspaceId, sessionId, {
|
|
42
|
+
text: input.text,
|
|
43
|
+
annotations: input.annotations,
|
|
44
|
+
modelContext: input.modelContext ?? null,
|
|
45
|
+
resources: [...input.resources, ...additionalResources],
|
|
46
|
+
...(additionalResources.length > 0 ? { composerDraftResources: input.resources } : {}),
|
|
47
|
+
model: input.model,
|
|
48
|
+
reasoningEffort: input.reasoningEffort,
|
|
49
|
+
latencyMode: input.latencyMode,
|
|
50
|
+
mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
|
|
51
|
+
connectionAuthorities: input.connectionAuthorities,
|
|
52
|
+
...(input.personalResourceAttachment
|
|
53
|
+
? { personalResourceAttachment: input.personalResourceAttachment }
|
|
54
|
+
: {}),
|
|
55
|
+
...(options.authorization ? { authorization: options.authorization } : {}),
|
|
56
|
+
delivery: input.delivery,
|
|
57
|
+
origin: "human",
|
|
58
|
+
expectedDraftRevision: input.expectedDraftRevision,
|
|
59
|
+
clientEventId: input.clientEventId,
|
|
60
|
+
...(input.controlEtag ? { controlEtag: input.controlEtag } : {}),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (!result.draft) {
|
|
64
|
+
throw new Error("Accepted composer draft submission did not return its next draft");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
accepted: result.accepted,
|
|
69
|
+
turn: result.turn,
|
|
70
|
+
draft: result.draft,
|
|
71
|
+
receipt: result.receipt,
|
|
72
|
+
routing: result.routing,
|
|
73
|
+
interruptionCount: result.interruptionCount,
|
|
74
|
+
replay: result.replay,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -511,26 +511,38 @@ export async function controlAgentSessionWorkstream(
|
|
|
511
511
|
},
|
|
512
512
|
);
|
|
513
513
|
scheduleSessionCommandPostCommit(deps, "agent_control", [
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
514
|
+
...(result.sessionControlEventId
|
|
515
|
+
? [
|
|
516
|
+
{
|
|
517
|
+
kind: "session_event_fanout" as const,
|
|
518
|
+
run: async () =>
|
|
519
|
+
await publishSessionEventIds(deps, context.workspaceId, input.targetSessionId, [
|
|
520
|
+
result.sessionControlEventId!,
|
|
521
|
+
]),
|
|
522
|
+
},
|
|
523
|
+
]
|
|
524
|
+
: []),
|
|
525
|
+
...(result.workspaceControlEventId
|
|
526
|
+
? [
|
|
527
|
+
{
|
|
528
|
+
kind: "workspace_control_fanout" as const,
|
|
529
|
+
run: async () =>
|
|
530
|
+
await publishWorkspaceControlEvent(
|
|
531
|
+
deps,
|
|
532
|
+
context.workspaceId,
|
|
533
|
+
result.workspaceControlEventId!,
|
|
534
|
+
),
|
|
535
|
+
},
|
|
536
|
+
]
|
|
537
|
+
: []),
|
|
538
|
+
...(result.wakeCount > 0
|
|
539
|
+
? [
|
|
540
|
+
{
|
|
541
|
+
kind: "workflow_wake" as const,
|
|
542
|
+
run: async () => await requestControlWakeDispatch(deps, result.wakeCount),
|
|
543
|
+
},
|
|
544
|
+
]
|
|
545
|
+
: []),
|
|
534
546
|
{
|
|
535
547
|
kind: "workflow_wake",
|
|
536
548
|
run: async () => {
|
|
@@ -832,7 +844,11 @@ export async function controlHumanSessionWorkstreamWithOutcome(
|
|
|
832
844
|
} & SessionCommandPostCommitDeps,
|
|
833
845
|
context: HumanSessionCommandContext,
|
|
834
846
|
input: SessionControlRequest,
|
|
835
|
-
): Promise<{
|
|
847
|
+
): Promise<{
|
|
848
|
+
response: SessionControlResponse;
|
|
849
|
+
outcome: "changed" | "unchanged" | "replayed";
|
|
850
|
+
replay: boolean;
|
|
851
|
+
}> {
|
|
836
852
|
const authorization = await authorizeHumanSessionCommand(deps, context, "session.control");
|
|
837
853
|
const result = await runSessionCommandPersistenceTransaction(
|
|
838
854
|
deps,
|
|
@@ -879,19 +895,27 @@ export async function controlHumanSessionWorkstreamWithOutcome(
|
|
|
879
895
|
affected.eventIds,
|
|
880
896
|
),
|
|
881
897
|
})),
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
898
|
+
...(result.workspaceControlEventId
|
|
899
|
+
? [
|
|
900
|
+
{
|
|
901
|
+
kind: "workspace_control_fanout" as const,
|
|
902
|
+
run: async () =>
|
|
903
|
+
await publishWorkspaceControlEvent(
|
|
904
|
+
deps,
|
|
905
|
+
context.workspaceId,
|
|
906
|
+
result.workspaceControlEventId!,
|
|
907
|
+
),
|
|
908
|
+
},
|
|
909
|
+
]
|
|
910
|
+
: []),
|
|
911
|
+
...(result.wakeCount > 0
|
|
912
|
+
? [
|
|
913
|
+
{
|
|
914
|
+
kind: "workflow_wake" as const,
|
|
915
|
+
run: async () => await requestControlWakeDispatch(deps, result.wakeCount),
|
|
916
|
+
},
|
|
917
|
+
]
|
|
918
|
+
: []),
|
|
895
919
|
{
|
|
896
920
|
kind: "workflow_wake",
|
|
897
921
|
run: async () => {
|
|
@@ -909,7 +933,7 @@ export async function controlHumanSessionWorkstreamWithOutcome(
|
|
|
909
933
|
},
|
|
910
934
|
},
|
|
911
935
|
]);
|
|
912
|
-
return { response, replay: result.replay };
|
|
936
|
+
return { response, outcome: result.outcome, replay: result.replay };
|
|
913
937
|
}
|
|
914
938
|
|
|
915
939
|
/** Backward-compatible response path used by the REST control route. */
|
|
@@ -952,19 +976,27 @@ export async function controlHumanWorkspace(
|
|
|
952
976
|
wakeCount: result.wakeCount,
|
|
953
977
|
};
|
|
954
978
|
scheduleSessionCommandPostCommit(deps, "human_workspace_control", [
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
979
|
+
...(result.workspaceControlEventId
|
|
980
|
+
? [
|
|
981
|
+
{
|
|
982
|
+
kind: "workspace_control_fanout" as const,
|
|
983
|
+
run: async () =>
|
|
984
|
+
await publishWorkspaceControlEvent(
|
|
985
|
+
deps,
|
|
986
|
+
context.workspaceId,
|
|
987
|
+
result.workspaceControlEventId!,
|
|
988
|
+
),
|
|
989
|
+
},
|
|
990
|
+
]
|
|
991
|
+
: []),
|
|
992
|
+
...(result.wakeCount > 0
|
|
993
|
+
? [
|
|
994
|
+
{
|
|
995
|
+
kind: "workflow_wake" as const,
|
|
996
|
+
run: async () => await requestControlWakeDispatch(deps, result.wakeCount),
|
|
997
|
+
},
|
|
998
|
+
]
|
|
999
|
+
: []),
|
|
968
1000
|
]);
|
|
969
1001
|
return response;
|
|
970
1002
|
}
|
|
@@ -3,6 +3,13 @@ import type { Context } from "hono";
|
|
|
3
3
|
import { HTTPException } from "hono/http-exception";
|
|
4
4
|
import type { ManagedAuth } from "./managed-auth-type";
|
|
5
5
|
import { getManagedSession } from "./managed-session";
|
|
6
|
+
export {
|
|
7
|
+
getManagedAuthRequestActorAdmissionStamp,
|
|
8
|
+
getManagedAuthRequestActorLeaseStamp,
|
|
9
|
+
markManagedAuthRequestActorTransitionApplied,
|
|
10
|
+
} from "./managed-session";
|
|
11
|
+
import type { ManagedAuthSessionAdapter } from "./managed-auth-session-sets";
|
|
12
|
+
import type { ManagedAuthSessionSetMode } from "@opengeni/contracts/managed-auth-session-sets";
|
|
6
13
|
|
|
7
14
|
export type CanonicalHumanRequestIdentity = {
|
|
8
15
|
authUserId: string;
|
|
@@ -11,17 +18,29 @@ export type CanonicalHumanRequestIdentity = {
|
|
|
11
18
|
|
|
12
19
|
export async function requireCanonicalHumanRequestIdentity(
|
|
13
20
|
context: Context,
|
|
14
|
-
input: {
|
|
21
|
+
input: {
|
|
22
|
+
db: Database;
|
|
23
|
+
managedAuth?: ManagedAuth | null | undefined;
|
|
24
|
+
managedAuthSessionAdapter?: ManagedAuthSessionAdapter | null | undefined;
|
|
25
|
+
managedAuthSessionSetMode?: ManagedAuthSessionSetMode | undefined;
|
|
26
|
+
allowRecovery?: boolean | undefined;
|
|
27
|
+
},
|
|
15
28
|
): Promise<CanonicalHumanRequestIdentity> {
|
|
16
29
|
if (!input.managedAuth) {
|
|
17
|
-
throw new HTTPException(404, {
|
|
30
|
+
throw new HTTPException(404, {
|
|
31
|
+
message: "Canonical human identity is unavailable",
|
|
32
|
+
});
|
|
18
33
|
}
|
|
19
34
|
const session = await getManagedSession(context, input.managedAuth, {
|
|
20
35
|
db: input.db,
|
|
36
|
+
sessionAdapter: input.managedAuthSessionAdapter,
|
|
37
|
+
sessionSetMode: input.managedAuthSessionSetMode,
|
|
21
38
|
...(input.allowRecovery === undefined ? {} : { allowIdentityRecovery: input.allowRecovery }),
|
|
22
39
|
});
|
|
23
40
|
if (!session?.user || typeof session.session?.id !== "string") {
|
|
24
|
-
throw new HTTPException(401, {
|
|
41
|
+
throw new HTTPException(401, {
|
|
42
|
+
message: "Managed human authentication required",
|
|
43
|
+
});
|
|
25
44
|
}
|
|
26
45
|
return { authUserId: session.user.id, authSessionId: session.session.id };
|
|
27
46
|
}
|
package/src/dependencies.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type { EventBus } from "@opengeni/events";
|
|
|
15
15
|
import type { Observability } from "@opengeni/observability";
|
|
16
16
|
import type { createObjectStorage } from "@opengeni/storage";
|
|
17
17
|
import type { ManagedAuth } from "./managed-auth-type";
|
|
18
|
+
import type { ManagedAuthSessionAdapter } from "./managed-auth-session-sets";
|
|
18
19
|
import type { ApiSandboxClient, ResumeBoxByIdInput, ResumedSandboxSession } from "./sandbox-types";
|
|
19
20
|
import type { TranscriptionSegmenter, TranscriptionService } from "./transcription";
|
|
20
21
|
import type { EditableArtifactApplicationPort } from "./editable-artifact-live";
|
|
@@ -177,6 +178,8 @@ export type AppDependencies = {
|
|
|
177
178
|
*/
|
|
178
179
|
sessionAuthorization?: SessionAuthorizationPort | null;
|
|
179
180
|
managedAuth?: ManagedAuth | null;
|
|
181
|
+
/** Provider-neutral browser login-slot adapter; required by dual/broker managed auth. */
|
|
182
|
+
managedAuthSessionAdapter?: ManagedAuthSessionAdapter | null;
|
|
180
183
|
/** Injectable managed-email transport; standalone API defaults to Resend or local capture. */
|
|
181
184
|
managedEmailTransport?: ManagedEmailTransport;
|
|
182
185
|
/** Injectable Codex HTTP transport for deterministic API/provider tests. */
|