@keycardai/eve 0.1.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.
Files changed (52) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +223 -0
  3. package/dist/esm/auth.d.ts +62 -0
  4. package/dist/esm/auth.d.ts.map +1 -0
  5. package/dist/esm/auth.js +165 -0
  6. package/dist/esm/auth.js.map +1 -0
  7. package/dist/esm/config.d.ts +50 -0
  8. package/dist/esm/config.d.ts.map +1 -0
  9. package/dist/esm/config.js +83 -0
  10. package/dist/esm/config.js.map +1 -0
  11. package/dist/esm/connections.d.ts +48 -0
  12. package/dist/esm/connections.d.ts.map +1 -0
  13. package/dist/esm/connections.js +167 -0
  14. package/dist/esm/connections.js.map +1 -0
  15. package/dist/esm/errors.d.ts +78 -0
  16. package/dist/esm/errors.d.ts.map +1 -0
  17. package/dist/esm/errors.js +93 -0
  18. package/dist/esm/errors.js.map +1 -0
  19. package/dist/esm/expiry.d.ts +20 -0
  20. package/dist/esm/expiry.d.ts.map +1 -0
  21. package/dist/esm/expiry.js +49 -0
  22. package/dist/esm/expiry.js.map +1 -0
  23. package/dist/esm/index.d.ts +44 -0
  24. package/dist/esm/index.d.ts.map +1 -0
  25. package/dist/esm/index.js +37 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/interactive.d.ts +90 -0
  28. package/dist/esm/interactive.d.ts.map +1 -0
  29. package/dist/esm/interactive.js +190 -0
  30. package/dist/esm/interactive.js.map +1 -0
  31. package/dist/esm/package.json +1 -0
  32. package/dist/esm/requireAuth.d.ts +35 -0
  33. package/dist/esm/requireAuth.d.ts.map +1 -0
  34. package/dist/esm/requireAuth.js +26 -0
  35. package/dist/esm/requireAuth.js.map +1 -0
  36. package/dist/esm/subjectTokens.d.ts +50 -0
  37. package/dist/esm/subjectTokens.d.ts.map +1 -0
  38. package/dist/esm/subjectTokens.js +73 -0
  39. package/dist/esm/subjectTokens.js.map +1 -0
  40. package/dist/esm/testing/index.d.ts +10 -0
  41. package/dist/esm/testing/index.d.ts.map +1 -0
  42. package/dist/esm/testing/index.js +9 -0
  43. package/dist/esm/testing/index.js.map +1 -0
  44. package/dist/esm/testing/testUtils.d.ts +51 -0
  45. package/dist/esm/testing/testUtils.d.ts.map +1 -0
  46. package/dist/esm/testing/testUtils.js +90 -0
  47. package/dist/esm/testing/testUtils.js.map +1 -0
  48. package/dist/esm/zoneClient.d.ts +42 -0
  49. package/dist/esm/zoneClient.d.ts.map +1 -0
  50. package/dist/esm/zoneClient.js +45 -0
  51. package/dist/esm/zoneClient.js.map +1 -0
  52. package/package.json +53 -0
