@owlmeans/test-auth 0.1.18-rc.5 → 0.1.18-rc.50

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
@@ -1,16 +1,124 @@
1
1
  # @owlmeans/test-auth
2
2
 
3
- The **only** OwlMeans package that ships authentication/authorization mocks. Tests in any other package may import from here when they need a fake authenticated identity, a deterministic Ed25519 keypair, or an in-memory `TRUSTED` resource. No other mocks (database, network, sibling-package services) belong in test code — those packages get integration tests instead. See the `auth-protocol` skill for the protocol this mock implements.
3
+ The **only** OwlMeans package that ships authentication/authorization mocks. Tests in any other package may import from here when they need a fake authenticated identity, a deterministic Ed25519 keypair, or an in-memory `TRUSTED` resource. No other mocks (database, network, sibling-package services) belong in test code — those packages get integration tests instead (`@owlmeans/test-integration`). It is a dev dependency of category-B packages (the auth/authz family); a category-A package that seems to need it is testing behaviour that belongs in an auth-aware sibling. The package's skill is `testing-auth-unit`; the protocol these mocks stand in for is described by the `auth-protocol` skill.
4
4
 
5
- Helpers exported here:
5
+ ## Installation
6
6
 
7
- - `makeFixtureKeyPair(seed?)` — deterministic Ed25519 `KeyPairModel`.
8
- - `makeMemoryTrustedResource(records?)` — `Resource<TrustedRecord>` satisfying `trust()` lookups against the `TRUSTED` config resource.
9
- - `makeMockGuard({ alias?, auth?, allow? })` — `GuardService` that resolves to a chosen `Auth`. Implements `match`, `handle`, `authenticated`.
10
- - `withAuth(ctx, auth)` — convenience that registers a mock guard with a chosen `Auth` on the context.
11
- - `signMockEnvelope(msg, type, kind?, kp?)` — wraps `makeEnvelopeModel` with a fixture keypair to produce a signed envelope.
12
- - `makeBearer(auth, kp?)` — `ED25519-BASIC-TOKEN <encoded>` header value for unit tests of header parsing.
13
- - Canonical fixtures: `SUPERUSER`, `USER`, `SERVICE` `Auth` payloads.
7
+ ```bash
8
+ bun add -d @owlmeans/test-auth@^0.1.18-rc.50
9
+ ```
10
+
11
+ It depends on `@owlmeans/test`, so the env gates and fixture loader are available alongside.
12
+
13
+ ## Concepts
14
+
15
+ - **Fixture keypair** — `makeFixtureKeyPair(seed)`: an Ed25519 `KeyPairModel` derived from a seed,
16
+ so signatures and trusted records are stable run to run. No seed gives a random pair.
17
+ - **Trusted resource** — `makeMemoryTrustedResource(records, alias?)`: a `Resource<TrustedRecord>`
18
+ registered under `TRUSTED` that answers the `trust()` lookups of `@owlmeans/auth-common`.
19
+ - **Mock guard** — `makeMockGuard(opts)`: a real `GuardService` shape (`match`, `handle`,
20
+ `authenticated`) that resolves a chosen `Auth` without cryptography or trusted-record lookups.
21
+ Defaults to the `DEFAULT_GUARD` alias, so it takes the place a real guard would occupy.
22
+ - **Canonical identities** — `SUPERUSER`, `USER`, `SERVICE`: `Auth` payloads with `scopes: ['*']`.
23
+ - **Last registration wins** — `registerService` overwrites an alias, so a mock guard registered
24
+ before a real one under the same alias is silently replaced.
25
+
26
+ ## Usage
27
+
28
+ ### Build the suite's context
29
+
30
+ ```typescript
31
+ // tests/context.ts
32
+ import { AppType, makeBasicContext } from '@owlmeans/context'
33
+ import type { BasicConfig } from '@owlmeans/context'
34
+ import type { TrustedRecord } from '@owlmeans/auth-common'
35
+ import { USER, appendMockGuard, makeFixtureKeyPair, makeMemoryTrustedResource } from '@owlmeans/test-auth'
36
+
37
+ export const authKey = makeFixtureKeyPair('auth-service')
38
+
39
+ export const authRecord: TrustedRecord = {
40
+ id: authKey.exportAddress(),
41
+ name: 'auth-service', // trust() looks up by name by default — seed both fields
42
+ credential: authKey.exportPublic(), // add `secret: authKey.export()` when the code must sign
43
+ scopes: ['*'],
44
+ }
45
+
46
+ export const makeTestCtx = () => {
47
+ const ctx = makeBasicContext<BasicConfig>({
48
+ ready: false, service: 'my-pkg-tests', type: AppType.Backend,
49
+ })
50
+ ctx.registerResource(makeMemoryTrustedResource([authRecord]))
51
+ appendMockGuard(ctx, USER) // after anything that registers a real guard
52
+
53
+ return ctx
54
+ }
55
+ ```
56
+
57
+ ### Control what the guard matches
58
+
59
+ ```typescript
60
+ import { SERVICE, makeMockGuard } from '@owlmeans/test-auth'
61
+
62
+ const guard = makeMockGuard({
63
+ alias: 'service-guard',
64
+ auth: SERVICE,
65
+ allow: req => req.headers['x-service'] != null, // `match` reports this predicate
66
+ token: 'token-service', // what client-side `authenticated()` answers
67
+ })
68
+ ctx.registerService(guard)
69
+ ```
70
+
71
+ ### Sign envelopes and bearers
72
+
73
+ ```typescript
74
+ import { EnvelopeKind } from '@owlmeans/basic-envelope'
75
+ import { USER, makeBearer, makeFixtureKeyPair, signMockEnvelope } from '@owlmeans/test-auth'
76
+
77
+ const key = makeFixtureKeyPair('alice')
78
+ const token = await signMockEnvelope({ userId: 'u-1' }, 'ed25519-basic-token', EnvelopeKind.Token, key)
79
+
80
+ const header = await makeBearer(USER, key) // 'ED25519-BASIC-TOKEN <encoded>'
81
+ ```
82
+
83
+ ## API
84
+
85
+ | Symbol | Kind | Purpose |
86
+ |---|---|---|
87
+ | `makeFixtureKeyPair(seed?)` | function | Deterministic Ed25519 `KeyPairModel`; random without a seed |
88
+ | `makeMemoryTrustedResource(records?, alias?)` | function | `Resource<TrustedRecord>` satisfying `trust()` lookups against the `TRUSTED` config resource; `alias` defaults to `'TRUSTED'` |
89
+ | `makeMockGuard(opts?)` | function | `GuardService` that resolves to a chosen `Auth`; implements `match`, `handle`, `authenticated` |
90
+ | `appendMockGuard(ctx, auth, alias?)` | function | Registers a mock guard resolving to `auth` on the context and returns it |
91
+ | `signMockEnvelope(msg, type, kind?, kp?)` | function | Wraps `makeEnvelopeModel` with a fixture keypair to produce a signed envelope; `kind` defaults to `EnvelopeKind.Token` |
92
+ | `makeBearer(auth, kp?)` | function | `ED25519-BASIC-TOKEN <encoded>` header value for unit tests of header parsing and guard `match` |
93
+ | `SUPERUSER`, `USER`, `SERVICE` | const | Canonical `Auth` payloads (`Superuser` / `User` / `Service` roles) |
94
+ | `MockGuardOptions` | type | `{ alias?, auth?, allow?, token? }` |
95
+
96
+ ### The in-memory trusted resource
97
+
98
+ - Implements only `load`, `save` and `create`; every other method throws.
99
+ - A read takes an id, or a criteria over exactly one of `id` / `name` with a string value; anything
100
+ wider throws `UnsupportedArgumentError('test-auth:trusted:where')`.
101
+ - Every record needs an `id` — a record without one is rejected on construction, and `create` refuses
102
+ an id already held.
103
+
104
+ ## Common pitfalls
105
+
106
+ - Registering the mock guard first and a real guard (through an `append*` mixin or a context factory)
107
+ afterwards under the same alias — the real one wins and the spec fails on a trusted-record lookup.
108
+ - Using random keypairs where a signature or record must be stable — pass a seed.
109
+ - Seeding a trusted record with `id` only — `trust()` looks up by `name`.
110
+ - Adding a new auth mock to a package's own `tests/` — it belongs here, documented in the
111
+ `testing-auth-unit` skill.
112
+ - Mocking anything other than authentication/authorization — write an integration test instead.
113
+
114
+ ## Related packages
115
+
116
+ - [`@owlmeans/test`](../test) — env gates and fixture loader this package builds on
117
+ - [`@owlmeans/test-integration`](../test-integration) — the place for tests that would need any other mock
118
+ - [`@owlmeans/auth-common`](../auth-common) — `trust()`, `TrustedRecord`, `DEFAULT_GUARD`
119
+ - [`@owlmeans/basic-keys`](../basic-keys) — `KeyPairModel`
120
+ - [`@owlmeans/basic-envelope`](../basic-envelope) — `makeEnvelopeModel`, `EnvelopeKind`
121
+ - [`@owlmeans/auth`](../auth) — the `Auth` type and roles
14
122
 
