@lunora/cloudflare-access 1.0.0-alpha.24 → 1.0.0-alpha.26

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/admin.d.mts CHANGED
@@ -1,36 +1,36 @@
1
- import { A as AccessClaims, R as RequestVerifyOptions } from "./packem_shared/types.d-BO8d74KI.mjs";
1
+ import { A as AccessClaims, R as RequestVerifyOptions } from "./packem_shared/types.d-C8c7Qwx1.mjs";
2
2
  import 'jose';
3
3
  /** Options for {@link accessAdminGate}; extends {@link RequestVerifyOptions}. */
4
4
  interface AccessAdminGateOptions extends RequestVerifyOptions {
5
5
  /**
6
- * Decide whether the **verified** claims authorize the Studio/admin plane —
7
- * e.g. `(claims) => claims.groups?.includes("ops") ?? false` or an email-domain
8
- * check. Required: there is no implicit grant, so a verified-but-unprivileged
9
- * identity is denied. Runs only after signature/issuer/audience/expiry pass.
10
- */
6
+ * Decide whether the **verified** claims authorize the Studio/admin plane —
7
+ * e.g. `(claims) => claims.groups?.includes("ops") ?? false` or an email-domain
8
+ * check. Required: there is no implicit grant, so a verified-but-unprivileged
9
+ * identity is denied. Runs only after signature/issuer/audience/expiry pass.
10
+ */
11
11
  isAdmin: (claims: AccessClaims) => boolean | Promise<boolean>;
12
12
  }
13
13
  /**
14
- * Build an admin gate for `@lunora/runtime`'s `WorkerOptions.adminGate`: a
15
- * request-only predicate that verifies the request's `Cf-Access-Jwt-Assertion`
16
- * JWT and applies your `isAdmin(claims)` test. When it resolves `true` the
17
- * request authorizes the `/_lunora/admin/*` plane (the Studio's HTTP + WS
18
- * endpoints) in addition to — or instead of — the static admin bearer, so the
19
- * Studio can sit behind Cloudflare Access.
20
- *
21
- * It is **fail-closed**: a missing token, a token that fails verification, or an
22
- * `isAdmin` that returns `false` all resolve to `false` (the bearer remains the
23
- * only other path). Verification needs no `env` binding (static team-domain/aud
24
- * config + the remote JWKS over `fetch`), so the gate takes only the request and
25
- * the runtime can evaluate it without threading async through every admin route.
26
- *
27
- * ```ts
28
- * options.adminGate = accessAdminGate({
29
- * teamDomain: env.CF_ACCESS_TEAM_DOMAIN,
30
- * aud: env.CF_ACCESS_ADMIN_AUD,
31
- * isAdmin: (claims) => claims.groups?.includes("lunora-admins") ?? false,
32
- * });
33
- * ```
34
- */
14
+ * Build an admin gate for `@lunora/runtime`'s `WorkerOptions.adminGate`: a
15
+ * request-only predicate that verifies the request's `Cf-Access-Jwt-Assertion`
16
+ * JWT and applies your `isAdmin(claims)` test. When it resolves `true` the
17
+ * request authorizes the `/_lunora/admin/*` plane (the Studio's HTTP + WS
18
+ * endpoints) in addition to — or instead of — the static admin bearer, so the
19
+ * Studio can sit behind Cloudflare Access.
20
+ *
21
+ * It is **fail-closed**: a missing token, a token that fails verification, or an
22
+ * `isAdmin` that returns `false` all resolve to `false` (the bearer remains the
23
+ * only other path). Verification needs no `env` binding (static team-domain/aud
24
+ * config + the remote JWKS over `fetch`), so the gate takes only the request and
25
+ * the runtime can evaluate it without threading async through every admin route.
26
+ *
27
+ * ```ts
28
+ * options.adminGate = accessAdminGate({
29
+ * teamDomain: env.CF_ACCESS_TEAM_DOMAIN,
30
+ * aud: env.CF_ACCESS_ADMIN_AUD,
31
+ * isAdmin: (claims) => claims.groups?.includes("lunora-admins") ?? false,
32
+ * });
33
+ * ```
34
+ */
35
35
  declare const accessAdminGate: (options: AccessAdminGateOptions) => ((request: Request) => Promise<boolean>);
36
36
  export { type AccessAdminGateOptions, accessAdminGate };
package/dist/admin.d.ts CHANGED
@@ -1,36 +1,36 @@
1
- import { A as AccessClaims, R as RequestVerifyOptions } from "./packem_shared/types.d-BO8d74KI.js";
1
+ import { A as AccessClaims, R as RequestVerifyOptions } from "./packem_shared/types.d-C8c7Qwx1.js";
2
2
  import 'jose';
3
3
  /** Options for {@link accessAdminGate}; extends {@link RequestVerifyOptions}. */
