@owlmeans/server-auth-token 0.1.18-rc.1 → 0.1.18-rc.11

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/README.md CHANGED
@@ -6,7 +6,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
6
6
  your project's skill store (`.agents/skills/`):
7
7
 
8
8
  ```sh
9
- npx @owlmeans/agent-skills@^0.1.18-rc.13
9
+ npx @owlmeans/agent-skills@^0.1.18-rc.23
10
10
  ```
11
11
 
12
12
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/server-auth-token",
4
- "version": "0.1.18-rc.1",
5
- "generatedAt": "2026-09-10T18:54:42.508Z",
4
+ "version": "0.1.18-rc.11",
5
+ "generatedAt": "2026-09-15T12:50:32.651Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/server-auth-token
9
9
 
10
10
  **Layer:** Server
11
- **Install:** `"@owlmeans/server-auth-token": "^0.1.18-rc.1"` in `dependencies`
11
+ **Install:** `"@owlmeans/server-auth-token": "^0.1.18-rc.11"` in `dependencies`
12
12
  **Contracts:** `@owlmeans/auth-token` — the record, the routes, the format helpers
13
13
 
14
14
  ## Key Exports
@@ -21,7 +21,7 @@ user-invocable: false
21
21
  | `makeAccessTokenResource(dbAlias?)` | The Mongo resource, with its three indexes |
22
22
  | `prefixOf(context, opts?)` | The deployment's prefix: guard options → config → default |
23
23
  | `hashAccessToken(token)` · `mintAccessToken(prefix)` | The stored form; one minted `{ token, hash, display }` |
24
- | `setupAuthTokenCoguard(entrypoints, guard?)` | Append the guard to every entrypoint that already has one |
24
+ | `withAuthTokenCoguard(protocolTree, guard?)` | Return the same-shaped immutable tree with the guard appended to every already-guarded protocol |
25
25
  | `listAccessTokens` · `createAccessToken` · `revokeAccessToken` | The three handlers |
26
26
  | `AuthTokenGuardOptions` (`prefix`, `denyAliases`, `touchInterval`, `resourceAlias`, `profileAlias`) · `AuthTokenConfig` · `AccessTokenResource` | Types |
27
27
 
@@ -99,7 +99,7 @@ tokens that are not theirs.
99
99
  ## The coguard admits a token everywhere, and the deny list lives in the GUARD
100
100
 
101
101
  ```typescript
102
- setupAuthTokenCoguard(managerEntrypoints as Array<{ guards?: string[] }>)
102
+ const guardedManagerProtocols = withAuthTokenCoguard(managerProtocols)
103
103
  ```
104
104
 
105
105
  An API client drives the same surface a browser does — projects, stories, files — so admitting the
@@ -108,8 +108,8 @@ never substitutes: the primary guard stays first and still claims its own creden
108
108
  matches only a value carrying the prefix. It skips entrypoints that have no guard, and it is
109
109
  idempotent.
110
110
 
111
- **Run it after the last elevation**, because it reads the guard list each entrypoint actually ended
112
- up with.
111
+ Decorate the declaration tree before bindings are created. The helper preserves the input tree's
112
+ shape, leaves unguarded protocols unchanged, and is idempotent.
113
113
 
114
114
  Routes that must stay behind an interactive session — opening a checkout, starting an OAuth flow,
115
115
  minting another token — are named in `AuthTokenGuardOptions.denyAliases` rather than skipped here.
@@ -1,3 +1,4 @@
1
+ import type { EntrypointTree } from '@owlmeans/entrypoint';
1
2
  /**
2
3
  * Let an access token authenticate every route that already has a guard.
3
4
  *
@@ -10,7 +11,5 @@
10
11
  * than skipped here — a child entrypoint inherits every guard its ancestors declare and cannot
11
12
  * drop one, so the refusal has to live where the credential is inspected.
12
13
  */