15
123
  <!-- owlmeans:agent-guidance:start -->
16
124
  ## Agent guidance
@@ -20,7 +128,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
20
128
  your project's skill store (`.agents/skills/`):
21
129
 
22
130
  ```sh
23
- npx @owlmeans/agent-skills
131
+ npx @owlmeans/agent-skills@^0.1.18-rc.56
24
132
  ```
25
133
 
26
134
  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/test-auth",
4
- "version": "0.1.18-rc.0",
5
- "generatedAt": "2026-08-16T22:20:50.499Z",
4
+ "version": "0.1.18-rc.50",
5
+ "generatedAt": "2026-10-17T00:00:32.697Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,12 +1,14 @@
1
1
  ---
2
2
  name: testing-auth-unit
3
- description: Category-B unit tests for OwlMeans Common — auth/authz packages where the test substitutes a fake authenticated identity via @owlmeans/test-auth. Auto-invoked when writing tests in auth, auth-common, basic-keys, basic-envelope, did, client-auth, client-did, server-auth, oidc, server-oidc-*, web-oidc-*, wled, client-payment.
3
+ description: Category-B unit tests for OwlMeans Common — auth/authz packages where the test substitutes a fake authenticated identity via @owlmeans/test-auth. Auto-invoked when writing tests in auth, auth-common, auth-otp, basic-keys, basic-envelope, did, client-auth, client-did, client-iam, client-payment, mui-oidc-rp, oidc, server-auth, server-auth-otp, server-oidc-*, web-auth, web-oidc-*, wled.
4
4
  ---
5
5
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
6
6
 
7
7
  # Auth Unit Tests — Category B
8
8
 