4
4
  interface AccessAdminGateOptions extends RequestVerifyOptions {
5
5
  /**
6
- * Decide whether the **verified** claims authorize the Studio/admin plane —
7
- * e.g. `(claims) => claims.groups?.includes("ops") ?? false` or an email-domain
8
- * check. Required: there is no implicit grant, so a verified-but-unprivileged
9
- * identity is denied. Runs only after signature/issuer/audience/expiry pass.
10
- */
6
+ * Decide whether the **verified** claims authorize the Studio/admin plane —
7
+ * e.g. `(claims) => claims.groups?.includes("ops") ?? false` or an email-domain
8
+ * check. Required: there is no implicit grant, so a verified-but-unprivileged
9
+ * identity is denied. Runs only after signature/issuer/audience/expiry pass.
10
+ */
11
11
  isAdmin: (claims: AccessClaims) => boolean | Promise<boolean>;
12
12
  }
13
13
  /**
14
- * Build an admin gate for `@lunora/runtime`'s `WorkerOptions.adminGate`: a
15
- * request-only predicate that verifies the request's `Cf-Access-Jwt-Assertion`
16
- * JWT and applies your `isAdmin(claims)` test. When it resolves `true` the
17
- * request authorizes the `/_lunora/admin/*` plane (the Studio's HTTP + WS
18
- * endpoints) in addition to — or instead of — the static admin bearer, so the
19
- * Studio can sit behind Cloudflare Access.
20
- *
21
- * It is **fail-closed**: a missing token, a token that fails verification, or an
22
- * `isAdmin` that returns `false` all resolve to `false` (the bearer remains the
23
- * only other path). Verification needs no `env` binding (static team-domain/aud
24
- * config + the remote JWKS over `fetch`), so the gate takes only the request and
25
- * the runtime can evaluate it without threading async through every admin route.
26
- *
27
- * ```ts
28
- * options.adminGate = accessAdminGate({
29
- * teamDomain: env.CF_ACCESS_TEAM_DOMAIN,
30
- * aud: env.CF_ACCESS_ADMIN_AUD,
31
- * isAdmin: (claims) => claims.groups?.includes("lunora-admins") ?? false,
32
- * });
33
- * ```
34
- */
14
+ * Build an admin gate for `@lunora/runtime`'s `WorkerOptions.adminGate`: a
15
+ * request-only predicate that verifies the request's `Cf-Access-Jwt-Assertion`
16
+ * JWT and applies your `isAdmin(claims)` test. When it resolves `true` the
17
+ * request authorizes the `/_lunora/admin/*` plane (the Studio's HTTP + WS
18
+ * endpoints) in addition to — or instead of — the static admin bearer, so the
19
+ * Studio can sit behind Cloudflare Access.
20
+ *
21
+ * It is **fail-closed**: a missing token, a token that fails verification, or an
22
+ * `isAdmin` that returns `false` all resolve to `false` (the bearer remains the
23
+ * only other path). Verification needs no `env` binding (static team-domain/aud
24
+ * config + the remote JWKS over `fetch`), so the gate takes only the request and
25
+ * the runtime can evaluate it without threading async through every admin route.
26
+ *
27
+ * ```ts
28
+ * options.adminGate = accessAdminGate({
29
+ * teamDomain: env.CF_ACCESS_TEAM_DOMAIN,
30
+ * aud: env.CF_ACCESS_ADMIN_AUD,
31
+ * isAdmin: (claims) => claims.groups?.includes("lunora-admins") ?? false,
32
+ * });
33
+ * ```
34
+ */
35
35
  declare const accessAdminGate: (options: AccessAdminGateOptions) => ((request: Request) => Promise<boolean>);
36
36
  export { type AccessAdminGateOptions, accessAdminGate };
@@ -1,14 +1,14 @@
1
- import { M as Middleware } from "./packem_shared/index.d-ByAnpUzP.mjs";
2
- import { A as AccessClaims } from "./packem_shared/types.d-BO8d74KI.mjs";
1
+ import { M as Middleware } from "./packem_shared/index.d-5O8LZ3gE.mjs";
2
+ import { A as AccessClaims } from "./packem_shared/types.d-C8c7Qwx1.mjs";
3
3
  import '@lunora/errors';
4
4
  import 'jose';
