@fuzdev/fuz_app 0.54.0 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/CLAUDE.md +68 -13
- package/dist/actions/action_codegen.d.ts +13 -0
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +15 -1
- package/dist/actions/action_rpc.d.ts +60 -7
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +158 -44
- package/dist/actions/register_action_ws.d.ts +4 -4
- package/dist/actions/register_action_ws.js +6 -6
- package/dist/actions/register_ws_endpoint.d.ts +20 -7
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +30 -5
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +0 -4
- package/dist/auth/CLAUDE.md +219 -66
- package/dist/auth/account_actions.d.ts +6 -6
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +8 -11
- package/dist/auth/account_queries.d.ts +6 -3
- package/dist/auth/account_queries.d.ts.map +1 -1
- package/dist/auth/account_queries.js +14 -5
- package/dist/auth/account_routes.d.ts +7 -10
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +70 -23
- package/dist/auth/account_schema.d.ts +19 -0
- package/dist/auth/account_schema.d.ts.map +1 -1
- package/dist/auth/account_schema.js +20 -0
- package/dist/auth/admin_action_specs.d.ts +45 -11
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +23 -8
- package/dist/auth/admin_actions.d.ts +8 -7
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +11 -18
- package/dist/auth/audit_log_queries.d.ts +53 -14
- package/dist/auth/audit_log_queries.d.ts.map +1 -1
- package/dist/auth/audit_log_queries.js +45 -2
- package/dist/auth/audit_log_schema.d.ts +55 -1
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +19 -3
- package/dist/auth/bearer_auth.d.ts +9 -7
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +13 -21
- package/dist/auth/cleanup.d.ts.map +1 -1
- package/dist/auth/cleanup.js +5 -0
- package/dist/auth/daemon_token_middleware.d.ts +23 -11
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +26 -20
- package/dist/auth/deps.d.ts +14 -0
- package/dist/auth/deps.d.ts.map +1 -1
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +4 -2
- package/dist/auth/migrations.d.ts +15 -7
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +15 -7
- package/dist/auth/permit_offer_action_specs.d.ts +45 -6
- package/dist/auth/permit_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/permit_offer_action_specs.js +38 -7
- package/dist/auth/permit_offer_actions.d.ts +2 -2
- package/dist/auth/permit_offer_actions.d.ts.map +1 -1
- package/dist/auth/permit_offer_actions.js +98 -90
- package/dist/auth/permit_offer_notifications.d.ts +10 -0
- package/dist/auth/permit_offer_notifications.d.ts.map +1 -1
- package/dist/auth/permit_offer_queries.d.ts +68 -9
- package/dist/auth/permit_offer_queries.d.ts.map +1 -1
- package/dist/auth/permit_offer_queries.js +147 -35
- package/dist/auth/permit_offer_schema.d.ts +23 -1
- package/dist/auth/permit_offer_schema.d.ts.map +1 -1
- package/dist/auth/permit_offer_schema.js +5 -0
- package/dist/auth/permit_queries.d.ts +17 -5
- package/dist/auth/permit_queries.d.ts.map +1 -1
- package/dist/auth/permit_queries.js +19 -8
- package/dist/auth/request_context.d.ts +321 -38
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +393 -66
- package/dist/auth/route_guards.d.ts +10 -4
- package/dist/auth/route_guards.d.ts.map +1 -1
- package/dist/auth/route_guards.js +14 -8
- package/dist/auth/self_service_role_action_specs.d.ts +2 -0
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +2 -0
- package/dist/auth/self_service_role_actions.d.ts +6 -5
- package/dist/auth/self_service_role_actions.d.ts.map +1 -1
- package/dist/auth/self_service_role_actions.js +18 -8
- package/dist/db/migrate.d.ts +11 -7
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +9 -6
- package/dist/dev/setup.d.ts.map +1 -1
- package/dist/dev/setup.js +5 -3
- package/dist/hono_context.d.ts +77 -0
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +50 -0
- package/dist/http/CLAUDE.md +80 -17
- package/dist/http/error_schemas.d.ts +92 -1
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +73 -16
- package/dist/http/jsonrpc_errors.d.ts +27 -2
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +26 -2
- package/dist/http/route_spec.d.ts +62 -4
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/route_spec.js +117 -21
- package/dist/http/schema_helpers.d.ts +13 -1
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +21 -2
- package/dist/http/surface.d.ts +10 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +2 -2
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +11 -1
- package/dist/testing/CLAUDE.md +23 -17
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +15 -13
- package/dist/testing/adversarial_headers.js +1 -1
- package/dist/testing/app_server.js +2 -2
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +21 -7
- package/dist/testing/auth_apps.d.ts.map +1 -1
- package/dist/testing/auth_apps.js +6 -3
- package/dist/testing/entities.d.ts +2 -1
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +1 -0
- package/dist/testing/integration_helpers.d.ts +4 -2
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +9 -5
- package/dist/testing/middleware.d.ts +12 -8
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +67 -25
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +3 -1
- package/dist/testing/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/ws_round_trip.js +5 -1
- package/dist/ui/CLAUDE.md +16 -10
- package/dist/ui/PermitOfferForm.svelte +14 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts +6 -0
- package/dist/ui/PermitOfferForm.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts +8 -1
- package/dist/ui/admin_accounts_state.svelte.d.ts.map +1 -1
- package/dist/ui/admin_accounts_state.svelte.js +14 -3
- package/dist/ui/permit_offers_state.svelte.d.ts +9 -1
- package/dist/ui/permit_offers_state.svelte.d.ts.map +1 -1
- package/dist/ui/permit_offers_state.svelte.js +7 -1
- package/package.json +1 -1
|
@@ -25,7 +25,6 @@ import { rpc_call_for_spec, require_rpc_endpoint_path, resolve_rpc_endpoints_for
|
|
|
25
25
|
import { permit_offer_create_action_spec, permit_revoke_action_spec, } from '../auth/permit_offer_action_specs.js';
|
|
26
26
|
import { admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, app_settings_update_action_spec, invite_create_action_spec, invite_delete_action_spec, } from '../auth/admin_action_specs.js';
|
|
27
27
|
import { account_session_list_action_spec, account_session_revoke_action_spec, account_session_revoke_all_action_spec, account_token_create_action_spec, account_token_list_action_spec, account_token_revoke_action_spec, } from '../auth/account_action_specs.js';
|
|
28
|
-
import { query_actor_by_account } from '../auth/account_queries.js';
|
|
29
28
|
/** Query audit log events from the database. */
|
|
30
29
|
const query_audit_events = async (db) => {
|
|
31
30
|
return db.query('SELECT event_type, seq FROM audit_log ORDER BY seq');
|
|
@@ -250,16 +249,19 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
250
249
|
const events_after_offer = await query_audit_events(test_app.backend.deps.db);
|
|
251
250
|
assert_has_event(events_after_offer, 'permit_offer_create', 'permit_offer_create RPC');
|
|
252
251
|
await get_db().transaction(async (tx) => {
|
|
253
|
-
await query_accept_offer({ db: tx }, {
|
|
252
|
+
await query_accept_offer({ db: tx }, {
|
|
253
|
+
offer_id: offer.id,
|
|
254
|
+
to_account_id: target.account.id,
|
|
255
|
+
actor_id: target.actor.id,
|
|
256
|
+
ip: null,
|
|
257
|
+
});
|
|
254
258
|
});
|
|
255
259
|
const events_after_accept = await query_audit_events(test_app.backend.deps.db);
|
|
256
260
|
assert_has_event(events_after_accept, 'permit_grant', 'offer accept');
|
|
257
261
|
});
|
|
258
|
-
test('permit revoke (RPC) produces permit_revoke event', async () => {
|
|
262
|
+
test('permit revoke (RPC) produces permit_revoke event with both target columns', async () => {
|
|
259
263
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
260
264
|
const target = await test_app.create_account({ username: 'audit_revoke_target' });
|
|
261
|
-
const target_actor = await query_actor_by_account({ db: get_db() }, target.account.id);
|
|
262
|
-
assert.ok(target_actor);
|
|
263
265
|
// Offer + accept to materialize a permit we can revoke.
|
|
264
266
|
const offer_res = await rpc_call_for_spec({
|
|
265
267
|
app: test_app.app,
|
|
@@ -271,19 +273,31 @@ export const describe_audit_completeness_tests = (options) => {
|
|
|
271
273
|
assert.ok(offer_res.ok, `permit_offer_create failed: ${offer_res.ok ? '' : JSON.stringify(offer_res.error)}`);
|
|
272
274
|
const { offer } = offer_res.result;
|
|
273
275
|
const accept_result = await get_db().transaction(async (tx) => {
|
|
274
|
-
return query_accept_offer({ db: tx }, {
|
|
276
|
+
return query_accept_offer({ db: tx }, {
|
|
277
|
+
offer_id: offer.id,
|
|
278
|
+
to_account_id: target.account.id,
|
|
279
|
+
actor_id: target.actor.id,
|
|
280
|
+
ip: null,
|
|
281
|
+
});
|
|
275
282
|
});
|
|
276
283
|
// Revoke via RPC.
|
|
277
284
|
const revoke_res = await rpc_call_for_spec({
|
|
278
285
|
app: test_app.app,
|
|
279
286
|
path: rpc_path,
|
|
280
287
|
spec: permit_revoke_action_spec,
|
|
281
|
-
params: { actor_id:
|
|
288
|
+
params: { actor_id: target.actor.id, permit_id: accept_result.permit.id },
|
|
282
289
|
headers: test_app.create_session_headers(),
|
|
283
290
|
});
|
|
284
291
|
assert.ok(revoke_res.ok, `permit_revoke failed: ${revoke_res.ok ? '' : JSON.stringify(revoke_res.error)}`);
|
|
285
292
|
const events = await query_audit_events(test_app.backend.deps.db);
|
|
286
293
|
assert_has_event(events, 'permit_revoke', 'permit_revoke RPC');
|
|
294
|
+
// Audit envelope must populate both target columns —
|
|
295
|
+
// `permit_revoke` is the canonical actor-bound-subject event.
|
|
296
|
+
const revoke_rows = await test_app.backend.deps.db.query(`SELECT target_account_id, target_actor_id FROM audit_log
|
|
297
|
+
WHERE event_type = 'permit_revoke' ORDER BY seq DESC LIMIT 1`);
|
|
298
|
+
const row = revoke_rows[0];
|
|
299
|
+
assert.strictEqual(row.target_account_id, target.account.id);
|
|
300
|
+
assert.strictEqual(row.target_actor_id, target.actor.id);
|
|
287
301
|
});
|
|
288
302
|
test('admin session revoke-all produces session_revoke_all event', async () => {
|
|
289
303
|
const test_app = await create_test_app(build_options(options, get_db()));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_apps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/auth_apps.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAG1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,
|
|
1
|
+
{"version":3,"file":"auth_apps.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/auth_apps.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAG1B,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAExF,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAIN,KAAK,cAAc,EACnB,MAAM,oBAAoB,CAAC;AAI5B;;GAEG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,MAAM,KAAG,cAI1D,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GACtC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,WAAW,cAAc,EACzB,kBAAkB,cAAc,KAC9B,IAsBF,CAAC;AAEF,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GACjC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAClB,YAeF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,YAAY,EAAE,MAAM,SAAS,KAAG,IAcrE,CAAC;AAEF,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,MAA4C,CAAC"}
|
|
@@ -11,8 +11,8 @@ import { Hono } from 'hono';
|
|
|
11
11
|
import { Logger } from '@fuzdev/fuz_util/log.js';
|
|
12
12
|
import { apply_route_specs } from '../http/route_spec.js';
|
|
13
13
|
import { fuz_auth_guard_resolver } from '../auth/route_guards.js';
|
|
14
|
-
import { REQUEST_CONTEXT_KEY } from '../auth/request_context.js';
|
|
15
|
-
import { CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
14
|
+
import { REQUEST_CONTEXT_KEY, create_fuz_authorization_handler, } from '../auth/request_context.js';
|
|
15
|
+
import { ACCOUNT_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY, } from '../hono_context.js';
|
|
16
16
|
import { create_stub_db } from './stubs.js';
|
|
17
17
|
import { create_test_account, create_test_actor, create_test_permit } from './entities.js';
|
|
18
18
|
/**
|
|
@@ -32,15 +32,18 @@ export const create_test_request_context = (role) => ({
|
|
|
32
32
|
*/
|
|
33
33
|
export const create_test_app_from_specs = (route_specs, auth_ctx, credential_type) => {
|
|
34
34
|
const app = new Hono();
|
|
35
|
+
const db = create_stub_db();
|
|
35
36
|
app.use('/*', async (c, next) => {
|
|
36
37
|
c.set('pending_effects', []);
|
|
37
38
|
if (auth_ctx) {
|
|
39
|
+
c.set(ACCOUNT_ID_KEY, auth_ctx.account.id);
|
|
38
40
|
c.set(REQUEST_CONTEXT_KEY, auth_ctx);
|
|
39
41
|
c.set(CREDENTIAL_TYPE_KEY, credential_type ?? 'session');
|
|
42
|
+
c.set(TEST_CONTEXT_PRESET_KEY, true);
|
|
40
43
|
}
|
|
41
44
|
await next();
|
|
42
45
|
});
|
|
43
|
-
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, new Logger('test', { level: 'off' }),
|
|
46
|
+
apply_route_specs(app, route_specs, fuz_auth_guard_resolver, new Logger('test', { level: 'off' }), db, create_fuz_authorization_handler({ db }));
|
|
44
47
|
return app;
|
|
45
48
|
};
|
|
46
49
|
/**
|
|
@@ -32,11 +32,12 @@ export declare const create_test_permit: (overrides?: TestPermitOverrides) => Pe
|
|
|
32
32
|
/** Create a test `RequestContext` with permits from partial overrides. */
|
|
33
33
|
export declare const create_test_context: (permits?: Array<TestPermitOverrides>) => RequestContext;
|
|
34
34
|
/** Override type for `create_test_audit_event` — id-like fields accept plain `string`. */
|
|
35
|
-
export type TestAuditEventOverrides = Partial<Omit<AuditLogEvent, 'id' | 'actor_id' | 'account_id' | 'target_account_id'>> & {
|
|
35
|
+
export type TestAuditEventOverrides = Partial<Omit<AuditLogEvent, 'id' | 'actor_id' | 'account_id' | 'target_account_id' | 'target_actor_id'>> & {
|
|
36
36
|
id?: string;
|
|
37
37
|
actor_id?: string | null;
|
|
38
38
|
account_id?: string | null;
|
|
39
39
|
target_account_id?: string | null;
|
|
40
|
+
target_actor_id?: string | null;
|
|
40
41
|
};
|
|
41
42
|
/** Create a test `AuditLogEvent` with sensible defaults. */
|
|
42
43
|
export declare const create_test_audit_event: (overrides?: TestAuditEventOverrides) => AuditLogEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,YAAY,oBAAoB,KAAG,OAWrE,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC3F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,GAAI,YAAY,kBAAkB,KAAG,KAQjE,CAAC;AAEH,qFAAqF;AACrF,MAAM,MAAM,mBAAmB,GAAG,OAAO,CACxC,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC,CAC9F,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,GAAI,YAAY,mBAAmB,KAAG,MAanE,CAAC;AAEH,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAC/B,UAAS,KAAK,CAAC,mBAAmB,CAAQ,KACxC,cAID,CAAC;AAEH,0FAA0F;AAC1F,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC5C,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/entities.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,KAAK,EAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAC,MAAM,2BAA2B,CAAC;AACtE,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,6BAA6B,CAAC;AAC/D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAE/D,sFAAsF;AACtF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC/F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,YAAY,oBAAoB,KAAG,OAWrE,CAAC;AAEH,oFAAoF;AACpF,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC,GAAG;IAC3F,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,GAAI,YAAY,kBAAkB,KAAG,KAQjE,CAAC;AAEH,qFAAqF;AACrF,MAAM,MAAM,mBAAmB,GAAG,OAAO,CACxC,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,GAAG,iBAAiB,CAAC,CAC9F,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,GAAI,YAAY,mBAAmB,KAAG,MAanE,CAAC;AAEH,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,GAC/B,UAAS,KAAK,CAAC,mBAAmB,CAAQ,KACxC,cAID,CAAC;AAEH,0FAA0F;AAC1F,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAC5C,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,CAC/F,GAAG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,uBAAuB,GAAI,YAAY,uBAAuB,KAAG,aAa5E,CAAC"}
|
package/dist/testing/entities.js
CHANGED
|
@@ -59,11 +59,13 @@ export declare const check_error_response_fields: (body: Record<string, unknown>
|
|
|
59
59
|
* Assert that an error response contains no leaky field values.
|
|
60
60
|
*
|
|
61
61
|
* Checks both field names and string values for patterns indicating
|
|
62
|
-
* stack traces, SQL, or internal paths.
|
|
62
|
+
* stack traces, SQL, or internal paths. Accepts `unknown` so callers
|
|
63
|
+
* pass response bodies / nested envelope fields directly without
|
|
64
|
+
* intermediate `as` casts; non-object bodies skip the field-name check.
|
|
63
65
|
*
|
|
64
66
|
* @param context - description for error messages
|
|
65
67
|
*/
|
|
66
|
-
export declare const assert_no_error_info_leakage: (body:
|
|
68
|
+
export declare const assert_no_error_info_leakage: (body: unknown, context: string) => void;
|
|
67
69
|
/**
|
|
68
70
|
* Assert that a 429 response includes a valid `Retry-After` header
|
|
69
71
|
* matching the JSON body's `retry_after` field.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,MAAM,EACd,MAAM,MAAM,KACV,SAAS,GAAG,SAad,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iFAO3B,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,mBAAmB,EAC3B,QAAQ,WAAW,KACjB,SAAS,GAAG,SAOd,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GACxC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,UAAU,QAAQ,KAChB,OAAO,CAAC,IAAI,CAmDd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,SAAS,OAAO,EAChB,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,OAAO,CAAC,MAAM,CAGhB,CAAC;AAgCF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,KAAK,CAAC,MAAM,CAQvF,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"integration_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAU7B,OAAO,KAAK,EAAC,SAAS,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAElE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAA8B,KAAK,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAE3F,OAAO,KAAK,EAAC,OAAO,EAAE,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAE1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,MAAM,EACd,MAAM,MAAM,KACV,SAAS,GAAG,SAad,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,iFAO3B,CAAC;AACX,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAC3B,OAAO,KAAK,CAAC,SAAS,CAAC,EACvB,QAAQ,mBAAmB,EAC3B,QAAQ,WAAW,KACjB,SAAS,GAAG,SAOd,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GACxC,aAAa,KAAK,CAAC,SAAS,CAAC,EAC7B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,UAAU,QAAQ,KAChB,OAAO,CAAC,IAAI,CAmDd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,GACtC,SAAS,OAAO,EAChB,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,OAAO,CAAC,MAAM,CAGhB,CAAC;AAgCF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,KAAK,CAAC,MAAM,CAQvF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,MAAM,OAAO,EAAE,SAAS,MAAM,KAAG,IAoB7E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,oCAAoC,GAChD,UAAU,QAAQ,EAClB,MAAM;IAAC,WAAW,EAAE,MAAM,CAAA;CAAC,KACzB,IAUF,CAAC;AAIF,oEAAoE;AACpE,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC,MAAM,CAAmC,CAAC;AAEhG,0EAA0E;AAC1E,eAAO,MAAM,0BAA0B,EAAE,aAAa,CAAC,MAAM,CAAgC,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GAAI,OAAO,OAAO,KAAG,GAAG,CAAC,MAAM,CAetE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,GAC9C,MAAM,OAAO,EACb,WAAW,aAAa,CAAC,MAAM,CAAC,EAChC,SAAS,MAAM,KACb,IAKF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC7B,MAAM,SAAS,EACf,UAAU,OAAO,EACjB,gBAAgB,WAAW,EAC3B,eAAe,WAAW,KACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAcvB,CAAC"}
|
|
@@ -172,16 +172,20 @@ export const check_error_response_fields = (body) => {
|
|
|
172
172
|
* Assert that an error response contains no leaky field values.
|
|
173
173
|
*
|
|
174
174
|
* Checks both field names and string values for patterns indicating
|
|
175
|
-
* stack traces, SQL, or internal paths.
|
|
175
|
+
* stack traces, SQL, or internal paths. Accepts `unknown` so callers
|
|
176
|
+
* pass response bodies / nested envelope fields directly without
|
|
177
|
+
* intermediate `as` casts; non-object bodies skip the field-name check.
|
|
176
178
|
*
|
|
177
179
|
* @param context - description for error messages
|
|
178
180
|
*/
|
|
179
181
|
export const assert_no_error_info_leakage = (body, context) => {
|
|
180
182
|
const body_str = JSON.stringify(body);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
if (body !== null && typeof body === 'object' && !Array.isArray(body)) {
|
|
184
|
+
for (const pattern of LEAKY_FIELD_PATTERNS) {
|
|
185
|
+
// check field names (not values — 'error' legitimately contains error codes)
|
|
186
|
+
for (const key of Object.keys(body)) {
|
|
187
|
+
assert.ok(!key.toLowerCase().includes(pattern), `${context}: error response field '${key}' matches leaky pattern '${pattern}'`);
|
|
188
|
+
}
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
191
|
// check for stack traces and file paths in values
|
|
@@ -25,8 +25,8 @@ export interface BearerAuthTestOptions {
|
|
|
25
25
|
mock_validate_result?: unknown;
|
|
26
26
|
/** What `query_account_by_id()` returns. */
|
|
27
27
|
mock_find_by_id_result?: unknown;
|
|
28
|
-
/** What `
|
|
29
|
-
|
|
28
|
+
/** What `query_actor_by_id()` returns. */
|
|
29
|
+
mock_find_actor_by_id_result?: unknown;
|
|
30
30
|
/** What `query_permit_find_active_for_actor()` returns. */
|
|
31
31
|
mock_permits_result?: unknown;
|
|
32
32
|
/** Expected HTTP status, or `'next'` if the middleware should call `next()`. */
|
|
@@ -40,11 +40,13 @@ export interface BearerAuthTestOptions {
|
|
|
40
40
|
export interface BearerAuthTestCase extends BearerAuthTestOptions {
|
|
41
41
|
/** Whether the request should reach token validation or be short-circuited. */
|
|
42
42
|
validate_expectation: 'called' | 'not_called';
|
|
43
|
-
/** If true, assert `
|
|
44
|
-
|
|
43
|
+
/** If true, assert `ACCOUNT_ID_KEY` was set and `CREDENTIAL_TYPE_KEY` is `'api_token'`. */
|
|
44
|
+
assert_account_set?: boolean;
|
|
45
|
+
/** Expected `ACCOUNT_ID_KEY` value when `assert_account_set` is true. */
|
|
46
|
+
expected_account_id?: string;
|
|
45
47
|
/** If set, assert `AUTH_API_TOKEN_ID_KEY` was set to this value after a successful bearer auth. */
|
|
46
48
|
expected_api_token_id?: string;
|
|
47
|
-
/** If true, assert the pre-existing session
|
|
49
|
+
/** If true, assert the pre-existing session `ACCOUNT_ID_KEY` and credential type are preserved. */
|
|
48
50
|
assert_context_preserved?: boolean;
|
|
49
51
|
/** Optional callback for custom spy assertions on the mocks bundle. */
|
|
50
52
|
assert_mocks?: (mocks: BearerAuthMocks) => void;
|
|
@@ -53,14 +55,15 @@ export interface BearerAuthTestCase extends BearerAuthTestOptions {
|
|
|
53
55
|
export interface BearerAuthMocks {
|
|
54
56
|
mock_validate: ReturnType<typeof vi.fn>;
|
|
55
57
|
mock_find_by_id: ReturnType<typeof vi.fn>;
|
|
56
|
-
|
|
58
|
+
mock_find_actor_by_id: ReturnType<typeof vi.fn>;
|
|
59
|
+
mock_find_actors_by_account: ReturnType<typeof vi.fn>;
|
|
57
60
|
mock_find_active_for_actor: ReturnType<typeof vi.fn>;
|
|
58
61
|
}
|
|
59
62
|
/**
|
|
60
63
|
* Create mock dependencies for `create_bearer_auth_middleware`, configured per test case.
|
|
61
64
|
*
|
|
62
65
|
* Configures the module-level mocks for `query_validate_api_token`,
|
|
63
|
-
* `query_account_by_id`, `
|
|
66
|
+
* `query_account_by_id`, `query_actor_by_id`, and `query_permit_find_active_for_actor`
|
|
64
67
|
* so each test case controls return values independently.
|
|
65
68
|
*
|
|
66
69
|
* @returns mocks bundle with spy references
|
|
@@ -105,7 +108,8 @@ export interface TestMiddlewareStackApp {
|
|
|
105
108
|
app: Hono;
|
|
106
109
|
mock_validate: ReturnType<typeof vi.fn>;
|
|
107
110
|
mock_find_by_id: ReturnType<typeof vi.fn>;
|
|
108
|
-
|
|
111
|
+
mock_find_actor_by_id: ReturnType<typeof vi.fn>;
|
|
112
|
+
mock_find_actors_by_account: ReturnType<typeof vi.fn>;
|
|
109
113
|
mock_find_active_for_actor: ReturnType<typeof vi.fn>;
|
|
110
114
|
}
|
|
111
115
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,EAAC,EAAE,EAAyB,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAC1B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B;;;;;;;;GAQG;AAEH,OAAO,EAAC,EAAE,EAAyB,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAC1B,OAAO,KAAK,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAc3B,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AA2BpF,gEAAgE;AAChE,MAAM,WAAW,qBAAqB;IACrC,wBAAwB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,oEAAoE;IACpE,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,0CAA0C;IAC1C,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gFAAgF;IAChF,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+GAA+G;IAC/G,qBAAqB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;CAClC;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAChE,+EAA+E;IAC/E,oBAAoB,EAAE,QAAQ,GAAG,YAAY,CAAC;IAC9C,2FAA2F;IAC3F,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mGAAmG;IACnG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mGAAmG;IACnG,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,uEAAuE;IACvE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;CAChD;AAID,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,eAAe,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1C,qBAAqB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,2BAA2B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,0BAA0B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACrD;AAKD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,GAAI,IAAI,qBAAqB,KAAG,eAoCpE,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,GACvC,IAAI,qBAAqB,EACzB,kBAAiB,WAAW,GAAG,IAAW,KACxC;IAAC,GAAG,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAwDpC,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,GACtC,YAAY,MAAM,EAClB,OAAO,KAAK,CAAC,kBAAkB,CAAC,EAChC,kBAAiB,WAAW,GAAG,IAAW,KACxC,IAyEF,CAAC;AAIF,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,sDAAsD;AACtD,MAAM,WAAW,0BAA0B;IAC1C,iDAAiD;IACjD,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,oFAAoF;IACpF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD,oDAAoD;IACpD,eAAe,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACrC;AAED,yDAAyD;AACzD,MAAM,WAAW,sBAAsB;IACtC,GAAG,EAAE,IAAI,CAAC;IACV,aAAa,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACxC,eAAe,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1C,qBAAqB,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,2BAA2B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACtD,0BAA0B,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;CACrD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC,GAC5C,UAAU,0BAA0B,KAClC,sBA4DF,CAAC"}
|
|
@@ -13,12 +13,12 @@ import { Hono } from 'hono';
|
|
|
13
13
|
import { Logger } from '@fuzdev/fuz_util/log.js';
|
|
14
14
|
import { create_bearer_auth_middleware } from '../auth/bearer_auth.js';
|
|
15
15
|
import { query_validate_api_token } from '../auth/api_token_queries.js';
|
|
16
|
-
import { query_account_by_id,
|
|
16
|
+
import { query_account_by_id, query_actor_by_id, query_actors_by_account, } from '../auth/account_queries.js';
|
|
17
17
|
import { query_permit_find_active_for_actor } from '../auth/permit_queries.js';
|
|
18
18
|
import { create_proxy_middleware, get_client_ip } from '../http/proxy.js';
|
|
19
19
|
import { verify_request_source, parse_allowed_origins } from '../http/origin.js';
|
|
20
20
|
import { REQUEST_CONTEXT_KEY } from '../auth/request_context.js';
|
|
21
|
-
import { AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
21
|
+
import { ACCOUNT_ID_KEY, AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY, } from '../hono_context.js';
|
|
22
22
|
import { ApiError } from '../http/error_schemas.js';
|
|
23
23
|
// Mock the query modules so test cases can control return values.
|
|
24
24
|
// vi.mock() is hoisted by vitest, so these run before any imports resolve.
|
|
@@ -27,7 +27,8 @@ vi.mock('../auth/api_token_queries.js', () => ({
|
|
|
27
27
|
}));
|
|
28
28
|
vi.mock('../auth/account_queries.js', () => ({
|
|
29
29
|
query_account_by_id: vi.fn(),
|
|
30
|
-
|
|
30
|
+
query_actor_by_id: vi.fn(),
|
|
31
|
+
query_actors_by_account: vi.fn(),
|
|
31
32
|
}));
|
|
32
33
|
vi.mock('../auth/permit_queries.js', () => ({
|
|
33
34
|
query_permit_find_active_for_actor: vi.fn(),
|
|
@@ -38,7 +39,7 @@ const STUB_DEPS = { db: {} };
|
|
|
38
39
|
* Create mock dependencies for `create_bearer_auth_middleware`, configured per test case.
|
|
39
40
|
*
|
|
40
41
|
* Configures the module-level mocks for `query_validate_api_token`,
|
|
41
|
-
* `query_account_by_id`, `
|
|
42
|
+
* `query_account_by_id`, `query_actor_by_id`, and `query_permit_find_active_for_actor`
|
|
42
43
|
* so each test case controls return values independently.
|
|
43
44
|
*
|
|
44
45
|
* @returns mocks bundle with spy references
|
|
@@ -49,7 +50,8 @@ const STUB_DEPS = { db: {} };
|
|
|
49
50
|
export const create_bearer_auth_mocks = (tc) => {
|
|
50
51
|
const mock_validate = vi.mocked(query_validate_api_token);
|
|
51
52
|
const mock_find_by_id = vi.mocked(query_account_by_id);
|
|
52
|
-
const
|
|
53
|
+
const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
|
|
54
|
+
const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
|
|
53
55
|
const mock_find_active_for_actor = vi.mocked(query_permit_find_active_for_actor);
|
|
54
56
|
mock_validate
|
|
55
57
|
.mockReset()
|
|
@@ -57,13 +59,28 @@ export const create_bearer_auth_mocks = (tc) => {
|
|
|
57
59
|
mock_find_by_id
|
|
58
60
|
.mockReset()
|
|
59
61
|
.mockImplementation(() => Promise.resolve(tc.mock_find_by_id_result));
|
|
60
|
-
|
|
62
|
+
mock_find_actor_by_id
|
|
61
63
|
.mockReset()
|
|
62
|
-
.mockImplementation(() => Promise.resolve(tc.
|
|
64
|
+
.mockImplementation(() => Promise.resolve(tc.mock_find_actor_by_id_result));
|
|
65
|
+
// `resolve_acting_actor` enumerates actors. Default: wrap the
|
|
66
|
+
// `mock_find_actor_by_id_result` in a single-element array so
|
|
67
|
+
// single-actor account scenarios resolve transparently; empty when
|
|
68
|
+
// the actor mock is undefined/null. Multi-actor scenarios should
|
|
69
|
+
// override this directly via `mockResolvedValue`.
|
|
70
|
+
mock_find_actors_by_account.mockReset().mockImplementation(() => {
|
|
71
|
+
const actor = tc.mock_find_actor_by_id_result;
|
|
72
|
+
return Promise.resolve(actor ? [actor] : []);
|
|
73
|
+
});
|
|
63
74
|
mock_find_active_for_actor
|
|
64
75
|
.mockReset()
|
|
65
76
|
.mockImplementation(() => Promise.resolve(tc.mock_permits_result ?? []));
|
|
66
|
-
return {
|
|
77
|
+
return {
|
|
78
|
+
mock_validate,
|
|
79
|
+
mock_find_by_id,
|
|
80
|
+
mock_find_actor_by_id,
|
|
81
|
+
mock_find_actors_by_account,
|
|
82
|
+
mock_find_active_for_actor,
|
|
83
|
+
};
|
|
67
84
|
};
|
|
68
85
|
/** Default client IP set by the proxy stub in test apps. */
|
|
69
86
|
export const TEST_CLIENT_IP = '127.0.0.1';
|
|
@@ -77,11 +94,19 @@ export const create_bearer_auth_test_app = (tc, ip_rate_limiter = null) => {
|
|
|
77
94
|
const mocks = create_bearer_auth_mocks(tc);
|
|
78
95
|
const bearer_middleware = create_bearer_auth_middleware(STUB_DEPS, ip_rate_limiter, new Logger('test', { level: 'off' }));
|
|
79
96
|
const app = new Hono();
|
|
80
|
-
// inject pre-existing
|
|
97
|
+
// inject pre-existing session identity if the test case specifies one.
|
|
98
|
+
// `pre_context` simulates the session middleware having authenticated
|
|
99
|
+
// the caller — sets `ACCOUNT_ID_KEY` (the account-grain identity bearer
|
|
100
|
+
// auth checks) and the legacy `REQUEST_CONTEXT_KEY` (preserved through
|
|
101
|
+
// the bearer middleware unchanged so consumer expectations on the full
|
|
102
|
+
// context shape stay testable).
|
|
81
103
|
if (tc.pre_context) {
|
|
104
|
+
const pre_context = tc.pre_context;
|
|
82
105
|
app.use('*', async (c, next) => {
|
|
83
|
-
c.set(
|
|
106
|
+
c.set(ACCOUNT_ID_KEY, pre_context.account.id);
|
|
107
|
+
c.set(REQUEST_CONTEXT_KEY, pre_context);
|
|
84
108
|
c.set(CREDENTIAL_TYPE_KEY, 'session');
|
|
109
|
+
c.set(TEST_CONTEXT_PRESET_KEY, true);
|
|
85
110
|
await next();
|
|
86
111
|
});
|
|
87
112
|
}
|
|
@@ -91,19 +116,22 @@ export const create_bearer_auth_test_app = (tc, ip_rate_limiter = null) => {
|
|
|
91
116
|
await next();
|
|
92
117
|
});
|
|
93
118
|
app.use('/api/*', bearer_middleware);
|
|
94
|
-
// route handler echoes
|
|
119
|
+
// route handler echoes the account-grain identity the middleware writes
|
|
120
|
+
// (bearer auth sets `ACCOUNT_ID_KEY` + `CREDENTIAL_TYPE_KEY` +
|
|
121
|
+
// `AUTH_API_TOKEN_ID_KEY`; it never builds the full request context —
|
|
122
|
+
// that is the dispatcher's authorization phase). `request_context_set`
|
|
123
|
+
// is only true when a test pre-populates it via `pre_context`.
|
|
95
124
|
app.get('/api/test', (c) => {
|
|
96
|
-
const
|
|
125
|
+
const account_id = c.get(ACCOUNT_ID_KEY);
|
|
97
126
|
const cred = c.get(CREDENTIAL_TYPE_KEY);
|
|
98
127
|
const api_token_id = c.get(AUTH_API_TOKEN_ID_KEY);
|
|
128
|
+
const ctx = c.get(REQUEST_CONTEXT_KEY);
|
|
99
129
|
return c.json({
|
|
100
130
|
ok: true,
|
|
101
|
-
|
|
131
|
+
account_id: account_id ?? null,
|
|
102
132
|
credential_type: cred ?? null,
|
|
103
|
-
account_id: ctx?.account.id ?? null,
|
|
104
|
-
actor_id: ctx?.actor.id ?? null,
|
|
105
|
-
permit_count: ctx?.permits.length ?? 0,
|
|
106
133
|
api_token_id: api_token_id ?? null,
|
|
134
|
+
request_context_set: ctx != null,
|
|
107
135
|
});
|
|
108
136
|
});
|
|
109
137
|
return { app, mocks };
|
|
@@ -141,15 +169,18 @@ export const describe_bearer_auth_cases = (suite_name, cases, ip_rate_limiter =
|
|
|
141
169
|
else {
|
|
142
170
|
assert.ok(mocks.mock_validate.mock.calls.length > 0, 'validate should have been called');
|
|
143
171
|
}
|
|
144
|
-
if (tc.
|
|
145
|
-
assert.
|
|
172
|
+
if (tc.assert_account_set) {
|
|
173
|
+
assert.ok(body.account_id, 'ACCOUNT_ID_KEY should be set');
|
|
174
|
+
if (tc.expected_account_id !== undefined) {
|
|
175
|
+
assert.strictEqual(body.account_id, tc.expected_account_id, 'ACCOUNT_ID_KEY should match the validated api_token.account_id');
|
|
176
|
+
}
|
|
146
177
|
assert.strictEqual(body.credential_type, 'api_token', 'CREDENTIAL_TYPE_KEY should be api_token');
|
|
147
178
|
}
|
|
148
179
|
if (tc.expected_api_token_id !== undefined) {
|
|
149
180
|
assert.strictEqual(body.api_token_id, tc.expected_api_token_id, 'AUTH_API_TOKEN_ID_KEY should match the validated api_token.id');
|
|
150
181
|
}
|
|
151
182
|
if (tc.assert_context_preserved) {
|
|
152
|
-
assert.
|
|
183
|
+
assert.ok(body.account_id, 'pre-existing account_id should be preserved');
|
|
153
184
|
assert.strictEqual(body.credential_type, 'session', 'credential type should remain session');
|
|
154
185
|
}
|
|
155
186
|
if (tc.assert_mocks) {
|
|
@@ -177,11 +208,13 @@ export const create_test_middleware_stack_app = (options) => {
|
|
|
177
208
|
const allowed_origins_str = options?.allowed_origins ?? 'https://app.example.com';
|
|
178
209
|
const mock_validate = vi.mocked(query_validate_api_token);
|
|
179
210
|
const mock_find_by_id = vi.mocked(query_account_by_id);
|
|
180
|
-
const
|
|
211
|
+
const mock_find_actor_by_id = vi.mocked(query_actor_by_id);
|
|
212
|
+
const mock_find_actors_by_account = vi.mocked(query_actors_by_account);
|
|
181
213
|
const mock_find_active_for_actor = vi.mocked(query_permit_find_active_for_actor);
|
|
182
214
|
mock_validate.mockReset().mockImplementation(() => Promise.resolve(undefined));
|
|
183
215
|
mock_find_by_id.mockReset().mockImplementation(() => Promise.resolve(undefined));
|
|
184
|
-
|
|
216
|
+
mock_find_actor_by_id.mockReset().mockImplementation(() => Promise.resolve(undefined));
|
|
217
|
+
mock_find_actors_by_account.mockReset().mockImplementation(() => Promise.resolve([]));
|
|
185
218
|
mock_find_active_for_actor.mockReset().mockImplementation(() => Promise.resolve([]));
|
|
186
219
|
const get_connection_ip = typeof options?.connection_ip === 'function'
|
|
187
220
|
? options.connection_ip
|
|
@@ -197,14 +230,23 @@ export const create_test_middleware_stack_app = (options) => {
|
|
|
197
230
|
app.use('*', proxy_mw);
|
|
198
231
|
app.use('/api/*', origin_mw);
|
|
199
232
|
app.use('/api/*', bearer_mw);
|
|
200
|
-
// echo route for assertions
|
|
233
|
+
// echo route for assertions — exposes the account-grain identity bearer
|
|
234
|
+
// auth writes (`ACCOUNT_ID_KEY`); the full request context is the
|
|
235
|
+
// dispatcher's authorization phase concern, not middleware.
|
|
201
236
|
app.get(TEST_MIDDLEWARE_PATH, (c) => {
|
|
202
|
-
const
|
|
237
|
+
const account_id = c.get(ACCOUNT_ID_KEY);
|
|
203
238
|
return c.json({
|
|
204
239
|
ok: true,
|
|
205
240
|
client_ip: get_client_ip(c),
|
|
206
|
-
|
|
241
|
+
account_id: account_id ?? null,
|
|
207
242
|
});
|
|
208
243
|
});
|
|
209
|
-
return {
|
|
244
|
+
return {
|
|
245
|
+
app,
|
|
246
|
+
mock_validate,
|
|
247
|
+
mock_find_by_id,
|
|
248
|
+
mock_find_actor_by_id,
|
|
249
|
+
mock_find_actors_by_account,
|
|
250
|
+
mock_find_active_for_actor,
|
|
251
|
+
};
|
|
210
252
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAa7B,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAC,qBAAqB,EAAE,mBAAmB,EAAE,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAG9D;;;;;;;;GAQG;AACH,MAAM,MAAM,uBAAuB,GAChC,KAAK,CAAC,eAAe,CAAC,GACtB,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,+BAA+B,GAC3C,eAAe,uBAAuB,EACtC,iBAAiB,cAAc,CAAC,MAAM,CAAC,KACrC,KAAK,CAAC,eAAe,CAuBvB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,oBAAoB,GAChC,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,WAQF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC9B,eAAe,MAAM,EACrB,QAAQ,MAAM,EACd,SAAS,OAAO,EAChB,KAAI,MAAM,GAAG,MAAe,KAC1B,MAMF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,GACzC,MAAM,OAAO,EACb,gBAAgB,gBAAgB,KAC9B,IAUF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,GAAI,MAAM,OAAO,EAAE,gBAAgB,CAAC,CAAC,OAAO,KAAG,
|
|
1
|
+
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,7 +119,9 @@ export const assert_jsonrpc_success_response = (body, output_schema) => {
|
|
|
119
119
|
assert.ok(result.success, `not a valid JSON-RPC success response: ${JSON.stringify(body)}`);
|
|
120
120
|
if (output_schema) {
|
|
121
121
|
const output_result = output_schema.safeParse(result.data.result);
|
|
122
|
-
|
|
122
|
+
if (!output_result.success) {
|
|
123
|
+
assert.fail(`JSON-RPC result does not match output schema: ${JSON.stringify(output_result.error.issues)}`);
|
|
124
|
+
}
|
|
123
125
|
}
|
|
124
126
|
};
|
|
125
127
|
/** Adapt a `Hono`-style app into an `RpcTestTransport`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAO,MAAM,MAAM,CAAC;AACxC,OAAO,EACN,SAAS,EAET,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAc,KAAK,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAEvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EAEN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,yBAAyB,EAAC,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAEpF,OAAO,
|
|
1
|
+
{"version":3,"file":"ws_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/ws_round_trip.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAO,MAAM,MAAM,CAAC;AACxC,OAAO,EACN,SAAS,EAET,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EACb,MAAM,SAAS,CAAC;AACjB,OAAO,EAAC,MAAM,EAAC,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAc,KAAK,IAAI,EAAC,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,4BAA4B,CAAC;AAEvD,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EAEN,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAC,yBAAyB,EAAC,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAsB,KAAK,cAAc,EAAC,MAAM,4BAA4B,CAAC;AAEpF,OAAO,EAKN,KAAK,cAAc,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AAanD;;;GAGG;AACH,MAAM,WAAW,MAAM;IACtB,EAAE,EAAE,SAAS,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,MAajC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,WAAW,sBAAsB;IACtC,eAAe,EAAE,cAAc,CAAC;IAChC,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAM,sBAAsB,KAAG,OAavE,CAAC;AAEF,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC3B,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC,CAAC,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtE;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAO,WAatC,CAAC;AAEF;;;;GAIG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;;IACtE,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAa;gBAEjC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC;IAGjD,qBAAqB,IAAI,SAAS;IAGlC,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;CAG/D;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC/B,YAAY,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAC9C,OAAO,YAAY,EACnB,IAAI,SAAS,KACX,OAAO,CAAC,IAAI,CAId,CAAC;AAMF,2CAA2C;AAC3C,MAAM,WAAW,iBAAiB;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,yFAAyF;IACzF,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,mFAAmF;IACnF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,kFAAkF;IAClF,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACtB;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC5B;;;;;OAKG;IACH,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C;;;;;;;;;;;OAWG;IACH,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EACpB,EAAE,EAAE,MAAM,GAAG,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,UAAU,CAAC,EAAE,MAAM,KACf,OAAO,CAAC,CAAC,CAAC,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C;;;;;;;;;;;;OAYG;IACH,QAAQ,EAAE;QACT,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,GAAG,IAAI,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE5E,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrF,CAAC;CACF;AAkBD,MAAM,WAAW,wBAAwB,CAAC,CAAC,GAAG,OAAO;IACpD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,2BAA2B,CAAC,CAAC,GAAG,OAAO;IACvD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC,GAAG,OAAO;IACrD,OAAO,EAAE,OAAO,eAAe,CAAC;IAChC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,CAAA;KAAC,CAAC;CACjD;AAED,6EAA6E;AAC7E,eAAO,MAAM,eAAe,GAC1B,QAAQ,MAAM,MACd,KAAK,OAAO,KAAG,OACsC,CAAC;AAExD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,GAC/B,CAAC,EAAE,QAAQ,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,MAChD,KAAK,OAAO,KAAG,GAAG,IAAI,wBAAwB,CAAC,CAAC,CAGE,CAAC;AAErD,gGAAgG;AAChG,eAAO,MAAM,eAAe,GAC1B,IAAI,MAAM,GAAG,MAAM,MACnB,KAAK,OAAO,KAAG,OAC8D,CAAC;AAEhF,4CAA4C;AAC5C,MAAM,WAAW,0BAA0B,CAAC,IAAI,SAAS,kBAAkB;IAC1E;;;;;OAKG;IACH,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACjE,kEAAkE;IAClE,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CAAC;IACvD,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,cAAc,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACjE,yDAAyD;IACzD,eAAe,CAAC,EAAE,uBAAuB,CAAC,IAAI,CAAC,CAAC,iBAAiB,CAAC,CAAC;CACnE;AAED,kEAAkE;AAClE,MAAM,WAAW,aAAa;IAC7B,SAAS,EAAE,yBAAyB,CAAC;IACrC;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,iBAAiB,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACjE;AA8DD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,GAAI,IAAI,SAAS,kBAAkB,EACrE,SAAS,0BAA0B,CAAC,IAAI,CAAC,KACvC,aA+KF,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,eAAe,QAAO,iBAGjC,CAAC;AAYH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,SAAS,MAAM,EAAE,SAAS;IACjE,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CACtC,KAAG,IAIH,CAAC"}
|
|
@@ -45,7 +45,7 @@ import { register_action_ws, } from '../actions/register_action_ws.js';
|
|
|
45
45
|
import { BackendWebsocketTransport } from '../actions/transports_ws_backend.js';
|
|
46
46
|
import { REQUEST_CONTEXT_KEY } from '../auth/request_context.js';
|
|
47
47
|
import { ROLE_KEEPER } from '../auth/role_schema.js';
|
|
48
|
-
import { AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY } from '../hono_context.js';
|
|
48
|
+
import { ACCOUNT_ID_KEY, AUTH_API_TOKEN_ID_KEY, CREDENTIAL_TYPE_KEY, TEST_CONTEXT_PRESET_KEY, } from '../hono_context.js';
|
|
49
49
|
import { JSONRPC_VERSION } from '../http/jsonrpc.js';
|
|
50
50
|
import { create_jsonrpc_request, is_jsonrpc_error_response, is_jsonrpc_notification, is_jsonrpc_response, } from '../http/jsonrpc_helpers.js';
|
|
51
51
|
import { create_test_account, create_test_actor, create_test_permit } from './entities.js';
|
|
@@ -76,10 +76,12 @@ export const create_fake_ws = () => {
|
|
|
76
76
|
export const create_fake_hono_context = (opts) => {
|
|
77
77
|
const request_context = opts.request_context ?? build_simple_request_context(opts.role);
|
|
78
78
|
const vars = {
|
|
79
|
+
[ACCOUNT_ID_KEY]: request_context.account.id,
|
|
79
80
|
[REQUEST_CONTEXT_KEY]: request_context,
|
|
80
81
|
[CREDENTIAL_TYPE_KEY]: opts.credential_type,
|
|
81
82
|
auth_session_id: opts.auth_session_id ?? (opts.credential_type === 'session' ? 's1' : null),
|
|
82
83
|
[AUTH_API_TOKEN_ID_KEY]: opts.api_token_id ?? null,
|
|
84
|
+
[TEST_CONTEXT_PRESET_KEY]: true,
|
|
83
85
|
};
|
|
84
86
|
return {
|
|
85
87
|
get: (key) => vars[key],
|
|
@@ -244,10 +246,12 @@ export const create_ws_test_harness = (options) => {
|
|
|
244
246
|
const api_token_id = identity.api_token_id ?? null;
|
|
245
247
|
const roles = identity.roles ?? [];
|
|
246
248
|
const ctx_store = new Map([
|
|
249
|
+
[ACCOUNT_ID_KEY, account_id],
|
|
247
250
|
[REQUEST_CONTEXT_KEY, build_multi_role_request_context(account_id, roles)],
|
|
248
251
|
[CREDENTIAL_TYPE_KEY, credential_type],
|
|
249
252
|
['auth_session_id', session_id],
|
|
250
253
|
[AUTH_API_TOKEN_ID_KEY, api_token_id],
|
|
254
|
+
[TEST_CONTEXT_PRESET_KEY, true],
|
|
251
255
|
]);
|
|
252
256
|
const fake_c = {
|
|
253
257
|
get: (key) => ctx_store.get(key),
|
package/dist/ui/CLAUDE.md
CHANGED
|
@@ -169,12 +169,16 @@ destructive actions.
|
|
|
169
169
|
Accept is a `PendingButton`; decline is a `ConfirmButton` whose
|
|
170
170
|
popover contains a textarea (max `PERMIT_OFFER_MESSAGE_LENGTH_MAX`).
|
|
171
171
|
- `PermitOfferForm.svelte` — grantor-side create form. Props:
|
|
172
|
-
`to_account_id`, `
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
`
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
`to_account_id`, `to_actor_id = null` (optional — narrows the offer
|
|
173
|
+
to a specific actor on the recipient account; default account-grain),
|
|
174
|
+
`roles: Array<string>` (pre-filtered upstream by `web_grantable`),
|
|
175
|
+
`scope_id = null`, `on_created?`, `format_role?`. Surfaces five
|
|
176
|
+
reason codes with friendly copy: `ERROR_OFFER_SELF_TARGET`,
|
|
177
|
+
`ERROR_OFFER_ROLE_NOT_GRANTABLE`, `ERROR_OFFER_NOT_AUTHORIZED`,
|
|
178
|
+
`ERROR_OFFER_ACTOR_ACCOUNT_MISMATCH`, `ERROR_OFFER_ACTOR_MISMATCH`
|
|
179
|
+
— imported from `../auth/permit_offer_action_specs.js` (see
|
|
180
|
+
`../auth/CLAUDE.md` for `permit_offer_action_specs.ts` +
|
|
181
|
+
`permit_offer_actions.ts`).
|
|
178
182
|
- `PermitOfferHistory.svelte` — both-directions history (recipient +
|
|
179
183
|
grantor, including terminal). Props: `current_actor_id: string | null`
|
|
180
184
|
(classifies row as "sent" vs "received"), `format_actor?`,
|
|
@@ -247,10 +251,12 @@ destructive actions.
|
|
|
247
251
|
`revoke_permit`, `retract_offer`, `session_revoke_all`,
|
|
248
252
|
`token_revoke_all` — the last two are also reused by
|
|
249
253
|
`AdminSessionsState`). `SvelteSet`s for in-flight tracking:
|
|
250
|
-
`granting_keys` (`${account_id}:${role}`
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
+
`granting_keys` (`${account_id}:${role}` for the account-grain
|
|
255
|
+
default; `${account_id}:${role}:${to_actor_id}` when `grant_permit`
|
|
256
|
+
is called with an actor-targeted offer), `revoking_ids` (permit id),
|
|
257
|
+
`retracting_ids` (offer id). `revoke_permit` keys on `actor_id`
|
|
258
|
+
(permits are actor-scoped — matches `row.actor.id` straight from the
|
|
259
|
+
listing) with optional `reason`.
|
|
254
260
|
- `admin_invites_state.svelte.ts` — `AdminInvitesState` extends
|
|
255
261
|
`Loadable` + `admin_invites_rpc_context` + narrow
|
|
256
262
|
`AdminInvitesRpc` (`list`, `create`, `delete`). Fields:
|