@@ -0,0 +1,48 @@
1
+ import type { ConnectionPrincipal, NonInteractiveAuthorizationDefinition } from "eve/connections";
2
+ import { type KeycardConnectionOptions } from "./config.js";
3
+ /** Options for {@link impersonate}. */
4
+ export interface KeycardImpersonateOptions extends KeycardConnectionOptions {
5
+ /**
6
+ * The user the agent acts for. A function receives the connection principal,
7
+ * so a session-scoped identifier can be read from the turn's current auth.
8
+ */
9
+ userIdentifier: string | ((principal: ConnectionPrincipal) => string);
10
+ }
11
+ /**
12
+ * Connection auth that runs client credentials under the agent's own identity.
13
+ *
14
+ * App-scoped: eve resolves `{ type: "app" }` and never asks the session for a
15
+ * user, so this works on schedules and subagent turns. No exchange and no
16
+ * impersonation, so nothing about the caller reaches the zone.
17
+ */
18
+ export declare function asSelf(options: KeycardConnectionOptions): NonInteractiveAuthorizationDefinition;
19
+ /**
20
+ * Connection auth that exchanges the caller's token for a resource token.
21
+ *
22
+ * User-scoped, so eve resolves the principal from the active turn's
23
+ * `ctx.session.auth.current` and fails with `principal_required` before this
24
+ * runs when there is no authenticated user. The subject token exchanged is the
25
+ * one `keycardAuth` verified for that same principal.
26
+ *
27
+ * Nothing here falls back to the agent's authority. A run without a user
28
+ * principal, a turn whose subject token was never retained, and an expired
29
+ * subject token all fail, each with its own reason: `principal_required`,
30
+ * `subject_token_unavailable`, and `subject_token_expired`. The last one is
31
+ * the sign-in signal, decided by a decode-only expiry check so an already
32
+ * dead token never costs an exchange round trip.
33
+ */
34
+ export declare function onBehalfOf(options: KeycardConnectionOptions): NonInteractiveAuthorizationDefinition;
35
+ /**
36
+ * Connection auth that acts for a named user the agent holds no token for.
37
+ *
38
+ * Uses the zone's substitute-user exchange, authenticated by the application
39
+ * credential: no subject token is involved, so this is the pattern for
40
+ * back-office and batch work rather than for a user's own request.
41
+ *
42
+ * The principal type follows the identifier. A function needs the turn's
43
+ * current user, so the connection is user-scoped and inherits eve's
44
+ * `principal_required` rejection; a fixed identifier needs no caller, so the
45
+ * connection is app-scoped and runs on schedules.
46
+ */
47
+ export declare function impersonate(options: KeycardImpersonateOptions): NonInteractiveAuthorizationDefinition;
48
+ //# sourceMappingURL=connections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,mBAAmB,EACnB,qCAAqC,EAEtC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAsC,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAKhG,uCAAuC;AACvC,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACzE;;;OAGG;IACH,cAAc,EAAE,MAAM,GAAG,CAAC,CAAC,SAAS,EAAE,mBAAmB,KAAK,MAAM,CAAC,CAAC;CACvE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,wBAAwB,GAChC,qCAAqC,CAmBvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,wBAAwB,GAChC,qCAAqC,CAmDvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,yBAAyB,GACjC,qCAAqC,CAuCvC"}
@@ -0,0 +1,167 @@
1
+ import { AuthProviderConfigurationError, TokenType, } from "@keycardai/oauth";
2
+ import { expiresAt, resolveConnectionConfig } from "./config.js";
3
+ import { AuthorizationFailedError, FailureReason } from "./errors.js";
4
+ import { subjectTokenExpired } from "./expiry.js";
5
+ import { principalKey, readSubjectToken } from "./subjectTokens.js";
6
+ /**
7
+ * Connection auth that runs client credentials under the agent's own identity.
8
+ *
9
+ * App-scoped: eve resolves `{ type: "app" }` and never asks the session for a
10
+ * user, so this works on schedules and subagent turns. No exchange and no
11
+ * impersonation, so nothing about the caller reaches the zone.
12
+ */
13
+ export function asSelf(options) {
14
+ const config = resolveConnectionConfig(options, "asSelf");
15
+ return {
16
+ principalType: "app",
17
+ displayName: config.connectionName,
18
+ async getToken() {
19
+ const request = {
20
+ resource: config.resource,
21
+ ...(config.scope ? { scope: config.scope } : {}),
22
+ ...(await config.clientAuthFields()),
23
+ };
24
+ return tokenResult(await acquire(config.connectionName, () => config.zoneClient().clientCredentialsGrant(request)));
25
+ },
26
+ };
27
+ }
28
+ /**
29
+ * Connection auth that exchanges the caller's token for a resource token.
30
+ *
31
+ * User-scoped, so eve resolves the principal from the active turn's
32
+ * `ctx.session.auth.current` and fails with `principal_required` before this
33
+ * runs when there is no authenticated user. The subject token exchanged is the
34
+ * one `keycardAuth` verified for that same principal.
35
+ *
36
+ * Nothing here falls back to the agent's authority. A run without a user
37
+ * principal, a turn whose subject token was never retained, and an expired
38
+ * subject token all fail, each with its own reason: `principal_required`,
39
+ * `subject_token_unavailable`, and `subject_token_expired`. The last one is
40
+ * the sign-in signal, decided by a decode-only expiry check so an already
41
+ * dead token never costs an exchange round trip.
42
+ */
43
+ export function onBehalfOf(options) {
44
+ const config = resolveConnectionConfig(options, "onBehalfOf");
45
+ return {
46
+ principalType: "user",
47
+ displayName: config.connectionName,
48
+ async getToken({ principal }) {
49
+ requireUser(principal, config.connectionName);
50
+ const subjectToken = readSubjectToken(principal, config.subjectTokens);
51
+ if (!subjectToken) {
52
+ throw new AuthorizationFailedError(config.connectionName, {
53
+ message: "No Keycard subject token is retained for this turn's principal. Add " +
54
+ "keycardAuth() to the channel's auth array, or use retainSubjectToken: " +
55
+ '"attributes" when connections run outside the process that authenticated ' +
56
+ "the request.",
57
+ reason: FailureReason.SUBJECT_TOKEN_UNAVAILABLE,
58
+ retryable: false,
59
+ });
60
+ }
61
+ if (subjectTokenExpired(subjectToken)) {
62
+ config.subjectTokens.delete(principalKey(principal));
63
+ throw new AuthorizationFailedError(config.connectionName, {
64
+ message: "The Keycard subject token for this turn has expired. Sign in again to continue.",
65
+ reason: FailureReason.SUBJECT_TOKEN_EXPIRED,
66
+ retryable: false,
67
+ });
68
+ }
69
+ let request;
70
+ if (config.credential) {
71
+ request = await config.credential.prepareTokenExchangeRequest(subjectToken, config.resource);
72
+ }
73
+ else {
74
+ request = {
75
+ subjectToken,
76
+ resource: config.resource,
77
+ subjectTokenType: TokenType.ACCESS_TOKEN,
78
+ };
79
+ }
80
+ if (config.scope)
81
+ request = { ...request, scope: config.scope };
82
+ return tokenResult(await acquire(config.connectionName, () => config.zoneClient().exchangeToken(request)));
83
+ },
84
+ };
85
+ }
86
+ /**
87
+ * Connection auth that acts for a named user the agent holds no token for.
88
+ *
89
+ * Uses the zone's substitute-user exchange, authenticated by the application
90
+ * credential: no subject token is involved, so this is the pattern for
91
+ * back-office and batch work rather than for a user's own request.
92
+ *
93
+ * The principal type follows the identifier. A function needs the turn's
94
+ * current user, so the connection is user-scoped and inherits eve's
95
+ * `principal_required` rejection; a fixed identifier needs no caller, so the
96
+ * connection is app-scoped and runs on schedules.
97
+ */
98
+ export function impersonate(options) {
99
+ const config = resolveConnectionConfig(options, "impersonate");
100
+ const identifier = options.userIdentifier;
101
+ if (typeof identifier === "string" && !identifier.trim()) {
102
+ throw new AuthProviderConfigurationError("impersonate requires a non-empty user identifier");
103
+ }
104
+ return {
105
+ principalType: typeof identifier === "function" ? "user" : "app",
106
+ displayName: config.connectionName,
107
+ async getToken({ principal }) {
108
+ let userIdentifier;
109
+ if (typeof identifier === "function") {
110
+ requireUser(principal, config.connectionName);
111
+ userIdentifier = identifier(principal);
112
+ }
113
+ else {
114
+ userIdentifier = identifier;
115
+ }
116
+ if (!userIdentifier || !userIdentifier.trim()) {
117
+ throw new AuthorizationFailedError(config.connectionName, {
118
+ message: "impersonate resolved an empty user identifier for this turn.",
119
+ reason: FailureReason.PRINCIPAL_REQUIRED,
120
+ retryable: false,
121
+ });
122
+ }
123
+ return tokenResult(await acquire(config.connectionName, () => config.zoneClient().impersonate({
124
+ userIdentifier,
125
+ resource: config.resource,
126
+ ...(config.scope ? { scope: config.scope } : {}),
127
+ })));
128
+ },
129
+ };
130
+ }
131
+ /**
132
+ * eve rejects a user-scoped connection with no current user before `getToken`
133
+ * runs. This repeats the check with eve's own reason so a factory driven
134
+ * directly, or resolved under an app principal, fails the same way instead of
135
+ * acquiring under the agent's authority.
136
+ */
137
+ function requireUser(principal, connectionName) {
138
+ if (principal.type === "user")
139
+ return;
140
+ throw new AuthorizationFailedError(connectionName, {
141
+ message: "This connection acts for a user, and the current turn has no authenticated " +
142
+ "user principal.",
143
+ reason: FailureReason.PRINCIPAL_REQUIRED,
144
+ retryable: false,
145
+ });
146
+ }
147
+ /** Wraps a zone failure as an eve authorization failure for this connection. */
148
+ async function acquire(connectionName, request) {
149
+ try {
150
+ return await request();
151
+ }
152
+ catch (cause) {
153
+ throw new AuthorizationFailedError(connectionName, {
154
+ message: cause instanceof Error ? cause.message : "Token acquisition failed",
155
+ reason: FailureReason.ACQUISITION_FAILED,
156
+ retryable: false,
157
+ });
158
+ }
159
+ }
160
+ function tokenResult(response) {
161
+ const expiry = expiresAt(response.expiresIn);
162
+ return {
163
+ token: response.accessToken,
164
+ ...(expiry !== undefined ? { expiresAt: expiry } : {}),
165
+ };
166
+ }
167
+ //# sourceMappingURL=connections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../src/connections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Errors this package raises into eve's own error channels.
3
+ *
4
+ * eve narrows connection authorization errors by `error.name` rather than by
5
+ * `instanceof` (see `isConnectionAuthorizationRequiredError` in
6
+ * `eve/connections`), and its `routeAuth` walk recognizes a rejection by the
7
+ * `response` property carrying a `Response`. Both contracts are structural, so
8
+ * this package satisfies them without importing eve at runtime: nothing here
9
+ * loads eve code, which is what keeps the package usable from a Node 22
10
+ * toolchain even though eve itself requires Node 24.
11
+ */
12
+ /**
13
+ * Signals that the user must complete an authorization flow.
14
+ *
15
+ * Thrown from an interactive connection's `getToken`. eve emits
16
+ * `authorization.required`, runs `startAuthorization`, and durably parks the
17
+ * turn on its own callback webhook.
18
+ */
19
+ export declare class AuthorizationRequiredError extends Error {
20
+ readonly connectionName: string;
21
+ constructor(connectionName: string, options?: {
22
+ message?: string;
23
+ });
24
+ }
25
+ /**
26
+ * Signals that authorization failed.
27
+ *
28
+ * `reason` is the stable machine-readable code eve surfaces on the
29
+ * `authorization.completed` event and on the failed tool result. `retryable`
30
+ * is `false` for the cases a fresh consent page cannot fix, so eve stops
31
+ * re-prompting: a run with no user principal, an expired subject token, or a
32
+ * denied grant.
33
+ */
34
+ export declare class AuthorizationFailedError extends Error {
35
+ readonly connectionName: string;
36
+ readonly reason?: string;
37
+ readonly retryable: boolean;
38
+ constructor(connectionName: string, options?: {
39
+ message?: string;
40
+ reason?: string;
41
+ retryable?: boolean;
42
+ });
43
+ }
44
+ /** Reasons {@link AuthorizationFailedError} carries out of this package. */
45
+ export declare const FailureReason: Readonly<{
46
+ /**
47
+ * eve's own reason for a user-scoped connection running without an
48
+ * authenticated user. Raised here too, so a factory used outside eve's
49
+ * principal resolution fails the same way instead of falling back to the
50
+ * agent's authority.
51
+ */
52
+ readonly PRINCIPAL_REQUIRED: "principal_required";
53
+ /** The retained subject token is a JWT whose `exp` has passed. */
54
+ readonly SUBJECT_TOKEN_EXPIRED: "subject_token_expired";
55
+ /** No subject token was retained for the principal of this turn. */
56
+ readonly SUBJECT_TOKEN_UNAVAILABLE: "subject_token_unavailable";
57
+ /** The zone refused to issue a token for the connection's resource. */
58
+ readonly ACQUISITION_FAILED: "acquisition_failed";
59
+ /** The user denied consent, or the provider returned an OAuth error. */
60
+ readonly ACCESS_DENIED: "access_denied";
61
+ /** The callback did not carry the state journaled at the begin step. */
62
+ readonly INVALID_CALLBACK: "invalid_callback";
63
+ }>;
64
+ /**
65
+ * Rejects a route in eve's ordered auth walk with a structured 401.
66
+ *
67
+ * `routeAuth` returns the `response` of a thrown error that carries one, so
68
+ * the walk stops here instead of continuing to a later, more permissive entry.
69
+ */
70
+ export declare class RouteRejectedError extends Error {
71
+ readonly response: Response;
72
+ constructor(options?: {
73
+ message?: string;
74
+ code?: string;
75
+ error?: string;
76
+ });
77
+ }
78
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH;;;;;;GAMG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,cAAc,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;CAKnE;AAED;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAG1B,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE;CAQvE;AAED,4EAA4E;AAC5E,eAAO,MAAM,aAAa;IACxB;;;;;OAKG;;IAEH,kEAAkE;;IAElE,oEAAoE;;IAEpE,uEAAuE;;IAEvE,wEAAwE;;IAExE,wEAAwE;;EAE/D,CAAC;AAEZ;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAEhB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;CAkB1E"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Errors this package raises into eve's own error channels.
3
+ *
4
+ * eve narrows connection authorization errors by `error.name` rather than by
5
+ * `instanceof` (see `isConnectionAuthorizationRequiredError` in
6
+ * `eve/connections`), and its `routeAuth` walk recognizes a rejection by the
7
+ * `response` property carrying a `Response`. Both contracts are structural, so
8
+ * this package satisfies them without importing eve at runtime: nothing here
9
+ * loads eve code, which is what keeps the package usable from a Node 22
10
+ * toolchain even though eve itself requires Node 24.
11
+ */
12
+ /** eve's name for the authorization-required error. */
13
+ const AUTHORIZATION_REQUIRED_NAME = "ConnectionAuthorizationRequiredError";
14
+ /** eve's name for the authorization-failed error. */
15
+ const AUTHORIZATION_FAILED_NAME = "ConnectionAuthorizationFailedError";
16
+ /** eve's name for a route rejection carrying its own 401 response. */
17
+ const UNAUTHENTICATED_NAME = "UnauthenticatedError";
18
+ /**
19
+ * Signals that the user must complete an authorization flow.
20
+ *
21
+ * Thrown from an interactive connection's `getToken`. eve emits
22
+ * `authorization.required`, runs `startAuthorization`, and durably parks the
23
+ * turn on its own callback webhook.
24
+ */
25
+ export class AuthorizationRequiredError extends Error {
26
+ constructor(connectionName, options) {
27
+ super(options?.message ?? `Connection "${connectionName}" requires authorization.`);
28
+ this.name = AUTHORIZATION_REQUIRED_NAME;
29
+ this.connectionName = connectionName;
30
+ }
31
+ }
32
+ /**
33
+ * Signals that authorization failed.
34
+ *
35
+ * `reason` is the stable machine-readable code eve surfaces on the
36
+ * `authorization.completed` event and on the failed tool result. `retryable`
37
+ * is `false` for the cases a fresh consent page cannot fix, so eve stops
38
+ * re-prompting: a run with no user principal, an expired subject token, or a
39
+ * denied grant.
40
+ */
41
+ export class AuthorizationFailedError extends Error {
42
+ constructor(connectionName, options) {
43
+ super(options?.message ?? `Connection "${connectionName}" authorization failed.`);
44
+ this.name = AUTHORIZATION_FAILED_NAME;
45
+ this.connectionName = connectionName;
46
+ this.reason = options?.reason;
47
+ this.retryable = options?.retryable ?? true;
48
+ }
49
+ }
50
+ /** Reasons {@link AuthorizationFailedError} carries out of this package. */
51
+ export const FailureReason = Object.freeze({
52
+ /**
53
+ * eve's own reason for a user-scoped connection running without an
54
+ * authenticated user. Raised here too, so a factory used outside eve's
55
+ * principal resolution fails the same way instead of falling back to the
56
+ * agent's authority.
57
+ */
58
+ PRINCIPAL_REQUIRED: "principal_required",
59
+ /** The retained subject token is a JWT whose `exp` has passed. */
60
+ SUBJECT_TOKEN_EXPIRED: "subject_token_expired",
61
+ /** No subject token was retained for the principal of this turn. */
62
+ SUBJECT_TOKEN_UNAVAILABLE: "subject_token_unavailable",
63
+ /** The zone refused to issue a token for the connection's resource. */
64
+ ACQUISITION_FAILED: "acquisition_failed",
65
+ /** The user denied consent, or the provider returned an OAuth error. */
66
+ ACCESS_DENIED: "access_denied",
67
+ /** The callback did not carry the state journaled at the begin step. */
68
+ INVALID_CALLBACK: "invalid_callback",
69
+ });
70
+ /**
71
+ * Rejects a route in eve's ordered auth walk with a structured 401.
72
+ *
73
+ * `routeAuth` returns the `response` of a thrown error that carries one, so
74
+ * the walk stops here instead of continuing to a later, more permissive entry.
75
+ */
76
+ export class RouteRejectedError extends Error {
77
+ constructor(options) {
78
+ super(options?.message ?? "Authorization is required for this route.");
79
+ this.name = UNAUTHENTICATED_NAME;
80
+ const challenge = options?.error
81
+ ? `Bearer error="${options.error}"`
82
+ : "Bearer";
83
+ this.response = Response.json({
84
+ code: options?.code ?? "unauthorized",
85
+ error: options?.message ?? "Authorization is required for this route.",
86
+ ok: false,
87
+ }, {
88
+ status: 401,
89
+ headers: { "cache-control": "no-store", "www-authenticate": challenge },
90
+ });
91
+ }
92
+ }
93
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,uDAAuD;AACvD,MAAM,2BAA2B,GAAG,sCAAsC,CAAC;AAC3E,qDAAqD;AACrD,MAAM,yBAAyB,GAAG,oCAAoC,CAAC;AACvE,sEAAsE;AACtE,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAGnD,YAAY,cAAsB,EAAE,OAA8B;QAChE,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,eAAe,cAAc,2BAA2B,CAAC,CAAC;QACpF,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAKjD,YACE,cAAsB,EACtB,OAAoE;QAEpE,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,eAAe,cAAc,yBAAyB,CAAC,CAAC;QAClF,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC;IAC9C,CAAC;CACF;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC;;;;;OAKG;IACH,kBAAkB,EAAE,oBAAoB;IACxC,kEAAkE;IAClE,qBAAqB,EAAE,uBAAuB;IAC9C,oEAAoE;IACpE,yBAAyB,EAAE,2BAA2B;IACtD,uEAAuE;IACvE,kBAAkB,EAAE,oBAAoB;IACxC,wEAAwE;IACxE,aAAa,EAAE,eAAe;IAC9B,wEAAwE;IACxE,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAG3C,YAAY,OAA6D;QACvE,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,2CAA2C,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,MAAM,SAAS,GAAG,OAAO,EAAE,KAAK;YAC9B,CAAC,CAAC,iBAAiB,OAAO,CAAC,KAAK,GAAG;YACnC,CAAC,CAAC,QAAQ,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAC3B;YACE,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,cAAc;YACrC,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,2CAA2C;YACtE,EAAE,EAAE,KAAK;SACV,EACD;YACE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE,kBAAkB,EAAE,SAAS,EAAE;SACxE,CACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Whether a JWT subject token is already expired.
3
+ *
4
+ * Decode-only, no signature verification: the zone remains the authority on
5
+ * validity. This check exists to route an expiry to a channel sign-in instead
6
+ * of a consent page that cannot fix it, and to skip an exchange round trip
7
+ * that is guaranteed to fail. Opaque or malformed tokens, and tokens with no
8
+ * `exp`, return false and are left for the zone to judge.
9
+ */
10
+ export declare function subjectTokenExpired(token: string): boolean;
11
+ /**
12
+ * The unverified claims of a JWT, or null when the value is not a JWT.
13
+ *
14
+ * Used for the expiry check above and for the issuer peek that decides whether
15
+ * an inbound bearer is a caller this package recognizes. Never a substitute
16
+ * for verification: every claim a decision depends on is re-read from the
17
+ * verified claims.
18
+ */
19
+ export declare function decodeClaims(token: string): Record<string, unknown> | null;
20
+ //# sourceMappingURL=expiry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiry.d.ts","sourceRoot":"","sources":["../../src/expiry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAa1E"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Whether a JWT subject token is already expired.
3
+ *
4
+ * Decode-only, no signature verification: the zone remains the authority on
5
+ * validity. This check exists to route an expiry to a channel sign-in instead
6
+ * of a consent page that cannot fix it, and to skip an exchange round trip
7
+ * that is guaranteed to fail. Opaque or malformed tokens, and tokens with no
8
+ * `exp`, return false and are left for the zone to judge.
9
+ */
10
+ export function subjectTokenExpired(token) {
11
+ const claims = decodeClaims(token);
12
+ if (claims === null)
13
+ return false;
14
+ const exp = claims.exp;
15
+ return typeof exp === "number" && Number.isFinite(exp) && exp <= Date.now() / 1000;
16
+ }
17
+ /**
18
+ * The unverified claims of a JWT, or null when the value is not a JWT.
19
+ *
20
+ * Used for the expiry check above and for the issuer peek that decides whether
21
+ * an inbound bearer is a caller this package recognizes. Never a substitute
22
+ * for verification: every claim a decision depends on is re-read from the
23
+ * verified claims.
24
+ */
25
+ export function decodeClaims(token) {
26
+ const parts = token.split(".");
27
+ if (parts.length !== 3)
28
+ return null;
29
+ let payload;
30
+ try {
31
+ payload = JSON.parse(decodeSegment(parts[1]));
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
37
+ return null;
38
+ }
39
+ return payload;
40
+ }
41
+ /** Decode one base64url JWT segment to its UTF-8 text. */
42
+ function decodeSegment(segment) {
43
+ const base64 = segment.replace(/-/g, "+").replace(/_/g, "/");
44
+ const padded = base64 + "=".repeat((4 - (base64.length % 4)) % 4);
45
+ const binary = atob(padded);
46
+ const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
47
+ return new TextDecoder().decode(bytes);
48
+ }
49
+ //# sourceMappingURL=expiry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiry.js","sourceRoot":"","sources":["../../src/expiry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IACvB,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACrF,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,OAAkC,CAAC;AAC5C,CAAC;AAED,0DAA0D;AAC1D,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Keycard auth for eve agents.
3
+ *
4
+ * Three adapters, each plugging into an eve primitive rather than wrapping it:
5
+ *
6
+ * - {@link keycardAuth} is an `AuthFn` for a channel's ordered `auth` array.
7
+ * It verifies a zone-issued bearer and projects the claims onto eve's
8
+ * `SessionAuthContext`.
9
+ * - {@link Keycard.asSelf}, {@link Keycard.onBehalfOf}, and
10
+ * {@link Keycard.impersonate} are connection auth definitions: eve resolves
11
+ * the principal from the turn, calls `getToken` at the tool boundary, and
12
+ * attaches the bearer itself, so no credential reaches the model.
13
+ * - {@link Keycard.interactive} is the interactive form. eve emits
14
+ * `authorization.required`, parks the turn durably on its own callback, and
15
+ * settles it once.
16
+ */
17
+ export { keycardAuth } from "./auth.js";
18
+ export type { KeycardAuthOptions, SubjectTokenRetention } from "./auth.js";
19
+ export { asSelf, impersonate, onBehalfOf } from "./connections.js";
20
+ export type { KeycardImpersonateOptions } from "./connections.js";
21
+ export { interactive, memoryAuthorizedTokenStore } from "./interactive.js";
22
+ export type { AuthorizedToken, AuthorizedTokenStore, KeycardInteractiveOptions, KeycardResumeState, WebAppFlow, } from "./interactive.js";
23
+ export type { KeycardConnectionOptions } from "./config.js";
24
+ export { AuthorizationFailedError, AuthorizationRequiredError, FailureReason, RouteRejectedError, } from "./errors.js";
25
+ export { decodeClaims, subjectTokenExpired } from "./expiry.js";
26
+ export { requireAuthOnUnauthorized } from "./requireAuth.js";
27
+ export type { RequireAuthContext } from "./requireAuth.js";
28
+ export { defaultSubjectTokenStore, memorySubjectTokenStore, SUBJECT_TOKEN_ATTRIBUTE, } from "./subjectTokens.js";
29
+ export type { SubjectTokenStore } from "./subjectTokens.js";
30
+ export { KeycardZoneClient } from "./zoneClient.js";
31
+ export type { ZoneClient } from "./zoneClient.js";
32
+ import { asSelf, impersonate, onBehalfOf } from "./connections.js";
33
+ import { interactive } from "./interactive.js";
34
+ /**
35
+ * The connection auth factories, grouped for the common
36
+ * `auth: Keycard.onBehalfOf({ ... })` call site.
37
+ */
38
+ export declare const Keycard: Readonly<{
39
+ asSelf: typeof asSelf;
40
+ impersonate: typeof impersonate;
41
+ interactive: typeof interactive;
42
+ onBehalfOf: typeof onBehalfOf;
43
+ }>;
44
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAE3E,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC3E,YAAY,EACV,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,kBAAkB,EAClB,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,OAAO;;;;;EAKlB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Keycard auth for eve agents.
3
+ *
4
+ * Three adapters, each plugging into an eve primitive rather than wrapping it:
5
+ *
6
+ * - {@link keycardAuth} is an `AuthFn` for a channel's ordered `auth` array.
7
+ * It verifies a zone-issued bearer and projects the claims onto eve's
8
+ * `SessionAuthContext`.
9
+ * - {@link Keycard.asSelf}, {@link Keycard.onBehalfOf}, and
10
+ * {@link Keycard.impersonate} are connection auth definitions: eve resolves
11
+ * the principal from the turn, calls `getToken` at the tool boundary, and
12
+ * attaches the bearer itself, so no credential reaches the model.
13
+ * - {@link Keycard.interactive} is the interactive form. eve emits
14
+ * `authorization.required`, parks the turn durably on its own callback, and
15
+ * settles it once.
16
+ */
17
+ export { keycardAuth } from "./auth.js";
18
+ export { asSelf, impersonate, onBehalfOf } from "./connections.js";
19
+ export { interactive, memoryAuthorizedTokenStore } from "./interactive.js";
20
+ export { AuthorizationFailedError, AuthorizationRequiredError, FailureReason, RouteRejectedError, } from "./errors.js";
21
+ export { decodeClaims, subjectTokenExpired } from "./expiry.js";
22
+ export { requireAuthOnUnauthorized } from "./requireAuth.js";
23
+ export { defaultSubjectTokenStore, memorySubjectTokenStore, SUBJECT_TOKEN_ATTRIBUTE, } from "./subjectTokens.js";
24
+ export { KeycardZoneClient } from "./zoneClient.js";
25
+ import { asSelf, impersonate, onBehalfOf } from "./connections.js";
26
+ import { interactive } from "./interactive.js";
27
+ /**
28
+ * The connection auth factories, grouped for the common
29
+ * `auth: Keycard.onBehalfOf({ ... })` call site.
30
+ */
31
+ export const Keycard = Object.freeze({
32
+ asSelf,
33
+ impersonate,
34
+ interactive,
35
+ onBehalfOf,
36
+ });
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAW3E,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EACL,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,MAAM;IACN,WAAW;IACX,WAAW;IACX,UAAU;CACX,CAAC,CAAC"}