13
- export declare const setupAuthTokenCoguard: (entrypoints: Array<{
14
- guards?: string[];
15
- }>, guard?: string) => void;
14
+ export declare const withAuthTokenCoguard: <Tree extends EntrypointTree>(tree: Tree, guard?: string) => Tree;
16
15
  //# sourceMappingURL=coguard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coguard.d.ts","sourceRoot":"","sources":["../src/coguard.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,gBACnB,KAAK,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,UAAS,MAAM,KACvD,IAMF,CAAA"}
1
+ {"version":3,"file":"coguard.d.ts","sourceRoot":"","sources":["../src/coguard.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAAI,IAAI,SAAS,cAAc,QACxD,IAAI,UAAS,MAAM,KACxB,IAID,CAAA"}
package/build/coguard.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token';
2
+ import { decorateEntrypoint, mapProtocols } from '@owlmeans/entrypoint';
2
3
  /**
3
4
  * Let an access token authenticate every route that already has a guard.
4
5
  *
@@ -11,13 +12,9 @@ import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token';
11
12
  * than skipped here — a child entrypoint inherits every guard its ancestors declare and cannot
12
13
  * drop one, so the refusal has to live where the credential is inspected.
13
14
  */
14
- export const setupAuthTokenCoguard = (entrypoints, guard = GUARD_AUTH_TOKEN) => {
15
- entrypoints.forEach(entrypoint => {
16
- if (entrypoint.guards == null || entrypoint.guards.length < 1)
17
- return;
18
- if (entrypoint.guards.includes(guard))
19
- return;
20
- entrypoint.guards = [...entrypoint.guards, guard];
21
- });
22
- };
15
+ export const withAuthTokenCoguard = (tree, guard = GUARD_AUTH_TOKEN) => mapProtocols(tree, declaration => {
16
+ if (declaration.guards.length < 1 || declaration.guards.includes(guard))
17
+ return declaration;
18
+ return decorateEntrypoint(declaration, { guards: [...declaration.guards, guard] });
19
+ });
23
20
  //# sourceMappingURL=coguard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"coguard.js","sourceRoot":"","sources":["../src/coguard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,WAAyC,EAAE,KAAK,GAAW,gBAAgB,EACrE,EAAE;IACR,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QAC/B,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAM;QACrE,IAAI,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAM;QAC7C,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
1
+ {"version":3,"file":"coguard.js","sourceRoot":"","sources":["../src/coguard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGvE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,IAAU,EAAE,KAAK,GAAW,gBAAgB,EACtC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE;IAC1C,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,WAAW,CAAA;IAE3F,OAAO,kBAAkB,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAA;AACpF,CAAC,CAAC,CAAA"}
@@ -1,4 +1,12 @@
1
- export declare const listAccessTokens: import("@owlmeans/server-entrypoint").RefedEntrypointHandler<import("@owlmeans/entrypoint").AbstractResponse<any>>;
2
- export declare const createAccessToken: import("@owlmeans/server-entrypoint").RefedEntrypointHandler<import("@owlmeans/entrypoint").AbstractResponse<any>>;
3
- export declare const revokeAccessToken: import("@owlmeans/server-entrypoint").RefedEntrypointHandler<import("@owlmeans/entrypoint").AbstractResponse<any>>;
1
+ import type { AccessTokenList, IssuedAccessToken } from '@owlmeans/auth-token';
2
+ import type { AuthTokenEntrypoints } from '@owlmeans/auth-token';
3
+ export declare const listAccessTokens: (protocol: AuthTokenEntrypoints['list']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<import("@owlmeans/entrypoint").OpenRequest, AccessTokenList>>;
4
+ export declare const createAccessToken: (protocol: AuthTokenEntrypoints['create']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<{
5
+ body: import("@owlmeans/auth-token").CreateAccessToken;
6
+ }, IssuedAccessToken>>;
7
+ export declare const revokeAccessToken: (protocol: AuthTokenEntrypoints['revoke']) => import("@owlmeans/server-entrypoint").BoundEntrypointHandler<import("@owlmeans/entrypoint").EntrypointProtocol<{
8
+ params: import("@owlmeans/auth-token").AccessTokenParams;
9
+ }, {
10
+ id: string;
11
+ }>>;
4
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAsCA,eAAO,MAAM,gBAAgB,oHAa3B,CAAA;AAEF,eAAO,MAAM,iBAAiB,oHAsC5B,CAAA;AAEF,eAAO,MAAM,iBAAiB,oHAqB5B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAAsC,iBAAiB,EACvE,MAAM,sBAAsB,CAAA;AAM7B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AA0BhE,eAAO,MAAM,gBAAgB,aAAc,oBAAoB,CAAC,MAAM,CAAC,iLAarE,CAAA;AAEF,eAAO,MAAM,iBAAiB,aAAc,oBAAoB,CAAC,QAAQ,CAAC;;sBAsCxE,CAAA;AAEF,eAAO,MAAM,iBAAiB,aAAc,oBAAoB,CAAC,QAAQ,CAAC;;;;GAqBxE,CAAA"}
@@ -1,7 +1,7 @@
1
1
  import { AuthForbidden, AuthroizationType, ALL_SCOPES, AuthRole } from '@owlmeans/auth';
2
2
  import { AUTH_TOKEN_MAX_TTL, AUTH_TOKEN_RESOURCE } from '@owlmeans/auth-token';
3
3
  import { requireEntityKey } from '@owlmeans/auth-common';
4
- import { handleBody, handleParams, handleRequest } from '@owlmeans/server-api';
4
+ import { handlers } from '@owlmeans/server-api';
5
5
  import { mintAccessToken } from '../hash.js';
6
6
  import { prefixOf } from '../guard.js';
7
7
  const view = (record) => {
@@ -23,7 +23,7 @@ const refuseTokenAuth = (req, what) => {
23
23
  throw new AuthForbidden(what);
24
24
  }
25
25
  };
26
- export const listAccessTokens = handleRequest(async (req, context) => {
26
+ export const listAccessTokens = (protocol) => handlers().request(protocol, async (req, context) => {
27
27
  const ctx = context;
28
28
  const entityId = requireEntityKey(req);
29
29
  const profileId = req.auth?.profileId;
@@ -36,7 +36,7 @@ export const listAccessTokens = handleRequest(async (req, context) => {
36
36
  .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()),
37
37
  };
38
38
  });
39
- export const createAccessToken = handleBody(async (payload, context, req) => {
39
+ export const createAccessToken = (protocol) => handlers().body(protocol, async (payload, context, req) => {
40
40
  const ctx = context;
41
41
  refuseTokenAuth(req, 'token-mint');
42
42
  const entityId = requireEntityKey(req);
@@ -72,7 +72,7 @@ export const createAccessToken = handleBody(async (payload, context, req) => {
72
72
  // The only moment the plaintext exists outside the caller's own machine.
73
73
  return { token: minted.token, record: view(record) };
74
74
  });
75
- export const revokeAccessToken = handleParams(async (payload, context, req) => {
75
+ export const revokeAccessToken = (protocol) => handlers().params(protocol, async (payload, context, req) => {
76
76
  const ctx = context;
77
77
  refuseTokenAuth(req, 'token-revoke');
78
78
  const entityId = requireEntityKey(req);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/handlers/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/server-auth-token",
3
- "version": "0.1.18-rc.1",
3
+ "version": "0.1.18-rc.11",
4
4
  "license": "MIT",
5
5
  "description": "The server half of OwlMeans access tokens — the store, the guard that verifies a presented token, the management handlers and the coguard that admits one on an existing route.",
6
6
  "type": "module",
@@ -24,16 +24,16 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@noble/hashes": "^1.5.0",
27
- "@owlmeans/auth": "^0.1.18-rc.10",
28
- "@owlmeans/auth-common": "^0.1.18-rc.14",
29
- "@owlmeans/auth-token": "^0.1.18-rc.1",
30
- "@owlmeans/context": "^0.1.18-rc.9",
31
- "@owlmeans/entrypoint": "^0.1.18-rc.12",
32
- "@owlmeans/mongo-resource": "^0.1.18-rc.13",
33
- "@owlmeans/resource": "^0.1.18-rc.10",
34
- "@owlmeans/server-api": "^0.1.18-rc.18",
35
- "@owlmeans/server-auth-identity": "^0.1.18-rc.14",
36
- "@owlmeans/server-context": "^0.1.18-rc.13",
27
+ "@owlmeans/auth": "^0.1.18-rc.20",
28
+ "@owlmeans/auth-common": "^0.1.18-rc.24",
29
+ "@owlmeans/auth-token": "^0.1.18-rc.11",
30
+ "@owlmeans/context": "^0.1.18-rc.19",
31
+ "@owlmeans/entrypoint": "^0.1.18-rc.22",
32
+ "@owlmeans/mongo-resource": "^0.1.18-rc.23",
33
+ "@owlmeans/resource": "^0.1.18-rc.20",
34
+ "@owlmeans/server-api": "^0.1.18-rc.28",
35
+ "@owlmeans/server-auth-identity": "^0.1.18-rc.24",
36
+ "@owlmeans/server-context": "^0.1.18-rc.23",
37
37
  "@scure/base": "^1.1.9"
38
38
  },
39
39
  "devDependencies": {
package/src/coguard.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token'
2
+ import { decorateEntrypoint, mapProtocols } from '@owlmeans/entrypoint'
3
+ import type { EntrypointTree } from '@owlmeans/entrypoint'
2
4
 
3
5
  /**
4
6
  * Let an access token authenticate every route that already has a guard.
@@ -12,12 +14,10 @@ import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token'
12
14
  * than skipped here — a child entrypoint inherits every guard its ancestors declare and cannot
13
15
  * drop one, so the refusal has to live where the credential is inspected.
14
16
  */
15
- export const setupAuthTokenCoguard = (
16
- entrypoints: Array<{ guards?: string[] }>, guard: string = GUARD_AUTH_TOKEN
17
- ): void => {
18
- entrypoints.forEach(entrypoint => {
19
- if (entrypoint.guards == null || entrypoint.guards.length < 1) return
20
- if (entrypoint.guards.includes(guard)) return
21
- entrypoint.guards = [...entrypoint.guards, guard]
22
- })
23
- }
17
+ export const withAuthTokenCoguard = <Tree extends EntrypointTree>(
18
+ tree: Tree, guard: string = GUARD_AUTH_TOKEN,
19
+ ): Tree => mapProtocols(tree, declaration => {
20
+ if (declaration.guards.length < 1 || declaration.guards.includes(guard)) return declaration
21
+
22
+ return decorateEntrypoint(declaration, { guards: [...declaration.guards, guard] })
23
+ })
@@ -3,14 +3,14 @@ import {
3
3
  AUTH_TOKEN_MAX_TTL, AUTH_TOKEN_RESOURCE
4
4
  } from '@owlmeans/auth-token'
5
5
  import type {
6
- AccessTokenList, AccessTokenParams, AccessTokenRecord, AccessTokenView, CreateAccessToken,
7
- IssuedAccessToken
6
+ AccessTokenList, AccessTokenRecord, AccessTokenView, IssuedAccessToken
8
7
  } from '@owlmeans/auth-token'
9
8
  import { requireEntityKey } from '@owlmeans/auth-common'
10
- import { handleBody, handleParams, handleRequest } from '@owlmeans/server-api'
9
+ import { handlers } from '@owlmeans/server-api'
11
10
  import { mintAccessToken } from '../hash.js'
12
11
  import { prefixOf } from '../guard.js'
13
12
  import type { AccessTokenResource, AuthTokenContext } from '../types.js'
13
+ import type { AuthTokenEntrypoints } from '@owlmeans/auth-token'
14
14
 
15
15
  const view = (record: AccessTokenRecord): AccessTokenView => {
16
16
  const { hash, ...rest } = record
@@ -36,7 +36,7 @@ const refuseTokenAuth = (req: { auth?: { type?: string } }, what: string): void
36
36
  }
37
37
  }
38
38
 
39
- export const listAccessTokens = handleRequest(async (req, context) => {
39
+ export const listAccessTokens = (protocol: AuthTokenEntrypoints['list']) => handlers<AuthTokenContext>().request(protocol, async (req, context) => {
40
40
  const ctx = context as AuthTokenContext
41
41
  const entityId = requireEntityKey(req)
42
42
  const profileId = req.auth?.profileId
@@ -51,7 +51,7 @@ export const listAccessTokens = handleRequest(async (req, context) => {
51
51
  } satisfies AccessTokenList
52
52
  })
53
53
 
54
- export const createAccessToken = handleBody<CreateAccessToken>(async (payload, context, req) => {
54
+ export const createAccessToken = (protocol: AuthTokenEntrypoints['create']) => handlers<AuthTokenContext>().body(protocol, async (payload, context, req) => {
55
55
  const ctx = context as AuthTokenContext
56
56
  refuseTokenAuth(req, 'token-mint')
57
57
 
@@ -91,7 +91,7 @@ export const createAccessToken = handleBody<CreateAccessToken>(async (payload, c
91
91
  return { token: minted.token, record: view(record) } satisfies IssuedAccessToken
92
92
  })
93
93
 
94
- export const revokeAccessToken = handleParams<AccessTokenParams>(async (payload, context, req) => {
94
+ export const revokeAccessToken = (protocol: AuthTokenEntrypoints['revoke']) => handlers<AuthTokenContext>().params(protocol, async (payload, context, req) => {
95
95
  const ctx = context as AuthTokenContext
96
96
  refuseTokenAuth(req, 'token-revoke')
97
97
 
@@ -1,36 +1,34 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import { GUARD_AUTH_TOKEN } from '@owlmeans/auth-token'
3
- import { setupAuthTokenCoguard } from '../src/coguard.js'
3
+ import { openProtocol, protocols } from '@owlmeans/entrypoint'
4
+ import { route } from '@owlmeans/route'
5
+ import { withAuthTokenCoguard } from '../src/coguard.js'
4
6
 
5
7
  describe('@owlmeans/server-auth-token — the coguard', () => {
6
- test('appends to a guarded entrypoint and leaves the primary guard first', () => {
7
- const entrypoints = [{ guards: ['auth'] }]
8
- setupAuthTokenCoguard(entrypoints)
8
+ test('decorates a guarded protocol and leaves the primary guard first', () => {
9
+ const guarded = openProtocol(route('guarded', '/guarded'), { guards: 'auth' })
10
+ const [decorated] = protocols(withAuthTokenCoguard({ guarded }))
9
11
 
10
- expect(entrypoints[0].guards).toEqual(['auth', GUARD_AUTH_TOKEN])
12
+ expect(decorated.guards).toEqual(['auth', GUARD_AUTH_TOKEN])
13
+ expect(guarded.guards).toEqual(['auth'])
11
14
  })
12
15
 
13
- test('leaves an unguarded entrypoint unguarded', () => {
14
- // A public route stays public: adding a guard here would turn an open page into a 401.
15
- const entrypoints: Array<{ guards?: string[] }> = [{}, { guards: [] }]
16
- setupAuthTokenCoguard(entrypoints)
17
-
18
- expect(entrypoints[0].guards).toBeUndefined()
19
- expect(entrypoints[1].guards).toEqual([])
16
+ test('leaves an unguarded protocol unchanged', () => {
17
+ const open = openProtocol(route('open', '/open'))
18
+ expect(protocols(withAuthTokenCoguard({ open }))[0]).toBe(open)
20
19
  })
21
20
 
22
- test('is idempotent — a second pass adds nothing', () => {
23
- const entrypoints = [{ guards: ['auth'] }]
24
- setupAuthTokenCoguard(entrypoints)
25
- setupAuthTokenCoguard(entrypoints)
21
+ test('is idempotent', () => {
22
+ const guarded = openProtocol(route('guarded', '/guarded'), { guards: 'auth' })
23
+ const [once] = protocols(withAuthTokenCoguard({ guarded }))
24
+ const [twice] = protocols(withAuthTokenCoguard({ once }))
26
25
 
27
- expect(entrypoints[0].guards).toEqual(['auth', GUARD_AUTH_TOKEN])
26
+ expect(twice.guards).toEqual(['auth', GUARD_AUTH_TOKEN])
28
27
  })
29
28
 
30
29
  test('honours a custom guard alias', () => {
31
- const entrypoints = [{ guards: ['auth'] }]
32
- setupAuthTokenCoguard(entrypoints, 'other-guard')
33
-
34
- expect(entrypoints[0].guards).toEqual(['auth', 'other-guard'])
30
+ const guarded = openProtocol(route('guarded', '/guarded'), { guards: 'auth' })
31
+ expect(protocols(withAuthTokenCoguard({ guarded }, 'other-guard'))[0].guards)
32
+ .toEqual(['auth', 'other-guard'])
35
33
  })
36
34
  })
@@ -1,24 +1,32 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import { AuthroizationType, AuthRole } from '@owlmeans/auth'
3
- import { AUTH_TOKEN_RESOURCE } from '@owlmeans/auth-token'
3
+ import { AUTH_TOKEN_RESOURCE, makeAuthTokenEntrypoints } from '@owlmeans/auth-token'
4
4
  import type { AccessTokenRecord, IssuedAccessToken } from '@owlmeans/auth-token'
5
- import { createAccessToken, listAccessTokens, revokeAccessToken } from '../src/handlers/index.js'
5
+ import {
6
+ createAccessToken as bindCreateAccessToken,
7
+ listAccessTokens as bindListAccessTokens,
8
+ revokeAccessToken as bindRevokeAccessToken,
9
+ } from '../src/handlers/index.js'
6
10
  import { hashAccessToken } from '../src/hash.js'
7
11
  import { makeTestContext, seedProfile, seedToken, TEST_ENTITY, TEST_PREFIX, TEST_PROFILE, TEST_USER } from './context.js'
8
12
 
9
13
  /**
10
- * A handler is a `RefedEntrypointHandler`: it is given the entrypoint reference it was elevated
11
- * onto and answers with `(req, res)`. Calling it directly is what lets these tests be about the
12
- * RULES — who may mint, what a list shows, whose token may be revoked — rather than about routing.
14
+ * A protocol-bound implementation is run with the smallest binding context the transport needs.
15
+ * This keeps the tests about the authorization rules rather than a router's alias lookup.
13
16
  */
14
17
  const invoke = async (handler: any, context: any, req: any): Promise<any> => {
15
18
  const res: any = { resolve: (value: unknown) => { res.value = value }, reject: (e: Error) => { res.error = e } }
16
- await handler({ ref: { ctx: context } })(req, res)
19
+ await handler.bind({ ref: { ctx: context } })(req, res)
17
20
  if (res.error != null) throw res.error
18
21
 
19
22
  return res.value
20
23
  }
21
24
 
25
+ const protocols = makeAuthTokenEntrypoints()
26
+ const listAccessTokens = bindListAccessTokens(protocols.list)
27
+ const createAccessToken = bindCreateAccessToken(protocols.create)
28
+ const revokeAccessToken = bindRevokeAccessToken(protocols.revoke)
29
+
22
30
  const session = (patch: Record<string, unknown> = {}): any => ({
23
31
  headers: {}, params: {}, query: {}, body: {},
24
32
  entity: { id: TEST_ENTITY, slug: TEST_ENTITY },