5
5
  /**
6
- * The slice of context {@link accessContext} reads: the `auth` facade every
7
- * Lunora ctx carries. `getIdentity()` returns the verified identity envelope —
8
- * `createAccessResolver`'s {@link import("./types").ResolvedAccessIdentity}
9
- * output, which carries the full claim set under `access` plus the promoted
10
- * `email` / `groups` / `commonName` fields.
11
- */
6
+ * The slice of context {@link accessContext} reads: the `auth` facade every
7
+ * Lunora ctx carries. `getIdentity()` returns the verified identity envelope —
8
+ * `createAccessResolver`'s {@link import("./types").ResolvedAccessIdentity}
9
+ * output, which carries the full claim set under `access` plus the promoted
10
+ * `email` / `groups` / `commonName` fields.
11
+ */
12
12
  interface AccessContextInput {
13
13
  auth?: {
14
14
  getIdentity?: () => (Record<string, unknown> | null) | Promise<Record<string, unknown> | null>;
@@ -16,11 +16,11 @@ interface AccessContextInput {
16
16
  };
17
17
  }
18
18
  /**
19
- * The typed, per-request `ctx.access` facade {@link accessContext} attaches. A
20
- * synchronous, Access-shaped read over the already-resolved identity — so a
21
- * handler reads `ctx.access.email` / `ctx.access.hasGroup("ops")` without an
22
- * `await` or a cast off the generic `ctx.auth.getIdentity()` envelope.
23
- */
19
+ * The typed, per-request `ctx.access` facade {@link accessContext} attaches. A
20
+ * synchronous, Access-shaped read over the already-resolved identity — so a
21
+ * handler reads `ctx.access.email` / `ctx.access.hasGroup("ops")` without an
22
+ * `await` or a cast off the generic `ctx.auth.getIdentity()` envelope.
23
+ */
24
24
  interface AccessFacade {
25
25
  /** True when a verified Access identity is present on the request. */
26
26
  readonly authenticated: boolean;
@@ -42,39 +42,39 @@ interface AccessContextOutput extends AccessContextInput {
42
42
  access: AccessFacade;
43
43
  }
44
44
  /**
45
- * Build the `ctx.access` facade from a (possibly absent) resolved identity
46
- * envelope. Returns the anonymous facade when no identity is present, so callers
47
- * never null-check. Shared by {@link accessContext} and the codegen-wired global
48
- * `ctx.access` (which calls this synchronously from the resolved identity locals
49
- * at ctx-build time, so a global `ctx.access` adds only this object construction
50
- * per request — no extra I/O or re-verification).
51
- */
45
+ * Build the `ctx.access` facade from a (possibly absent) resolved identity
46
+ * envelope. Returns the anonymous facade when no identity is present, so callers
47
+ * never null-check. Shared by {@link accessContext} and the codegen-wired global
48
+ * `ctx.access` (which calls this synchronously from the resolved identity locals
49
+ * at ctx-build time, so a global `ctx.access` adds only this object construction
50
+ * per request — no extra I/O or re-verification).
51
+ */
52
52
  declare const accessFacade: (identity: Record<string, unknown> | null | undefined, userId: string | null | undefined) => AccessFacade;
53
53
  /**
54
- * Middleware that attaches a typed `ctx.access` facade derived from the verified
55
- * Cloudflare Access identity. It resolves `ctx.auth.getIdentity()` once and
56
- * exposes a **synchronous**, Access-shaped read — `ctx.access.email`,
57
- * `ctx.access.groups`, `ctx.access.hasGroup("ops")`, `ctx.access.claims` — so a
58
- * handler reads the verified identity ergonomically and with full typing instead
59
- * of casting off the generic `getIdentity()` envelope.
60
- *
61
- * When no identity is resolved (anonymous request) it attaches the anonymous
62
- * facade — `authenticated: false`, empty `groups`, `hasGroup` always `false` —
63
- * so reads stay safe without a null check, and authorization decisions still
64
- * fail closed.
65
- *
66
- * It does not gate the request; pair it with `rls(...)` (or
67
- * `accessRoles(...)` → `rls(...)`) when you need enforcement. It only surfaces
68
- * the identity for branching inside a handler.
69
- *
70
- * ```ts
71
- * export const whoAmI = query
72
- * .use(accessContext())
73
- * .query(async ({ ctx }) => ({
74
- * email: ctx.access.email,
75
- * isOps: ctx.access.hasGroup("ops"),
76
- * }));
77
- * ```
78
- */
54
+ * Middleware that attaches a typed `ctx.access` facade derived from the verified
55
+ * Cloudflare Access identity. It resolves `ctx.auth.getIdentity()` once and
56
+ * exposes a **synchronous**, Access-shaped read — `ctx.access.email`,
57
+ * `ctx.access.groups`, `ctx.access.hasGroup("ops")`, `ctx.access.claims` — so a
58
+ * handler reads the verified identity ergonomically and with full typing instead
59
+ * of casting off the generic `getIdentity()` envelope.
60
+ *
61
+ * When no identity is resolved (anonymous request) it attaches the anonymous
62
+ * facade — `authenticated: false`, empty `groups`, `hasGroup` always `false` —
63
+ * so reads stay safe without a null check, and authorization decisions still
64
+ * fail closed.
65
+ *
66
+ * It does not gate the request; pair it with `rls(...)` (or
67
+ * `accessRoles(...)` → `rls(...)`) when you need enforcement. It only surfaces
68
+ * the identity for branching inside a handler.
69
+ *
70
+ * ```ts
71
+ * export const whoAmI = query
72
+ * .use(accessContext())
73
+ * .query(async ({ ctx }) => ({
74
+ * email: ctx.access.email,
75
+ * isOps: ctx.access.hasGroup("ops"),
76
+ * }));
77
+ * ```
78
+ */
79
79
  declare const accessContext: <Context extends AccessContextInput>() => Middleware<Context, AccessContextOutput & Context>;
80
80
  export { type AccessContextInput, type AccessContextOutput, type AccessFacade, accessContext, accessFacade };
package/dist/context.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { M as Middleware } from "./packem_shared/index.d-ByAnpUzP.js";
2
- import { A as AccessClaims } from "./packem_shared/types.d-BO8d74KI.js";
1
+ import { M as Middleware } from "./packem_shared/index.d-5O8LZ3gE.js";
2
+ import { A as AccessClaims } from "./packem_shared/types.d-C8c7Qwx1.js";
3
3
  import '@lunora/errors';
4
4
  import 'jose';
5
5
  /**
6
- * The slice of context {@link accessContext} reads: the `auth` facade every
7
- * Lunora ctx carries. `getIdentity()` returns the verified identity envelope —
8
- * `createAccessResolver`'s {@link import("./types").ResolvedAccessIdentity}
9
- * output, which carries the full claim set under `access` plus the promoted
10
- * `email` / `groups` / `commonName` fields.
11
- */
6
+ * The slice of context {@link accessContext} reads: the `auth` facade every
7
+ * Lunora ctx carries. `getIdentity()` returns the verified identity envelope —
8
+ * `createAccessResolver`'s {@link import("./types").ResolvedAccessIdentity}
9
+ * output, which carries the full claim set under `access` plus the promoted
10
+ * `email` / `groups` / `commonName` fields.
11
+ */
12
12
  interface AccessContextInput {
13
13
  auth?: {
14
14
  getIdentity?: () => (Record<string, unknown> | null) | Promise<Record<string, unknown> | null>;
@@ -16,11 +16,11 @@ interface AccessContextInput {
16
16
  };
17
17
  }
18
18
  /**
19
- * The typed, per-request `ctx.access` facade {@link accessContext} attaches. A
20
- * synchronous, Access-shaped read over the already-resolved identity — so a
21
- * handler reads `ctx.access.email` / `ctx.access.hasGroup("ops")` without an
22
- * `await` or a cast off the generic `ctx.auth.getIdentity()` envelope.
23
- */
19
+ * The typed, per-request `ctx.access` facade {@link accessContext} attaches. A
20
+ * synchronous, Access-shaped read over the already-resolved identity — so a
21
+ * handler reads `ctx.access.email` / `ctx.access.hasGroup("ops")` without an
22
+ * `await` or a cast off the generic `ctx.auth.getIdentity()` envelope.
23
+ */
24
24
  interface AccessFacade {
25
25
  /** True when a verified Access identity is present on the request. */
26
26
  readonly authenticated: boolean;
@@ -42,39 +42,39 @@ interface AccessContextOutput extends AccessContextInput {
42
42
  access: AccessFacade;
43
43
  }
44
44
  /**
45
- * Build the `ctx.access` facade from a (possibly absent) resolved identity
46
- * envelope. Returns the anonymous facade when no identity is present, so callers
47
- * never null-check. Shared by {@link accessContext} and the codegen-wired global
48
- * `ctx.access` (which calls this synchronously from the resolved identity locals
49
- * at ctx-build time, so a global `ctx.access` adds only this object construction
50
- * per request — no extra I/O or re-verification).
51
- */
45
+ * Build the `ctx.access` facade from a (possibly absent) resolved identity
46
+ * envelope. Returns the anonymous facade when no identity is present, so callers
47
+ * never null-check. Shared by {@link accessContext} and the codegen-wired global
48
+ * `ctx.access` (which calls this synchronously from the resolved identity locals
49
+ * at ctx-build time, so a global `ctx.access` adds only this object construction
50
+ * per request — no extra I/O or re-verification).
51
+ */
52
52
  declare const accessFacade: (identity: Record<string, unknown> | null | undefined, userId: string | null | undefined) => AccessFacade;
53
53
  /**
54
- * Middleware that attaches a typed `ctx.access` facade derived from the verified
55
- * Cloudflare Access identity. It resolves `ctx.auth.getIdentity()` once and
56
- * exposes a **synchronous**, Access-shaped read — `ctx.access.email`,
57
- * `ctx.access.groups`, `ctx.access.hasGroup("ops")`, `ctx.access.claims` — so a
58
- * handler reads the verified identity ergonomically and with full typing instead
59
- * of casting off the generic `getIdentity()` envelope.
60
- *
61
- * When no identity is resolved (anonymous request) it attaches the anonymous
62
- * facade — `authenticated: false`, empty `groups`, `hasGroup` always `false` —
63
- * so reads stay safe without a null check, and authorization decisions still
64
- * fail closed.
65
- *
66
- * It does not gate the request; pair it with `rls(...)` (or
67
- * `accessRoles(...)` → `rls(...)`) when you need enforcement. It only surfaces
68
- * the identity for branching inside a handler.
69
- *
70
- * ```ts
71
- * export const whoAmI = query
72
- * .use(accessContext())
73
- * .query(async ({ ctx }) => ({
74
- * email: ctx.access.email,
75
- * isOps: ctx.access.hasGroup("ops"),
76
- * }));
77
- * ```
78
- */
54
+ * Middleware that attaches a typed `ctx.access` facade derived from the verified
55
+ * Cloudflare Access identity. It resolves `ctx.auth.getIdentity()` once and
56
+ * exposes a **synchronous**, Access-shaped read — `ctx.access.email`,
57
+ * `ctx.access.groups`, `ctx.access.hasGroup("ops")`, `ctx.access.claims` — so a
58
+ * handler reads the verified identity ergonomically and with full typing instead
59
+ * of casting off the generic `getIdentity()` envelope.
60
+ *
61
+ * When no identity is resolved (anonymous request) it attaches the anonymous
62
+ * facade — `authenticated: false`, empty `groups`, `hasGroup` always `false` —
63
+ * so reads stay safe without a null check, and authorization decisions still
64
+ * fail closed.
65
+ *
66
+ * It does not gate the request; pair it with `rls(...)` (or
67
+ * `accessRoles(...)` → `rls(...)`) when you need enforcement. It only surfaces
68
+ * the identity for branching inside a handler.
69
+ *
70
+ * ```ts
71
+ * export const whoAmI = query
72
+ * .use(accessContext())
73
+ * .query(async ({ ctx }) => ({
74
+ * email: ctx.access.email,
75
+ * isOps: ctx.access.hasGroup("ops"),
76
+ * }));
77
+ * ```
78
+ */
79
79
  declare const accessContext: <Context extends AccessContextInput>() => Middleware<Context, AccessContextOutput & Context>;
80
80
  export { type AccessContextInput, type AccessContextOutput, type AccessFacade, accessContext, accessFacade };
package/dist/index.d.mts CHANGED
@@ -1,82 +1,58 @@
1
- import { a as ResolveIdentityFunction, C as CreateAccessResolverOptions, V as VerifyAccessJwtOptions, A as AccessClaims } from "./packem_shared/types.d-BO8d74KI.mjs";
2
- export type { b as AccessKeySet, c as ResolvedAccessIdentity, d as ResolvedIdentityLike } from "./packem_shared/types.d-BO8d74KI.mjs";
1
+ import { a as ResolveIdentityFunction, C as CreateAccessResolverOptions, V as VerifyAccessJwtOptions, A as AccessClaims } from "./packem_shared/types.d-C8c7Qwx1.mjs";
2
+ export type { b as AccessKeySet, c as ResolvedAccessIdentity, d as ResolvedIdentityLike } from "./packem_shared/types.d-C8c7Qwx1.mjs";
3
3
  import 'jose';
4
4
  /**
5
- * Create a `resolveIdentity` adapter for Cloudflare Access. The returned
6
- * function reads the Access JWT off the request, verifies it (`verifyAccessJwt`),
7
- * and maps the claims onto the identity shape `@lunora/runtime` expects — so a
8
- * verified Access user/service-token becomes `ctx.auth` for every
9
- * query/mutation/action (and feeds RLS) with no further wiring.
10
- *
11
- * Behaviour is **fail-closed → anonymous**: a missing token, or a token that
12
- * fails verification, resolves to `null` (the request proceeds unauthenticated
13
- * and RLS denies). Use {@link CreateAccessResolverOptions.onError} to observe
14
- * verification failures.
15
- *
16
- * Wire it in your worker entry:
17
- *
18
- * ```ts
19
- * options.resolveIdentity = createAccessResolver({
20
- * teamDomain: env.CF_ACCESS_TEAM_DOMAIN, // "acme" | "acme.cloudflareaccess.com"
21
- * aud: env.CF_ACCESS_AUD, // the Access app's AUD tag
22
- * });
23
- * ```
24
- */
5
+ * Create a `resolveIdentity` adapter for Cloudflare Access. The returned
6
+ * function reads the Access JWT off the request, verifies it (`verifyAccessJwt`),
7
+ * and maps the claims onto the identity shape `@lunora/runtime` expects — so a
8
+ * verified Access user/service-token becomes `ctx.auth` for every
9
+ * query/mutation/action (and feeds RLS) with no further wiring.
10
+ *
11
+ * Behaviour is **fail-closed → anonymous**: a missing token, or a token that
12
+ * fails verification, resolves to `null` (the request proceeds unauthenticated
13
+ * and RLS denies). Use {@link CreateAccessResolverOptions.onError} to observe
14
+ * verification failures.
15
+ *
16
+ * Wire it in your worker entry:
17
+ *
18
+ * ```ts
19
+ * options.resolveIdentity = createAccessResolver({
20
+ * teamDomain: env.CF_ACCESS_TEAM_DOMAIN, // "acme" | "acme.cloudflareaccess.com"
21
+ * aud: env.CF_ACCESS_AUD, // the Access app's AUD tag
22
+ * });
23
+ * ```
24
+ */
25
25
  declare const createAccessResolver: (options: CreateAccessResolverOptions) => ResolveIdentityFunction;
26
26
  /**
27
- * Compose several `resolveIdentity` adapters into one: each is tried in order
28
- * and the first to return a non-null identity wins. The canonical use is
29
- * pairing Access with `@lunora/auth` —
30
- * `composeResolvers(accessResolver, betterAuthResolver)` — so a request carrying
31
- * an Access JWT (machine/SSO) is authenticated by Access while everyone else
32
- * falls through to the app's own session.
33
- */
27
+ * Compose several `resolveIdentity` adapters into one: each is tried in order
28
+ * and the first to return a non-null identity wins. The canonical use is
29
+ * pairing Access with `@lunora/auth` —
30
+ * `composeResolvers(accessResolver, betterAuthResolver)` — so a request carrying
31
+ * an Access JWT (machine/SSO) is authenticated by Access while everyone else
32
+ * falls through to the app's own session.
33
+ */
34
34
  declare const composeResolvers: (...resolvers: ResolveIdentityFunction[]) => ResolveIdentityFunction;
35
35
  /**
36
- * Normalize a configured team domain to the canonical Access issuer URL.
37
- *
38
- * Accepts a short team name (`acme`), a host (`acme.cloudflareaccess.com`), or a
39
- * full URL, and always returns an `https://` origin with no trailing slash. A
40
- * bare name with no dot is expanded to the `cloudflareaccess.com` host.
41
- */
36
+ * Normalize a configured team domain to the canonical Access issuer URL.
37
+ *
38
+ * Accepts a short team name (`acme`), a host (`acme.cloudflareaccess.com`), or a
39
+ * full URL, and always returns an `https://` origin with no trailing slash. A
40
+ * bare name with no dot is expanded to the `cloudflareaccess.com` host.
41
+ */
42
42
  declare const accessIssuer: (teamDomain: string) => string;
43
43
  /**
44
- * Eagerly validate the static, construction-time verify options so a misconfigured
45
- * deployment fails fast at factory build time instead of degrading to
46
- * silent-anonymous on every request. `createAccessResolver` / `accessAdminGate`
47
- * call this once when built: `teamDomain` must resolve to a valid Access issuer
48
- * and `aud` must be a non-empty tag. The per-request catch in {@link verifyRequest}
49
- * then covers only genuine token-verification failures, not config mistakes a
50
- * broken deployment throws here at startup rather than resolving every caller to
51
- * anonymous with zero signal.
52
- */
53
-
54
- /**
55
- * Verify a Cloudflare Access JWT and return its claims.
56
- *
57
- * Enforces, in one shot: RS256 signature against the team JWKS, `iss` equal to
58
- * the team issuer, `aud` containing one of the configured Access application AUD
59
- * tags, and a non-expired `exp` (with optional clock tolerance). The algorithm
60
- * is pinned to `RS256` so an `alg:none` or HS-signed forgery is rejected
61
- * outright.
62
- *
63
- * Throws (a `jose` error) on any failure — callers that want fail-closed
64
- * anonymous behaviour should catch and treat it as "no identity" (the
65
- * `createAccessResolver` adapter does exactly this).
66
- * @param token The raw compact JWT (header value or cookie value).
67
- */
44
+ * Verify a Cloudflare Access JWT and return its claims.
45
+ *
46
+ * Enforces, in one shot: RS256 signature against the team JWKS, `iss` equal to
47
+ * the team issuer, `aud` containing one of the configured Access application AUD
48
+ * tags, and a non-expired `exp` (with optional clock tolerance). The algorithm
49
+ * is pinned to `RS256` so an `alg:none` or HS-signed forgery is rejected
50
+ * outright.
51
+ *
52
+ * Throws (a `jose` error) on any failure — callers that want fail-closed
53
+ * anonymous behaviour should catch and treat it as "no identity" (the
54
+ * `createAccessResolver` adapter does exactly this).
55
+ * @param token The raw compact JWT (header value or cookie value).
56
+ */
68
57
  declare const verifyAccessJwt: (token: string, options: VerifyAccessJwtOptions) => Promise<AccessClaims>;
69
- /**
70
- * Read the Access JWT off a request and verify it. Returns the verified claims,
71
- * or `undefined` when no token is present **or** verification fails — the single
72
- * fail-closed "no Access identity" signal that both `createAccessResolver` and
73
- * `accessAdminGate` build their distinct mapping / authorization step on top of.
74
- *
75
- * This is the package's one place that turns a request into verified claims:
76
- * header/cookie default resolution, the {@link readToken} read, the
77
- * {@link verifyAccessJwt} call, and the `onError`-observed fail-closed catch all
78
- * live here so the resolver and the admin gate carry only their genuinely
79
- * distinct line. `onError` fires for a present-but-invalid token, never for an
80
- * absent one.
81
- */
82
58
  export { type AccessClaims, type CreateAccessResolverOptions, type ResolveIdentityFunction, type VerifyAccessJwtOptions, accessIssuer, composeResolvers, createAccessResolver, verifyAccessJwt };
package/dist/index.d.ts CHANGED
@@ -1,82 +1,58 @@
1
- import { a as ResolveIdentityFunction, C as CreateAccessResolverOptions, V as VerifyAccessJwtOptions, A as AccessClaims } from "./packem_shared/types.d-BO8d74KI.js";
2
- export type { b as AccessKeySet, c as ResolvedAccessIdentity, d as ResolvedIdentityLike } from "./packem_shared/types.d-BO8d74KI.js";
1
+ import { a as ResolveIdentityFunction, C as CreateAccessResolverOptions, V as VerifyAccessJwtOptions, A as AccessClaims } from "./packem_shared/types.d-C8c7Qwx1.js";
2
+ export type { b as AccessKeySet, c as ResolvedAccessIdentity, d as ResolvedIdentityLike } from "./packem_shared/types.d-C8c7Qwx1.js";
3
3
  import 'jose';
4
4
  /**
5
- * Create a `resolveIdentity` adapter for Cloudflare Access. The returned
6
- * function reads the Access JWT off the request, verifies it (`verifyAccessJwt`),
7
- * and maps the claims onto the identity shape `@lunora/runtime` expects — so a
8
- * verified Access user/service-token becomes `ctx.auth` for every
9
- * query/mutation/action (and feeds RLS) with no further wiring.
10
- *
11
- * Behaviour is **fail-closed → anonymous**: a missing token, or a token that
12
- * fails verification, resolves to `null` (the request proceeds unauthenticated
13
- * and RLS denies). Use {@link CreateAccessResolverOptions.onError} to observe
14
- * verification failures.
15
- *
16
- * Wire it in your worker entry:
17
- *
18
- * ```ts
19
- * options.resolveIdentity = createAccessResolver({
20
- * teamDomain: env.CF_ACCESS_TEAM_DOMAIN, // "acme" | "acme.cloudflareaccess.com"
21
- * aud: env.CF_ACCESS_AUD, // the Access app's AUD tag
22
- * });
23
- * ```
24
- */
5
+ * Create a `resolveIdentity` adapter for Cloudflare Access. The returned
6
+ * function reads the Access JWT off the request, verifies it (`verifyAccessJwt`),
7
+ * and maps the claims onto the identity shape `@lunora/runtime` expects — so a
8
+ * verified Access user/service-token becomes `ctx.auth` for every
9
+ * query/mutation/action (and feeds RLS) with no further wiring.
10
+ *
11
+ * Behaviour is **fail-closed → anonymous**: a missing token, or a token that
12
+ * fails verification, resolves to `null` (the request proceeds unauthenticated
13
+ * and RLS denies). Use {@link CreateAccessResolverOptions.onError} to observe
14
+ * verification failures.
15
+ *
16
+ * Wire it in your worker entry:
17
+ *
18
+ * ```ts
19
+ * options.resolveIdentity = createAccessResolver({
20
+ * teamDomain: env.CF_ACCESS_TEAM_DOMAIN, // "acme" | "acme.cloudflareaccess.com"
21
+ * aud: env.CF_ACCESS_AUD, // the Access app's AUD tag
22
+ * });
23
+ * ```
24
+ */
25
25
  declare const createAccessResolver: (options: CreateAccessResolverOptions) => ResolveIdentityFunction;
26
26
  /**
27
- * Compose several `resolveIdentity` adapters into one: each is tried in order
28
- * and the first to return a non-null identity wins. The canonical use is
29
- * pairing Access with `@lunora/auth` —
30
- * `composeResolvers(accessResolver, betterAuthResolver)` — so a request carrying
31
- * an Access JWT (machine/SSO) is authenticated by Access while everyone else
32
- * falls through to the app's own session.
33
- */
27
+ * Compose several `resolveIdentity` adapters into one: each is tried in order
28
+ * and the first to return a non-null identity wins. The canonical use is
29
+ * pairing Access with `@lunora/auth` —
30
+ * `composeResolvers(accessResolver, betterAuthResolver)` — so a request carrying
31
+ * an Access JWT (machine/SSO) is authenticated by Access while everyone else
32
+ * falls through to the app's own session.
33
+ */
34
34
  declare const composeResolvers: (...resolvers: ResolveIdentityFunction[]) => ResolveIdentityFunction;
35
35
  /**
36
- * Normalize a configured team domain to the canonical Access issuer URL.
37
- *
38
- * Accepts a short team name (`acme`), a host (`acme.cloudflareaccess.com`), or a
39
- * full URL, and always returns an `https://` origin with no trailing slash. A
40
- * bare name with no dot is expanded to the `cloudflareaccess.com` host.
41
- */
36
+ * Normalize a configured team domain to the canonical Access issuer URL.
37
+ *
38
+ * Accepts a short team name (`acme`), a host (`acme.cloudflareaccess.com`), or a
39
+ * full URL, and always returns an `https://` origin with no trailing slash. A
40
+ * bare name with no dot is expanded to the `cloudflareaccess.com` host.
41
+ */
42
42
  declare const accessIssuer: (teamDomain: string) => string;
43
43
  /**
44
- * Eagerly validate the static, construction-time verify options so a misconfigured
45
- * deployment fails fast at factory build time instead of degrading to
46
- * silent-anonymous on every request. `createAccessResolver` / `accessAdminGate`
47
- * call this once when built: `teamDomain` must resolve to a valid Access issuer
48
- * and `aud` must be a non-empty tag. The per-request catch in {@link verifyRequest}
49
- * then covers only genuine token-verification failures, not config mistakes a
50
- * broken deployment throws here at startup rather than resolving every caller to
51
- * anonymous with zero signal.
52
- */
53
-
54
- /**
55
- * Verify a Cloudflare Access JWT and return its claims.
56
- *
57
- * Enforces, in one shot: RS256 signature against the team JWKS, `iss` equal to
58
- * the team issuer, `aud` containing one of the configured Access application AUD
59
- * tags, and a non-expired `exp` (with optional clock tolerance). The algorithm
60
- * is pinned to `RS256` so an `alg:none` or HS-signed forgery is rejected
61
- * outright.
62
- *
63
- * Throws (a `jose` error) on any failure — callers that want fail-closed
64
- * anonymous behaviour should catch and treat it as "no identity" (the
65
- * `createAccessResolver` adapter does exactly this).
66
- * @param token The raw compact JWT (header value or cookie value).
67
- */
44
+ * Verify a Cloudflare Access JWT and return its claims.
45
+ *
46
+ * Enforces, in one shot: RS256 signature against the team JWKS, `iss` equal to
47
+ * the team issuer, `aud` containing one of the configured Access application AUD
48
+ * tags, and a non-expired `exp` (with optional clock tolerance). The algorithm
49
+ * is pinned to `RS256` so an `alg:none` or HS-signed forgery is rejected
50
+ * outright.
51
+ *
52
+ * Throws (a `jose` error) on any failure — callers that want fail-closed
53
+ * anonymous behaviour should catch and treat it as "no identity" (the
54
+ * `createAccessResolver` adapter does exactly this).
55
+ * @param token The raw compact JWT (header value or cookie value).
56
+ */
68
57
  declare const verifyAccessJwt: (token: string, options: VerifyAccessJwtOptions) => Promise<AccessClaims>;
69
- /**
70
- * Read the Access JWT off a request and verify it. Returns the verified claims,
71
- * or `undefined` when no token is present **or** verification fails — the single
72
- * fail-closed "no Access identity" signal that both `createAccessResolver` and
73
- * `accessAdminGate` build their distinct mapping / authorization step on top of.
74
- *
75
- * This is the package's one place that turns a request into verified claims:
76
- * header/cookie default resolution, the {@link readToken} read, the
77
- * {@link verifyAccessJwt} call, and the `onError`-observed fail-closed catch all
78
- * live here so the resolver and the admin gate carry only their genuinely
79
- * distinct line. `onError` fires for a present-but-invalid token, never for an
80
- * absent one.
81
- */
82
58
  export { type AccessClaims, type CreateAccessResolverOptions, type ResolveIdentityFunction, type VerifyAccessJwtOptions, accessIssuer, composeResolvers, createAccessResolver, verifyAccessJwt };