9
- Category B applies to the auth/authz packages: `auth`, `auth-common`, `basic-keys`, `basic-envelope`, `did`, `client-auth`, `client-did`, `server-auth`, `oidc`, `server-oidc-rp`, `server-oidc-provider`, `web-oidc-rp`, `web-oidc-provider`, `wled`, `client-payment`. These tests run under `bun test` (no Playwright even when there are React bits) and are the **only** place mocks are allowed — and only for authentication/authorization, via `@owlmeans/test-auth`.
9
+ **Install:** `"@owlmeans/test-auth": "^0.1.18-rc.50"` in `devDependencies`
10
+
11
+ Category B applies to the auth/authz packages: `auth`, `auth-common`, `auth-otp`, `basic-envelope`, `basic-keys`, `client-auth`, `client-did`, `client-iam`, `client-payment`, `did`, `mui-oidc-rp`, `oidc`, `server-auth`, `server-auth-otp`, `server-oidc-provider`, `server-oidc-rp`, `web-auth`, `web-oidc-provider`, `web-oidc-rp`, `wled`. These tests run under `bun test` (no Playwright even when there are React bits) and are the **only** place mocks are allowed — and only for authentication/authorization, via `@owlmeans/test-auth`.
10
12
 
11
13
  For background on the protocol you're mocking, read the `auth-protocol` skill.
12
14
 
@@ -14,23 +16,37 @@ For background on the protocol you're mocking, read the `auth-protocol` skill.
14
16
 
15
17
  | Helper | Purpose |
16
18
  |---|---|
17
- | `makeFixtureKeyPair(seed?)` | Deterministic Ed25519 `KeyPairModel`. Same seed → same keys. |
18
- | `makeMemoryTrustedResource(records?)` | `Resource<TrustedRecord>` that satisfies `trust()` lookups. |
19
- | `makeMockGuard({ alias?, auth?, allow? })` | `GuardService` resolving to a chosen `Auth`. |
20
- | `withAuth(ctx, auth)` | Registers a mock guard on `ctx` that resolves to `auth`. |
21
- | `signMockEnvelope(msg, type, kind?, kp?)` | Wraps `makeEnvelopeModel` with a fixture keypair. |
22
- | `makeBearer(auth, kp?)` | Produces an `ED25519-BASIC-TOKEN <encoded>` header. |
23
- | `SUPERUSER`, `USER`, `SERVICE` | Canonical `Auth` payload fixtures. |
19
+ | `makeFixtureKeyPair(seed?)` | Deterministic Ed25519 `KeyPairModel`. Same seed → same keys; no seed → a fresh random pair. |
20
+ | `makeMemoryTrustedResource(records?, alias?)` | `Resource<TrustedRecord>` that satisfies `trust()` lookups. `alias` defaults to `TRUSTED`. |
21
+ | `makeMockGuard(opts?)` | `GuardService` resolving to a chosen `Auth`, registerable exactly like a real guard. |
22
+ | `MockGuardOptions` | `{ alias?, auth?, allow?, token? }` — see below. |
23
+ | `withAuth(ctx, auth, alias?)` | Registers a mock guard on `ctx` that resolves to `auth`, and returns `ctx`. |
24
+ | `signMockEnvelope(msg, type, kind?, kp?)` | Wraps `makeEnvelopeModel` with a fixture keypair and signs it; `kind` defaults to `EnvelopeKind.Token`. |
25
+ | `makeBearer(auth, kp?)` | Produces an `ED25519-BASIC-TOKEN <encoded>` header value from an `Auth`. |
26
+ | `SUPERUSER`, `USER`, `SERVICE` | Canonical `Auth` payload fixtures (`Superuser` / `User` / `Service` roles, `scopes: ['*']`). |
27
+
28
+ `MockGuardOptions` carries the whole seam: `auth` is what `handle` resolves into the response,
29
+ `allow` is the predicate `match` reports (default: always match), `token` is what the client-side
30
+ `authenticated()` answers, and `alias` defaults to `DEFAULT_GUARD` so the mock takes the place a
31
+ real guard would occupy. `withAuth` is the shorthand for the common case.
32
+
33
+ **The last registration for an alias wins.** `registerService` in `@owlmeans/context` assigns
34
+ `services[service.alias]`, so it overwrites silently — there is no "first one keeps the slot".
35
+ Register the mock **after** anything that appends a real guard under the same alias (an
36
+ `append*` mixin the package documents, or a context factory that wires one), or give the mock
37
+ its own alias and point the entrypoint's guard at that. A mock registered first and then
38
+ overwritten leaves the spec exercising real cryptography and failing on a trusted-record
39
+ lookup, which reads as an unrelated failure.
24
40
 
25
41
  ## `tests/context.ts` pattern
26
42
 
27
43
  ```ts
28
- import { AppType, Layer, makeBasicContext } from '@owlmeans/context'
44
+ import { AppType, makeBasicContext } from '@owlmeans/context'
29
45
  import { makeMemoryTrustedResource, withAuth, USER } from '@owlmeans/test-auth'
30
46
 
31
47
  export const makeTestCtx = () => {
32
48
  const ctx = makeBasicContext({
33
- ready: false, service: '<pkg>-tests', layer: Layer.Service, type: AppType.Backend,
49
+ ready: false, service: '<pkg>-tests', type: AppType.Backend, services: {},
34
50
  })
35
51
  ctx.registerResource(makeMemoryTrustedResource([
36
52
  { id: 'svc', name: 'svc', credential: '<fixture-pubkey>' },
@@ -40,6 +56,21 @@ export const makeTestCtx = () => {
40
56
  }
41
57
  ```
42
58
 
59
+ One factory, one context: the trusted resource and the mock guard are registered inside it, in the
60
+ order a real app's `makeContext` would.
61
+
62
+ `makeMemoryTrustedResource` implements only `load`, `save` and `create` — enough for the `trust()`
63
+ boundary and for seeding from a spec; every other resource method throws. A read takes an id or a
64
+ single-field criteria over `id` or `name`, and anything wider is refused with
65
+ `UnsupportedArgumentError` rather than scanned: a query the mock cannot answer exactly is a test
66
+ reaching past its seam, and the honest fix is integration coverage.
67
+
68
+ Every seeded record needs an `id`; a record without one is rejected on construction, and so is a
69
+ `create` for an id already held. `trust(context, resource, userName)` looks up by `name` by
70
+ default, so seed both fields. Give the record a `credential` (a public key) when the code under
71
+ test only verifies, and a `secret` (a private key) when it must sign as the trusted party —
72
+ `trust()` prefers `secret` and falls back to `credential`.
73
+
43
74
  The trusted resource, mock guard, and any fixture keys are the **only** mocks allowed. Everything else (the service under test, sibling packages it depends on) is the real thing.
44
75
 
45
76
  ## Spec shape
@@ -65,10 +96,10 @@ describe('@owlmeans/basic-keys — packAuthCredentials', () => {
65
96
  - **Mocks only for auth/authz.** No mocks for databases, network, or any sibling package. If you need one, move the spec to category C and write an integration test.
66
97
  - **Don't replicate `@owlmeans/test-auth` helpers in your package.** If you need a new mocking primitive (e.g. an OIDC userinfo endpoint stub), add it to `@owlmeans/test-auth` and its skill — never to a per-package `tests/`.
67
98
  - **Use deterministic seeds.** `makeFixtureKeyPair('<seed>')` keeps signatures stable run-to-run; random keypairs break snapshot-style assertions.
68
- - **Cover SKILL.md cases first.** The package's `.agents/skills/<pkg>/SKILL.md` documents the consumer-facing surface — that's the test priority order.
99
+ - **Cover SKILL.md cases first.** The package's own skill (its directory under `.agents/skills/` — named for the skill, which is not always the package name) documents the consumer-facing surface, and that is the test priority order.
69
100
  - **Max 3-4 tests per method/function.** Same as category A.
70
101
  - **Don't test types or utils.**
71
102
 
72
103
  ## When you actually want OIDC end-to-end
73
104
 
74
- The current `@owlmeans/test-auth` does not ship a fake JWKS server. Use the real `makeOidcGuard` against the in-memory trusted resource and a fixture keypair. If a future test needs a hostable IdP fake, add it to `@owlmeans/test-auth` and document it here — don't bolt it on per package.
105
+ `@owlmeans/test-auth` ships no fake JWKS server. Use the real `makeOidcGuard` against the in-memory trusted resource and a fixture keypair. If a future test needs a hostable IdP fake, add it to `@owlmeans/test-auth` and document it here — don't bolt it on per package.
@@ -0,0 +1,6 @@
1
+ export declare const TRUSTED_DEFAULT_ALIAS = "TRUSTED";
2
+ /** The fields a `trust()` lookup keys on — the only index this map has. */
3
+ export declare const SUPPORTED_FIELDS: string[];
4
+ /** The scheme word of an `Authorization` header carrying an Ed25519 basic token. */
5
+ export declare const AUTH_BEARER_PREFIX: string;
6
+ //# sourceMappingURL=consts.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,YAAY,CAAA;AAE9C,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,UAAiB,CAAA;AAE9C,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,QAAoD,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { AuthroizationType } from '@owlmeans/auth';
2
+ export const TRUSTED_DEFAULT_ALIAS = 'TRUSTED';
3
+ /** The fields a `trust()` lookup keys on — the only index this map has. */
4
+ export const SUPPORTED_FIELDS = ['id', 'name'];
5
+ /** The scheme word of an `Authorization` header carrying an Ed25519 basic token. */
6
+ export const AUTH_BEARER_PREFIX = AuthroizationType.Ed25519BasicToken.toUpperCase();
7
+ //# sourceMappingURL=consts.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../src/consts.local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,CAAC,MAAM,qBAAqB,GAAG,SAAS,CAAA;AAE9C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AAE9C,oFAAoF;AACpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,WAAW,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAK1C;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAU,CAAC,SAAS,EAAE,GAAG,MAAM,OACrD,CAAC,QACA,MAAM,SACN,YAAY,OACd,YAAY,KACf,OAAO,CAAC,MAAM,CAKhB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,SACf,IAAI,OACL,YAAY,KAChB,OAAO,CAAC,MAAM,CAQhB,CAAA"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,0BAA0B,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAI1C;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAAU,CAAC,SAAS,EAAE,GAAG,MAAM,OACrD,CAAC,QACA,MAAM,SACN,YAAY,OACd,YAAY,KACf,OAAO,CAAC,MAAM,CAKhB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,SACf,IAAI,OACL,YAAY,KAChB,OAAO,CAAC,MAAM,CAQhB,CAAA"}
package/build/envelope.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { EnvelopeKind, makeEnvelopeModel } from '@owlmeans/basic-envelope';
2
2
  import { AuthroizationType } from '@owlmeans/auth';
3
3
  import { makeFixtureKeyPair } from './keys.js';
4
- const AUTH_BEARER_PREFIX = AuthroizationType.Ed25519BasicToken.toUpperCase();
4
+ import { AUTH_BEARER_PREFIX } from './consts.local.js';
5
5
  /**
6
6
  * Wrap a payload in a signed `EnvelopeModel` using a fixture keypair (or one
7
7
  * supplied by the caller) and serialize it. Useful in category-B tests that
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAE9C,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,WAAW,EAAE,CAAA;AAE5E;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,GAAM,EACN,IAAY,EACZ,IAAI,GAAiB,YAAY,CAAC,KAAK,EACvC,EAAE,GAAiB,kBAAkB,CAAC,mBAAmB,CAAC,EACzC,EAAE;IACnB,MAAM,QAAQ,GAAG,iBAAiB,CAAI,IAAI,CAAC,CAAA;IAC3C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;IAC5C,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,IAAU,EACV,EAAiB,EACA,EAAE;IACnB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CACpC,IAA0C,EAC1C,iBAAiB,CAAC,iBAAiB,EACnC,YAAY,CAAC,KAAK,EAClB,EAAE,CACH,CAAA;IACD,OAAO,GAAG,kBAAkB,IAAI,OAAO,EAAE,CAAA;AAC3C,CAAC,CAAA"}
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,GAAM,EACN,IAAY,EACZ,IAAI,GAAiB,YAAY,CAAC,KAAK,EACvC,EAAE,GAAiB,kBAAkB,CAAC,mBAAmB,CAAC,EACzC,EAAE;IACnB,MAAM,QAAQ,GAAG,iBAAiB,CAAI,IAAI,CAAC,CAAA;IAC3C,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;IAC5C,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAC7B,IAAU,EACV,EAAiB,EACA,EAAE;IACnB,MAAM,OAAO,GAAG,MAAM,gBAAgB,CACpC,IAA0C,EAC1C,iBAAiB,CAAC,iBAAiB,EACnC,YAAY,CAAC,KAAK,EAClB,EAAE,CACH,CAAA;IACD,OAAO,GAAG,kBAAkB,IAAI,OAAO,EAAE,CAAA;AAC3C,CAAC,CAAA"}
package/build/guard.d.ts CHANGED
@@ -1,15 +1,7 @@
1
- import type { BasicConfig, BasicContext } from '@owlmeans/context';
1
+ import { type BasicConfig, type BasicContext } from '@owlmeans/context';
2
2
  import type { Auth } from '@owlmeans/auth';
3
- import type { AbstractRequest, AbstractResponse, GuardService } from '@owlmeans/entrypoint';
4
- export interface MockGuardOptions {
5
- alias?: string;
6
- /** Auth payload that `handle` will resolve into the response. */
7
- auth?: Auth;
8
- /** Optional predicate that decides whether `match` reports a hit. Defaults to "always match". */
9
- allow?: (req: AbstractRequest, res: AbstractResponse<unknown>) => boolean | Promise<boolean>;
10
- /** Token returned by the client-side `authenticated()` method. */
11
- token?: string;
12
- }
3
+ import type { GuardService } from '@owlmeans/entrypoint';
4
+ import type { MockGuardOptions } from './types.js';
13
5
  /**
14
6
  * Build a `GuardService` that resolves to a chosen `Auth` without exercising
15
7
  * any real cryptography or trusted-record lookup. Use this in category-B
@@ -26,5 +18,5 @@ export declare const makeMockGuard: (opts?: MockGuardOptions) => GuardService;
26
18
  * Returns the same context for chaining. Existing guards under the same
27
19
  * alias are not replaced — register before any real guard service.
28
20
  */
29
- export declare const withAuth: <C extends BasicConfig, T extends BasicContext<C>>(context: T, auth: Auth, alias?: string) => T;
21
+ export declare const appendMockGuard: <C extends BasicConfig, T extends BasicContext<C>>(context: T, auth: Auth, alias?: string) => T;
30
22
  //# sourceMappingURL=guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE3F,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,iGAAiG;IACjG,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5F,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,UAAU,gBAAgB,KAAQ,YAsB3D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WAC9D,CAAC,QACJ,IAAI,UACH,MAAM,KACZ,CAGF,CAAA"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEtF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,UAAU,gBAAgB,KAAQ,YAsB3D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,WACrE,CAAC,QACJ,IAAI,UACH,MAAM,KACZ,CAGF,CAAA"}
package/build/guard.js CHANGED
@@ -33,7 +33,7 @@ export const makeMockGuard = (opts = {}) => {
33
33
  * Returns the same context for chaining. Existing guards under the same
34
34
  * alias are not replaced — register before any real guard service.
35
35
  */
36
- export const withAuth = (context, auth, alias = DEFAULT_GUARD) => {
36
+ export const appendMockGuard = (context, auth, alias = DEFAULT_GUARD) => {
37
37
  const guard = makeMockGuard({ alias, auth });
38
38
  return context.registerService(guard);
39
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAcrD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAI,GAAqB,EAAE,EAAgB,EAAE;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAA;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAExC,MAAM,KAAK,GAAG,aAAa,CAAe,KAAK,EAAE;QAC/C,KAAK,EAAE,IAAI,CAAC,KAAK;QAEjB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACxB,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACvC,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC1B,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;gBACtB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACxB,CAAC;YACD,OAAO,IAAI,CAAC,IAAa,CAAA;QAC3B,CAAC;QAED,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI;KAC9C,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,OAAU,EACV,IAAU,EACV,KAAK,GAAW,aAAa,EAC1B,EAAE;IACL,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,OAAO,OAAO,CAAC,eAAe,CAAI,KAAK,CAAC,CAAA;AAC1C,CAAC,CAAA"}
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAuC,MAAM,mBAAmB,CAAA;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAKrD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAI,GAAqB,EAAE,EAAgB,EAAE;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAA;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAExC,MAAM,KAAK,GAAG,aAAa,CAAe,KAAK,EAAE;QAC/C,KAAK,EAAE,IAAI,CAAC,KAAK;QAEjB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACxB,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;QACvC,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC1B,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;gBACtB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACxB,CAAC;YACD,OAAO,IAAI,CAAC,IAAa,CAAA;QAC3B,CAAC;QAED,aAAa,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI;KAC9C,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,OAAU,EACV,IAAU,EACV,KAAK,GAAW,aAAa,EAC1B,EAAE;IACL,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,OAAO,OAAO,CAAC,eAAe,CAAI,KAAK,CAAC,CAAA;AAC1C,CAAC,CAAA"}
package/build/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './keys.js';
2
2
  export * from './trusted.js';
3
3
  export * from './guard.js';
4
+ export type * from './types.js';
4
5
  export * from './envelope.js';
5
6
  export * from './fixtures.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,mBAAmB,YAAY,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAE1B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import type { TrustedRecord } from '@owlmeans/auth-common';
2
- import type { Resource } from '@owlmeans/resource';
2
+ import { type Resource } from '@owlmeans/resource';
3
3
  /**
4
4
  * In-memory `Resource<TrustedRecord>` used to satisfy `trust()` lookups
5
5
  * (`@owlmeans/auth-common/utils/trusted.ts`). Pre-populate with the
@@ -9,6 +9,10 @@ import type { Resource } from '@owlmeans/resource';
9
9
  * `trust()` boundary plus straightforward seeding from tests. Other
10
10
  * operations throw, so tests that need them have to be honest about
11
11
  * adding integration coverage instead of leaning on the mock.
12
+ *
13
+ * A read takes an id or a single-field criteria over `id` or `name`. Anything
14
+ * wider is refused rather than scanned: the mock holds a handful of fixtures
15
+ * and a query it cannot answer exactly is a test reaching past its seam.
12
16
  */
13
17
  export declare const makeMemoryTrustedResource: (records?: TrustedRecord[], alias?: string) => Resource<TrustedRecord>;
14
18
  //# sourceMappingURL=trusted.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"trusted.d.ts","sourceRoot":"","sources":["../src/trusted.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAWlD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,aAC3B,aAAa,EAAE,UACjB,MAAM,KACZ,QAAQ,CAAC,aAAa,CAsDxB,CAAA"}
1
+ {"version":3,"file":"trusted.d.ts","sourceRoot":"","sources":["../src/trusted.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAoC,KAAK,QAAQ,EAA4B,MAAM,oBAAoB,CAAA;AAU9G;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,aAC3B,aAAa,EAAE,UACjB,MAAM,KACZ,QAAQ,CAAC,aAAa,CAqExB,CAAA"}
package/build/trusted.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { appendContextual } from '@owlmeans/context';
2
- const TRUSTED_DEFAULT_ALIAS = 'TRUSTED';
2
+ import { UnsupportedArgumentError } from '@owlmeans/resource';
3
+ import { SUPPORTED_FIELDS, TRUSTED_DEFAULT_ALIAS } from './consts.local.js';
3
4
  const notImplemented = (op) => {
4
5
  throw new Error(`@owlmeans/test-auth: in-memory TRUSTED resource does not implement ${op}()`);
5
6
  };
@@ -13,6 +14,10 @@ const getter = (record, field) => record[field];
13
14
  * `trust()` boundary plus straightforward seeding from tests. Other
14
15
  * operations throw, so tests that need them have to be honest about
15
16
  * adding integration coverage instead of leaning on the mock.
17
+ *
18
+ * A read takes an id or a single-field criteria over `id` or `name`. Anything
19
+ * wider is refused rather than scanned: the mock holds a handful of fixtures
20
+ * and a query it cannot answer exactly is a test reaching past its seam.
16
21
  */
17
22
  export const makeMemoryTrustedResource = (records = [], alias = TRUSTED_DEFAULT_ALIAS) => {
18
23
  const store = new Map();
@@ -29,16 +34,24 @@ export const makeMemoryTrustedResource = (records = [], alias = TRUSTED_DEFAULT_
29
34
  }
30
35
  return null;
31
36
  };
37
+ /**
38
+ * @throws {UnsupportedArgumentError} on criteria naming anything but one supported field.
39
+ */
40
+ const first = (idOrWhere) => {
41
+ if (typeof idOrWhere === 'string') {
42
+ return store.get(idOrWhere) ?? null;
43
+ }
44
+ const entries = Object.entries(idOrWhere).filter(([, value]) => value !== undefined);
45
+ const [entry, ...rest] = entries;
46
+ if (entry == null || rest.length > 0
47
+ || !SUPPORTED_FIELDS.includes(entry[0]) || typeof entry[1] !== 'string') {
48
+ throw new UnsupportedArgumentError('test-auth:trusted:where');
49
+ }
50
+ const [field, value] = entry;
51
+ return field === 'id' ? store.get(value) ?? null : findByField(value, field);
52
+ };
32
53
  const resource = {
33
- load: async (id, field) => {
34
- const fieldName = typeof field === 'string'
35
- ? field
36
- : field?.field;
37
- if (fieldName != null && fieldName !== 'id') {
38
- return findByField(id, fieldName) ?? null;
39
- }
40
- return store.get(id) ?? null;
41
- },
54
+ load: async (idOrWhere, _opts) => first(idOrWhere),
42
55
  save: async (record) => {
43
56
  if (record.id == null) {
44
57
  throw new Error('@owlmeans/test-auth: cannot save TRUSTED record without id');
@@ -58,9 +71,11 @@ export const makeMemoryTrustedResource = (records = [], alias = TRUSTED_DEFAULT_
58
71
  },
59
72
  get: () => notImplemented('get'),
60
73
  list: () => notImplemented('list'),
74
+ count: () => notImplemented('count'),
61
75
  update: () => notImplemented('update'),
62
76
  delete: () => notImplemented('delete'),
63
- pick: () => notImplemented('pick'),
77
+ take: () => notImplemented('take'),
78
+ purge: () => notImplemented('purge'),
64
79
  };
65
80
  return appendContextual(alias, resource);
66
81
  };
@@ -1 +1 @@
1
- {"version":3,"file":"trusted.js","sourceRoot":"","sources":["../src/trusted.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trusted.js","sourceRoot":"","sources":["../src/trusted.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Auth } from '@owlmeans/auth';
2
+ import type { AbstractRequest, AbstractResponse } from '@owlmeans/entrypoint';
3
+ export interface MockGuardOptions {
4
+ alias?: string;
5
+ /** Auth payload that `handle` will resolve into the response. */
6
+ auth?: Auth;
7
+ /** Optional predicate that decides whether `match` reports a hit. Defaults to "always match". */
8
+ allow?: (req: AbstractRequest, res: AbstractResponse<unknown>) => boolean | Promise<boolean>;
9
+ /** Token returned by the client-side `authenticated()` method. */
10
+ token?: string;
11
+ }
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,iGAAiG;IACjG,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,gBAAgB,CAAC,OAAO,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5F,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAA;CACf"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/test-auth",
3
- "version": "0.1.18-rc.5",
3
+ "version": "0.1.18-rc.50",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,18 +21,18 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@owlmeans/auth": "^0.1.18-rc.5",
25
- "@owlmeans/auth-common": "^0.1.18-rc.5",
26
- "@owlmeans/basic-envelope": "^0.1.18-rc.5",
27
- "@owlmeans/basic-keys": "^0.1.18-rc.5",
28
- "@owlmeans/context": "^0.1.18-rc.5",
29
- "@owlmeans/entrypoint": "^0.1.18-rc.5",
30
- "@owlmeans/resource": "^0.1.18-rc.5",
31
- "@owlmeans/test": "^0.1.18-rc.5"
24
+ "@owlmeans/auth": "^0.1.18-rc.41",
25
+ "@owlmeans/auth-common": "^0.1.18-rc.51",
26
+ "@owlmeans/basic-envelope": "^0.1.18-rc.50",
27
+ "@owlmeans/basic-keys": "^0.1.18-rc.52",
28
+ "@owlmeans/context": "^0.1.18-rc.34",
29
+ "@owlmeans/entrypoint": "^0.1.18-rc.41",
30
+ "@owlmeans/resource": "^0.1.18-rc.40",
31
+ "@owlmeans/test": "^0.1.18-rc.37"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@owlmeans/dep-config": "workspace:*",
35
- "@types/bun": "^1.3.14",
35
+ "@types/bun": "^1.4.2",
36
36
  "nodemon": "^3.1.14",
37
37
  "typescript": "^7.0.2"
38
38
  },
@@ -0,0 +1,9 @@
1
+ import { AuthroizationType } from '@owlmeans/auth'
2
+
3
+ export const TRUSTED_DEFAULT_ALIAS = 'TRUSTED'
4
+
5
+ /** The fields a `trust()` lookup keys on — the only index this map has. */
6
+ export const SUPPORTED_FIELDS = ['id', 'name']
7
+
8
+ /** The scheme word of an `Authorization` header carrying an Ed25519 basic token. */
9
+ export const AUTH_BEARER_PREFIX = AuthroizationType.Ed25519BasicToken.toUpperCase()
package/src/envelope.ts CHANGED
@@ -3,8 +3,7 @@ import type { KeyPairModel } from '@owlmeans/basic-keys'
3
3
  import { AuthroizationType } from '@owlmeans/auth'
4
4
  import type { Auth } from '@owlmeans/auth'
5
5
  import { makeFixtureKeyPair } from './keys.js'
6
-
7
- const AUTH_BEARER_PREFIX = AuthroizationType.Ed25519BasicToken.toUpperCase()
6
+ import { AUTH_BEARER_PREFIX } from './consts.local.js'
8
7
 
9
8
  /**
10
9
  * Wrap a payload in a signed `EnvelopeModel` using a fixture keypair (or one
package/src/guard.ts CHANGED
@@ -1,18 +1,8 @@
1
- import { createService } from '@owlmeans/context'
2
- import type { BasicConfig, BasicContext } from '@owlmeans/context'
1
+ import { createService, type BasicConfig, type BasicContext } from '@owlmeans/context'
3
2
  import { DEFAULT_GUARD } from '@owlmeans/auth-common'
4
3
  import type { Auth } from '@owlmeans/auth'
5
- import type { AbstractRequest, AbstractResponse, GuardService } from '@owlmeans/entrypoint'
6
-
7
- export interface MockGuardOptions {
8
- alias?: string
9
- /** Auth payload that `handle` will resolve into the response. */
10
- auth?: Auth
11
- /** Optional predicate that decides whether `match` reports a hit. Defaults to "always match". */
12
- allow?: (req: AbstractRequest, res: AbstractResponse<unknown>) => boolean | Promise<boolean>
13
- /** Token returned by the client-side `authenticated()` method. */
14
- token?: string
15
- }
4
+ import type { GuardService } from '@owlmeans/entrypoint'
5
+ import type { MockGuardOptions } from './types.js'
16
6
 
17
7
  /**
18
8
  * Build a `GuardService` that resolves to a chosen `Auth` without exercising
@@ -53,7 +43,7 @@ export const makeMockGuard = (opts: MockGuardOptions = {}): GuardService => {
53
43
  * Returns the same context for chaining. Existing guards under the same
54
44
  * alias are not replaced — register before any real guard service.
55
45
  */
56
- export const withAuth = <C extends BasicConfig, T extends BasicContext<C>>(
46
+ export const appendMockGuard = <C extends BasicConfig, T extends BasicContext<C>>(
57
47
  context: T,
58
48
  auth: Auth,
59
49
  alias: string = DEFAULT_GUARD
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './keys.js'
2
2
  export * from './trusted.js'
3
3
  export * from './guard.js'
4
+ export type * from './types.js'
4
5
  export * from './envelope.js'
5
6
  export * from './fixtures.js'
package/src/trusted.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { appendContextual } from '@owlmeans/context'
2
2
  import type { TrustedRecord } from '@owlmeans/auth-common'
3
- import type { Resource } from '@owlmeans/resource'
4
-
5
- const TRUSTED_DEFAULT_ALIAS = 'TRUSTED'
3
+ import { type Criteria, type FirstOptions, type Resource, UnsupportedArgumentError } from '@owlmeans/resource'
4
+ import { SUPPORTED_FIELDS, TRUSTED_DEFAULT_ALIAS } from './consts.local.js'
6
5
 
7
6
  const notImplemented = (op: string): never => {
8
7
  throw new Error(`@owlmeans/test-auth: in-memory TRUSTED resource does not implement ${op}()`)
@@ -20,6 +19,10 @@ const getter = (record: TrustedRecord, field: string): unknown =>
20
19
  * `trust()` boundary plus straightforward seeding from tests. Other
21
20
  * operations throw, so tests that need them have to be honest about
22
21
  * adding integration coverage instead of leaning on the mock.
22
+ *
23
+ * A read takes an id or a single-field criteria over `id` or `name`. Anything
24
+ * wider is refused rather than scanned: the mock holds a handful of fixtures
25
+ * and a query it cannot answer exactly is a test reaching past its seam.
23
26
  */
24
27
  export const makeMemoryTrustedResource = (
25
28
  records: TrustedRecord[] = [],
@@ -40,26 +43,39 @@ export const makeMemoryTrustedResource = (
40
43
  return null
41
44
  }
42
45
 
46
+ /**
47
+ * @throws {UnsupportedArgumentError} on criteria naming anything but one supported field.
48
+ */
49
+ const first = (idOrWhere: string | Criteria<TrustedRecord>): TrustedRecord | null => {
50
+ if (typeof idOrWhere === 'string') {
51
+ return store.get(idOrWhere) ?? null
52
+ }
53
+
54
+ const entries = Object.entries(idOrWhere).filter(([, value]) => value !== undefined)
55
+ const [entry, ...rest] = entries
56
+ if (entry == null || rest.length > 0
57
+ || !SUPPORTED_FIELDS.includes(entry[0]) || typeof entry[1] !== 'string') {
58
+ throw new UnsupportedArgumentError('test-auth:trusted:where')
59
+ }
60
+ const [field, value] = entry as [string, string]
61
+
62
+ return field === 'id' ? store.get(value) ?? null : findByField(value, field)
63
+ }
64
+
43
65
  const resource: Partial<Resource<TrustedRecord>> = {
44
- load: async <Type extends TrustedRecord>(id: string, field?: unknown) => {
45
- const fieldName = typeof field === 'string'
46
- ? field
47
- : (field as { field?: string } | undefined)?.field
48
- if (fieldName != null && fieldName !== 'id') {
49
- return (findByField(id, fieldName) as Type | null) ?? null
50
- }
51
- return (store.get(id) as Type | undefined) ?? null
52
- },
66
+ load: async (
67
+ idOrWhere: string | Criteria<TrustedRecord>, _opts?: FirstOptions<TrustedRecord>
68
+ ): Promise<TrustedRecord | null> => first(idOrWhere),
53
69
 
54
- save: async <Type extends TrustedRecord>(record: Partial<Type>) => {
70
+ save: async (record: Partial<TrustedRecord>) => {
55
71
  if (record.id == null) {
56
72
  throw new Error('@owlmeans/test-auth: cannot save TRUSTED record without id')
57
73
  }
58
74
  store.set(record.id, record as TrustedRecord)
59
- return record as Type
75
+ return record as TrustedRecord
60
76
  },
61
77
 
62
- create: async <Type extends TrustedRecord>(record: Partial<Type>) => {
78
+ create: async (record: Partial<TrustedRecord>) => {
63
79
  if (record.id == null) {
64
80
  throw new Error('@owlmeans/test-auth: cannot create TRUSTED record without id')
65
81
  }
@@ -67,14 +83,16 @@ export const makeMemoryTrustedResource = (
67
83
  throw new Error(`@owlmeans/test-auth: TRUSTED record ${record.id} already exists`)
68
84
  }
69
85
  store.set(record.id, record as TrustedRecord)
70
- return record as Type
86
+ return record as TrustedRecord
71
87
  },
72
88
 
73
89
  get: () => notImplemented('get'),
74
90
  list: () => notImplemented('list'),
91
+ count: () => notImplemented('count'),
75
92
  update: () => notImplemented('update'),
76
93
  delete: () => notImplemented('delete'),
77
- pick: () => notImplemented('pick'),
94
+ take: () => notImplemented('take'),
95
+ purge: () => notImplemented('purge'),
78
96
  }
79
97
 
80
98
  return appendContextual<Resource<TrustedRecord>>(alias, resource)
package/src/types.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { Auth } from '@owlmeans/auth'
2
+ import type { AbstractRequest, AbstractResponse } from '@owlmeans/entrypoint'
3
+
4
+ export interface MockGuardOptions {
5
+ alias?: string
6
+ /** Auth payload that `handle` will resolve into the response. */
7
+ auth?: Auth
8
+ /** Optional predicate that decides whether `match` reports a hit. Defaults to "always match". */
9
+ allow?: (req: AbstractRequest, res: AbstractResponse<unknown>) => boolean | Promise<boolean>
10
+ /** Token returned by the client-side `authenticated()` method. */
11
+ token?: string
12
+ }