@fuzdev/fuz_app 0.147.0 → 0.149.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 +8 -6
- package/dist/actions/action_codegen.d.ts +15 -1
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +23 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +14 -1
- package/dist/actions/perform_action.d.ts +17 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +23 -3
- package/dist/auth/CLAUDE.md +3 -2
- package/dist/auth/account_action_specs.d.ts +12 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +16 -2
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +7 -4
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +29 -8
- package/dist/auth/audit_emitter.d.ts +14 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +5 -1
- package/dist/auth/cell_action_specs.d.ts +3 -1
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +5 -5
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +2 -3
- package/dist/auth/cell_data_schema.d.ts +1 -1
- package/dist/auth/cell_data_schema.js +1 -1
- package/dist/auth/cell_field_action_specs.d.ts +4 -3
- package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_field_action_specs.js +5 -6
- package/dist/auth/cell_field_actions.d.ts.map +1 -1
- package/dist/auth/cell_field_actions.js +8 -1
- package/dist/auth/cell_item_action_specs.d.ts +4 -2
- package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_item_action_specs.js +5 -5
- package/dist/auth/cell_item_actions.d.ts.map +1 -1
- package/dist/auth/cell_item_actions.js +8 -1
- package/dist/auth/role_grant_offer_action_specs.d.ts +2 -0
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +8 -4
- package/dist/http/CLAUDE.md +14 -2
- package/dist/http/error_schemas.d.ts +8 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +12 -0
- package/dist/http/jsonrpc_errors.d.ts +40 -15
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +90 -35
- package/dist/primitive_schemas.d.ts +1 -1
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +2 -1
- package/dist/schema_meta.d.ts +80 -0
- package/dist/schema_meta.d.ts.map +1 -1
- package/dist/schema_meta.js +71 -1
- package/dist/testing/CLAUDE.md +853 -146
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +73 -5
- package/dist/testing/adversarial_input.d.ts +0 -47
- package/dist/testing/adversarial_input.d.ts.map +1 -1
- package/dist/testing/adversarial_input.js +4 -340
- package/dist/testing/adversarial_input_cases.d.ts +124 -0
- package/dist/testing/adversarial_input_cases.d.ts.map +1 -0
- package/dist/testing/adversarial_input_cases.js +393 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +24 -20
- package/dist/testing/audit_drift_guard.d.ts +30 -3
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +55 -3
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +29 -12
- package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
- package/dist/testing/cross_backend/actor_lookup.js +7 -25
- package/dist/testing/cross_backend/app_settings.d.ts.map +1 -1
- package/dist/testing/cross_backend/app_settings.js +4 -6
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts +57 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/audit_cross_helpers.js +89 -0
- package/dist/testing/cross_backend/backend_config.d.ts +2 -1
- package/dist/testing/cross_backend/backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.d.ts +6 -0
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +26 -44
- package/dist/testing/cross_backend/body_size_smuggling.d.ts +5 -0
- package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size_smuggling.js +7 -14
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts +3 -1
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.d.ts +78 -59
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +25 -24
- package/dist/testing/cross_backend/cargo_binary.d.ts +70 -0
- package/dist/testing/cross_backend/cargo_binary.d.ts.map +1 -0
- package/dist/testing/cross_backend/cargo_binary.js +148 -0
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +174 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts +0 -60
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +9 -487
- package/dist/testing/cross_backend/cell_grant_role.d.ts +14 -2
- package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_grant_role.js +22 -12
- package/dist/testing/cross_backend/cell_moderate.d.ts +66 -0
- package/dist/testing/cross_backend/cell_moderate.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_moderate.js +511 -0
- package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_ref_admission.js +1 -1
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.js +40 -19
- package/dist/testing/cross_backend/conformance_case.d.ts +43 -4
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_case.js +29 -1
- package/dist/testing/cross_backend/conformance_rpc_auth.d.ts +93 -0
- package/dist/testing/cross_backend/conformance_rpc_auth.d.ts.map +1 -0
- package/dist/testing/cross_backend/conformance_rpc_auth.js +125 -0
- package/dist/testing/cross_backend/conformance_table.d.ts +144 -4
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +297 -65
- package/dist/testing/cross_backend/cookie_attributes.d.ts.map +1 -1
- package/dist/testing/cross_backend/cookie_attributes.js +3 -2
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +38 -5
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/create_cross_backend_global_setup.js +24 -3
- package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +5 -5
- package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_deadline.d.ts +10 -6
- package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_deadline.js +32 -31
- package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_header_robustness.js +4 -6
- package/dist/testing/cross_backend/{cell_cross_helpers.d.ts → cross_rpc.d.ts} +14 -2
- package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -0
- package/dist/testing/cross_backend/{cell_cross_helpers.js → cross_rpc.js} +31 -7
- package/dist/testing/cross_backend/default_backend_configs.d.ts +58 -61
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +97 -91
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_spine_surface.js +2 -2
- package/dist/testing/cross_backend/differential.d.ts +126 -0
- package/dist/testing/cross_backend/differential.d.ts.map +1 -0
- package/dist/testing/cross_backend/differential.js +201 -0
- package/dist/testing/cross_backend/differential_normalize.d.ts +150 -0
- package/dist/testing/cross_backend/differential_normalize.d.ts.map +1 -0
- package/dist/testing/cross_backend/differential_normalize.js +153 -0
- package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
- package/dist/testing/cross_backend/fact_serving.js +27 -17
- package/dist/testing/cross_backend/full_spine_mount.d.ts +15 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +55 -1
- package/dist/testing/cross_backend/identity_parity.d.ts.map +1 -1
- package/dist/testing/cross_backend/identity_parity.js +6 -5
- package/dist/testing/cross_backend/in_process_setup.d.ts +12 -2
- package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/in_process_setup.js +10 -7
- package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
- package/dist/testing/cross_backend/login_security.js +13 -18
- package/dist/testing/cross_backend/origin.js +1 -1
- package/dist/testing/cross_backend/origin_conformance.js +1 -1
- package/dist/testing/cross_backend/origin_scope.d.ts +6 -0
- package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin_scope.js +13 -12
- package/dist/testing/cross_backend/peer_ping_ws.d.ts +2 -5
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +14 -24
- package/dist/testing/cross_backend/postgres_database.d.ts +85 -0
- package/dist/testing/cross_backend/postgres_database.d.ts.map +1 -0
- package/dist/testing/cross_backend/postgres_database.js +140 -0
- package/dist/testing/cross_backend/provided_context.d.ts +28 -0
- package/dist/testing/cross_backend/provided_context.d.ts.map +1 -0
- package/dist/testing/cross_backend/provided_context.js +35 -0
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
- package/dist/testing/cross_backend/query_shape.js +10 -12
- package/dist/testing/cross_backend/ready.js +2 -2
- package/dist/testing/cross_backend/revocation_drivers.d.ts +4 -3
- package/dist/testing/cross_backend/revocation_drivers.d.ts.map +1 -1
- package/dist/testing/cross_backend/revocation_drivers.js +1 -1
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +3 -2
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts +13 -0
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.js +203 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +2 -5
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +203 -111
- package/dist/testing/cross_backend/role_grant_participation.d.ts +13 -0
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +32 -21
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_role_grammar.js +6 -9
- package/dist/testing/cross_backend/rpc_adversarial.d.ts +47 -0
- package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -0
- package/dist/testing/cross_backend/rpc_adversarial.js +302 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.d.ts +24 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.d.ts.map +1 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.js +124 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +101 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts.map +1 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.js +113 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +10 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +33 -21
- package/dist/testing/cross_backend/session_cap.d.ts +9 -8
- package/dist/testing/cross_backend/session_cap.d.ts.map +1 -1
- package/dist/testing/cross_backend/session_cap.js +9 -4
- package/dist/testing/cross_backend/session_cookie_codec.js +1 -1
- package/dist/testing/cross_backend/setup.d.ts +58 -56
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +29 -29
- package/dist/testing/cross_backend/simple_request.d.ts.map +1 -1
- package/dist/testing/cross_backend/simple_request.js +4 -4
- package/dist/testing/cross_backend/spawn_backend.d.ts +59 -10
- package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
- package/dist/testing/cross_backend/spawn_backend.js +219 -60
- package/dist/testing/cross_backend/spine_suites.d.ts +311 -0
- package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -0
- package/dist/testing/cross_backend/spine_suites.js +897 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +44 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +53 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/sse_round_trip.js +3 -4
- package/dist/testing/cross_backend/standard.d.ts +18 -1
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +2 -0
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts +24 -0
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +15 -0
- package/dist/testing/cross_backend/testing_backdoor.d.ts +29 -12
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +143 -51
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -14
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +58 -37
- package/dist/testing/cross_backend/testing_server_bun.js +1 -1
- package/dist/testing/cross_backend/token_lifetime.js +1 -1
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_scope_surface.js +9 -13
- package/dist/testing/cross_backend/transport_composition.d.ts +26 -2
- package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -1
- package/dist/testing/cross_backend/transport_composition.js +81 -51
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +8 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +23 -13
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +2 -5
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_action_rate_limit.js +8 -14
- package/dist/testing/cross_backend/ws_connection_cap.d.ts +4 -9
- package/dist/testing/cross_backend/ws_connection_cap.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_connection_cap.js +11 -12
- package/dist/testing/cross_backend/ws_endpoint.d.ts +52 -0
- package/dist/testing/cross_backend/ws_endpoint.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_endpoint.js +54 -0
- package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts +2 -5
- package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_inbound_dispatch.js +9 -15
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +2 -7
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_outbound_overflow.js +5 -9
- package/dist/testing/cross_backend/ws_role_gated.d.ts +4 -5
- package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_role_gated.js +12 -21
- package/dist/testing/cross_backend/ws_round_trip.d.ts +12 -9
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +29 -34
- package/dist/testing/db_entities.d.ts +16 -3
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +28 -5
- package/dist/testing/integration_helpers.d.ts +61 -2
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +75 -18
- package/dist/testing/round_trip.d.ts +17 -0
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +67 -24
- package/dist/testing/rpc_attack_surface.d.ts +10 -0
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +27 -140
- package/dist/testing/rpc_envelope_cases.d.ts +114 -0
- package/dist/testing/rpc_envelope_cases.d.ts.map +1 -0
- package/dist/testing/rpc_envelope_cases.js +243 -0
- package/dist/testing/rpc_helpers.d.ts +31 -0
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +35 -14
- package/dist/testing/rpc_round_trip.d.ts +62 -6
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +151 -39
- package/dist/testing/schema_generators.d.ts +99 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +261 -73
- package/dist/testing/standard.d.ts +26 -0
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +4 -1
- package/dist/testing/stubs.d.ts +4 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +6 -4
- package/dist/testing/transports/raw_http.d.ts +21 -0
- package/dist/testing/transports/raw_http.d.ts.map +1 -1
- package/dist/testing/transports/raw_http.js +30 -0
- package/dist/zod.d.ts +9 -0
- package/dist/zod.d.ts.map +1 -1
- package/dist/zod.js +20 -0
- package/package.json +6 -4
- package/dist/testing/cross_backend/actor_search.d.ts +0 -6
- package/dist/testing/cross_backend/actor_search.d.ts.map +0 -1
- package/dist/testing/cross_backend/actor_search.js +0 -90
- package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +0 -1
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { AppSurfaceRpcEndpoint, AppSurfaceRpcMethod } from '../http/surface.js';
|
|
4
|
+
import type { JsonrpcErrorCode, JsonrpcRequestId } from '../http/jsonrpc.js';
|
|
5
|
+
import { type InputTestCase, type InputTestCaseOptions } from './adversarial_input_cases.js';
|
|
6
|
+
/** The request id every envelope case sends where it sends one. */
|
|
7
|
+
export declare const RPC_ENVELOPE_PROBE_ID = "envelope_probe";
|
|
8
|
+
/**
|
|
9
|
+
* One malformed-envelope request and the refusal it owes.
|
|
10
|
+
*
|
|
11
|
+
* Data, so the in-process group here and the cross-process
|
|
12
|
+
* `describe_rpc_adversarial_cross_tests` run the same set.
|
|
13
|
+
*/
|
|
14
|
+
export interface RpcEnvelopeCase {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/**
|
|
17
|
+
* Who sends it: the principal `method`'s auth admits, so the envelope check
|
|
18
|
+
* is what refuses, or no credential at all — the ordering cases, where an
|
|
19
|
+
* answer of 401 would mean auth ran before the envelope check.
|
|
20
|
+
*/
|
|
21
|
+
readonly as: 'authorized' | 'anonymous';
|
|
22
|
+
/** The declared method whose auth picks the principal (`'authorized'`). */
|
|
23
|
+
readonly method: AppSurfaceRpcMethod;
|
|
24
|
+
/** A raw POST body, or a GET query string starting with `?`. */
|
|
25
|
+
readonly request: {
|
|
26
|
+
readonly verb: 'POST';
|
|
27
|
+
readonly body: string;
|
|
28
|
+
} | {
|
|
29
|
+
readonly verb: 'GET';
|
|
30
|
+
readonly query: string;
|
|
31
|
+
};
|
|
32
|
+
readonly expect: {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly code: JsonrpcErrorCode;
|
|
35
|
+
/** The echoed `id` — `null` where the request carries none the server can read. */
|
|
36
|
+
readonly id: JsonrpcRequestId | null;
|
|
37
|
+
/** `error.data.reason` exactly, or `null` to require it absent. */
|
|
38
|
+
readonly reason: string | null;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** Options for `create_rpc_envelope_cases`. */
|
|
42
|
+
export interface RpcEnvelopeCaseOptions {
|
|
43
|
+
/** Method names never chosen as a case's method. */
|
|
44
|
+
readonly skip_methods?: ReadonlyArray<string>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The JSON values that are neither an object nor `null`, one per JSON type —
|
|
48
|
+
* what a `GET` `?params=` can carry that no input schema admits.
|
|
49
|
+
*/
|
|
50
|
+
export declare const RPC_NON_OBJECT_PARAMS: ReadonlyArray<string>;
|
|
51
|
+
/** The `data.reason` the dispatchers answer a `GET` of a `side_effects` method with. */
|
|
52
|
+
export declare const rpc_get_side_effects_reason: (method: string) => string;
|
|
53
|
+
/**
|
|
54
|
+
* Build the malformed-envelope cases for one RPC endpoint — the dispatcher's
|
|
55
|
+
* envelope parse, method lookup, and GET read restriction.
|
|
56
|
+
*
|
|
57
|
+
* The POST cases and the GET read cases ride the endpoint's first read method
|
|
58
|
+
* (`side_effects: false`), the GET mutation cases its first mutation that
|
|
59
|
+
* needs an account. `_testing_*` and protocol methods are never chosen. A case
|
|
60
|
+
* whose method the endpoint lacks is left out.
|
|
61
|
+
*
|
|
62
|
+
* Every read (`side_effects: false`) gets a `GET` with each of
|
|
63
|
+
* `RPC_NON_OBJECT_PARAMS` → `invalid_params`: the query string is no envelope,
|
|
64
|
+
* so the dispatcher's params validation is what refuses it.
|
|
65
|
+
*
|
|
66
|
+
* Three cases pin an order against auth, sent with no credential: a `GET` of
|
|
67
|
+
* a mutating method is refused `invalid_request` (the read restriction runs
|
|
68
|
+
* after the method lookup and before authorization), a batch array is
|
|
69
|
+
* refused `invalid_request` with `id: null` (the envelope parse runs first,
|
|
70
|
+
* and batches are unsupported), and a `GET` with non-object params on a
|
|
71
|
+
* read requiring an identity is the 401 (params validation runs after authorization).
|
|
72
|
+
*
|
|
73
|
+
* @param endpoint - the endpoint from the generated surface
|
|
74
|
+
* @param options - methods never chosen
|
|
75
|
+
* @returns the cases, in a fixed order
|
|
76
|
+
*/
|
|
77
|
+
export declare const create_rpc_envelope_cases: (endpoint: AppSurfaceRpcEndpoint, options?: RpcEnvelopeCaseOptions) => Array<RpcEnvelopeCase>;
|
|
78
|
+
/**
|
|
79
|
+
* Build the `RequestInit` + path suffix for an envelope case.
|
|
80
|
+
*
|
|
81
|
+
* @param endpoint_path - the RPC endpoint path
|
|
82
|
+
* @param c - the case
|
|
83
|
+
* @param headers - auth headers to merge in
|
|
84
|
+
* @returns the URL (path + query for GET) and the init
|
|
85
|
+
*/
|
|
86
|
+
export declare const to_rpc_envelope_request: (endpoint_path: string, c: RpcEnvelopeCase, headers?: Record<string, string>) => {
|
|
87
|
+
url: string;
|
|
88
|
+
init: RequestInit;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Assert a response body is the refusal an envelope case owes: a well-formed
|
|
92
|
+
* JSON-RPC error envelope with the case's code, echoed id, and `data.reason`.
|
|
93
|
+
*
|
|
94
|
+
* @param status - the response's HTTP status
|
|
95
|
+
* @param body - the parsed response body
|
|
96
|
+
* @param c - the case
|
|
97
|
+
*/
|
|
98
|
+
export declare const assert_rpc_envelope_refusal: (status: number, body: unknown, c: RpcEnvelopeCase) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Generate the schema-invalid params cases for one RPC method's input.
|
|
101
|
+
*
|
|
102
|
+
* `generate_input_test_cases` minus its structural cases: a non-object body
|
|
103
|
+
* is a non-object `params`, which the JSON-RPC envelope refuses
|
|
104
|
+
* (`invalid_request`) before params validation runs, and the envelope cases
|
|
105
|
+
* cover it. Every case returned owes 400 `invalid_params`.
|
|
106
|
+
*
|
|
107
|
+
* @param input - the method's input schema
|
|
108
|
+
* @param options - a valid base `params` to seed the cases (`InputTestCaseOptions.base`),
|
|
109
|
+
* and the method name for error messages
|
|
110
|
+
* @returns the cases, each a `params` object
|
|
111
|
+
* @throws Error if the base `params`, seeded or generated, fails the input schema
|
|
112
|
+
*/
|
|
113
|
+
export declare const generate_rpc_params_test_cases: (input: z.ZodType, options?: InputTestCaseOptions) => Array<InputTestCase>;
|
|
114
|
+
//# sourceMappingURL=rpc_envelope_cases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc_envelope_cases.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_envelope_cases.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAe7B,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAK7E,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,MAAM,8BAA8B,CAAC;AAItC,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,mBAAmB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAAC;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EACb;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAChD;QAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE;QAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;QAChC,mFAAmF;QACnF,QAAQ,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,CAAC;QACrC,mEAAmE;QACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,CAAC;CACF;AAED,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACtC,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,MAAM,CAAgC,CAAC;AAEzF,wFAAwF;AACxF,eAAO,MAAM,2BAA2B,GAAI,QAAQ,MAAM,KAAG,MACL,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,yBAAyB,GACrC,UAAU,qBAAqB,EAC/B,UAAS,sBAA2B,KAClC,KAAK,CAAC,eAAe,CAmKvB,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,GACnC,eAAe,MAAM,EACrB,GAAG,eAAe,EAClB,UAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,KAClC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAUgD,CAAC;AAEpF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACvC,QAAQ,MAAM,EACd,MAAM,OAAO,EACb,GAAG,eAAe,KAChB,IAUF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,8BAA8B,GAC1C,OAAO,CAAC,CAAC,OAAO,EAChB,UAAU,oBAAoB,KAC5B,KAAK,CAAC,aAAa,CAGpB,CAAC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import './assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* The malformed-envelope and invalid-params cases for a JSON-RPC endpoint, as
|
|
4
|
+
* data.
|
|
5
|
+
*
|
|
6
|
+
* Hono-free, so the in-process `describe_rpc_attack_surface_tests` and the
|
|
7
|
+
* cross-process `describe_rpc_adversarial_cross_tests` run one set: the
|
|
8
|
+
* envelope cases (`create_rpc_envelope_cases`) and the per-method params
|
|
9
|
+
* cases (`generate_rpc_params_test_cases`).
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { assert } from 'vitest';
|
|
14
|
+
import { is_public_auth } from '../http/auth_shape.js';
|
|
15
|
+
import { JSONRPC_ERROR_CODES } from '../http/jsonrpc_errors.js';
|
|
16
|
+
import { ERROR_AUTHENTICATION_REQUIRED, ERROR_INVALID_JSON_BODY } from '../http/error_schemas.js';
|
|
17
|
+
import { PROTOCOL_ACTION_METHODS } from '../actions/action_codegen.js';
|
|
18
|
+
import { TESTING_METHOD_PREFIX } from './surface_invariants.js';
|
|
19
|
+
import { assert_jsonrpc_error_response } from './rpc_helpers.js';
|
|
20
|
+
import { generate_input_test_cases } from './adversarial_input_cases.js';
|
|
21
|
+
const PROTOCOL_METHODS = new Set(PROTOCOL_ACTION_METHODS);
|
|
22
|
+
/** The request id every envelope case sends where it sends one. */
|
|
23
|
+
export const RPC_ENVELOPE_PROBE_ID = 'envelope_probe';
|
|
24
|
+
/**
|
|
25
|
+
* The JSON values that are neither an object nor `null`, one per JSON type —
|
|
26
|
+
* what a `GET` `?params=` can carry that no input schema admits.
|
|
27
|
+
*/
|
|
28
|
+
export const RPC_NON_OBJECT_PARAMS = ['42', '[1]', '"x"', 'true'];
|
|
29
|
+
/** The `data.reason` the dispatchers answer a `GET` of a `side_effects` method with. */
|
|
30
|
+
export const rpc_get_side_effects_reason = (method) => `method '${method}' has side effects and must use POST`;
|
|
31
|
+
/**
|
|
32
|
+
* Build the malformed-envelope cases for one RPC endpoint — the dispatcher's
|
|
33
|
+
* envelope parse, method lookup, and GET read restriction.
|
|
34
|
+
*
|
|
35
|
+
* The POST cases and the GET read cases ride the endpoint's first read method
|
|
36
|
+
* (`side_effects: false`), the GET mutation cases its first mutation that
|
|
37
|
+
* needs an account. `_testing_*` and protocol methods are never chosen. A case
|
|
38
|
+
* whose method the endpoint lacks is left out.
|
|
39
|
+
*
|
|
40
|
+
* Every read (`side_effects: false`) gets a `GET` with each of
|
|
41
|
+
* `RPC_NON_OBJECT_PARAMS` → `invalid_params`: the query string is no envelope,
|
|
42
|
+
* so the dispatcher's params validation is what refuses it.
|
|
43
|
+
*
|
|
44
|
+
* Three cases pin an order against auth, sent with no credential: a `GET` of
|
|
45
|
+
* a mutating method is refused `invalid_request` (the read restriction runs
|
|
46
|
+
* after the method lookup and before authorization), a batch array is
|
|
47
|
+
* refused `invalid_request` with `id: null` (the envelope parse runs first,
|
|
48
|
+
* and batches are unsupported), and a `GET` with non-object params on a
|
|
49
|
+
* read requiring an identity is the 401 (params validation runs after authorization).
|
|
50
|
+
*
|
|
51
|
+
* @param endpoint - the endpoint from the generated surface
|
|
52
|
+
* @param options - methods never chosen
|
|
53
|
+
* @returns the cases, in a fixed order
|
|
54
|
+
*/
|
|
55
|
+
export const create_rpc_envelope_cases = (endpoint, options = {}) => {
|
|
56
|
+
const skip = new Set(options.skip_methods);
|
|
57
|
+
const eligible = endpoint.methods.filter((m) => !m.name.startsWith(TESTING_METHOD_PREFIX) &&
|
|
58
|
+
!PROTOCOL_METHODS.has(m.name) &&
|
|
59
|
+
!skip.has(m.name));
|
|
60
|
+
const read = eligible.find((m) => !m.side_effects);
|
|
61
|
+
const mutation = eligible.find((m) => m.side_effects && !is_public_auth(m.auth));
|
|
62
|
+
const id = RPC_ENVELOPE_PROBE_ID;
|
|
63
|
+
const cases = [];
|
|
64
|
+
if (read) {
|
|
65
|
+
const post = (name, body, expect) => {
|
|
66
|
+
cases.push({ name, as: 'authorized', method: read, request: { verb: 'POST', body }, expect });
|
|
67
|
+
};
|
|
68
|
+
const get = (name, query, expect) => {
|
|
69
|
+
cases.push({ name, as: 'authorized', method: read, request: { verb: 'GET', query }, expect });
|
|
70
|
+
};
|
|
71
|
+
const invalid_request = { status: 400, code: JSONRPC_ERROR_CODES.invalid_request };
|
|
72
|
+
const m = read.name;
|
|
73
|
+
const q = encodeURIComponent;
|
|
74
|
+
post('non-JSON body → parse_error', 'not-json', {
|
|
75
|
+
status: 400,
|
|
76
|
+
code: JSONRPC_ERROR_CODES.parse_error,
|
|
77
|
+
id: null,
|
|
78
|
+
reason: null
|
|
79
|
+
});
|
|
80
|
+
post('wrong jsonrpc version → invalid_request', JSON.stringify({ jsonrpc: '1.0', id, method: m }), { ...invalid_request, id, reason: null });
|
|
81
|
+
post('missing jsonrpc field → invalid_request', JSON.stringify({ id, method: m }), {
|
|
82
|
+
...invalid_request,
|
|
83
|
+
id,
|
|
84
|
+
reason: null
|
|
85
|
+
});
|
|
86
|
+
post('missing method field → invalid_request', JSON.stringify({ jsonrpc: '2.0', id }), {
|
|
87
|
+
...invalid_request,
|
|
88
|
+
id,
|
|
89
|
+
reason: null
|
|
90
|
+
});
|
|
91
|
+
post('missing id field → invalid_request', JSON.stringify({ jsonrpc: '2.0', method: m }), {
|
|
92
|
+
...invalid_request,
|
|
93
|
+
id: null,
|
|
94
|
+
reason: null
|
|
95
|
+
});
|
|
96
|
+
post('batch (array) body → invalid_request', JSON.stringify([{ jsonrpc: '2.0', id, method: m }]), { ...invalid_request, id: null, reason: null });
|
|
97
|
+
post('unknown method name → method_not_found', JSON.stringify({ jsonrpc: '2.0', id, method: '__nonexistent_method__' }), { status: 404, code: JSONRPC_ERROR_CODES.method_not_found, id, reason: null });
|
|
98
|
+
get('GET missing method → invalid_request', `?id=${id}`, {
|
|
99
|
+
...invalid_request,
|
|
100
|
+
id: null,
|
|
101
|
+
reason: 'missing method query parameter'
|
|
102
|
+
});
|
|
103
|
+
get('GET missing id → invalid_request', `?method=${q(m)}`, {
|
|
104
|
+
...invalid_request,
|
|
105
|
+
id: null,
|
|
106
|
+
reason: 'missing id query parameter'
|
|
107
|
+
});
|
|
108
|
+
get('GET invalid JSON params → invalid_params', `?method=${q(m)}&id=${id}¶ms=not-json`, {
|
|
109
|
+
status: 400,
|
|
110
|
+
code: JSONRPC_ERROR_CODES.invalid_params,
|
|
111
|
+
id,
|
|
112
|
+
reason: null
|
|
113
|
+
});
|
|
114
|
+
// a present non-object `params` fails the envelope schema on POST
|
|
115
|
+
post('POST non-object params → invalid_request', JSON.stringify({ jsonrpc: '2.0', id, method: m, params: 42 }), { ...invalid_request, id, reason: null });
|
|
116
|
+
}
|
|
117
|
+
// The GET query string is no envelope, so a non-object `params` reaches the
|
|
118
|
+
// dispatcher's params validation — on every read, since a spine that decodes
|
|
119
|
+
// params per handler can drift on any of them.
|
|
120
|
+
for (const r of eligible) {
|
|
121
|
+
if (r.side_effects)
|
|
122
|
+
continue;
|
|
123
|
+
for (const value of RPC_NON_OBJECT_PARAMS) {
|
|
124
|
+
cases.push({
|
|
125
|
+
name: `GET non-object params (${value}) → invalid_params: ${r.name}`,
|
|
126
|
+
as: 'authorized',
|
|
127
|
+
method: r,
|
|
128
|
+
request: {
|
|
129
|
+
verb: 'GET',
|
|
130
|
+
query: `?method=${encodeURIComponent(r.name)}&id=${id}¶ms=${encodeURIComponent(value)}`
|
|
131
|
+
},
|
|
132
|
+
expect: { status: 400, code: JSONRPC_ERROR_CODES.invalid_params, id, reason: null }
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// params validation runs after authorization: an anonymous non-object
|
|
137
|
+
// `params` hears the 401 of any anonymous call, not a 400 about its input.
|
|
138
|
+
// The read must require an identity — an identity-optional one admits the
|
|
139
|
+
// anonymous caller, whose params validation then refuses
|
|
140
|
+
const protected_read = eligible.find((r) => !r.side_effects && (r.auth.account === 'required' || r.auth.actor === 'required'));
|
|
141
|
+
if (protected_read) {
|
|
142
|
+
cases.push({
|
|
143
|
+
name: 'ordering: anonymous GET non-object params → 401, not invalid_params',
|
|
144
|
+
as: 'anonymous',
|
|
145
|
+
method: protected_read,
|
|
146
|
+
request: {
|
|
147
|
+
verb: 'GET',
|
|
148
|
+
query: `?method=${encodeURIComponent(protected_read.name)}&id=${id}¶ms=42`
|
|
149
|
+
},
|
|
150
|
+
expect: {
|
|
151
|
+
status: 401,
|
|
152
|
+
code: JSONRPC_ERROR_CODES.unauthenticated,
|
|
153
|
+
id,
|
|
154
|
+
reason: ERROR_AUTHENTICATION_REQUIRED
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (mutation) {
|
|
159
|
+
const query = `?method=${encodeURIComponent(mutation.name)}&id=${id}`;
|
|
160
|
+
const expect = {
|
|
161
|
+
status: 400,
|
|
162
|
+
code: JSONRPC_ERROR_CODES.invalid_request,
|
|
163
|
+
id,
|
|
164
|
+
reason: rpc_get_side_effects_reason(mutation.name)
|
|
165
|
+
};
|
|
166
|
+
cases.push({
|
|
167
|
+
name: 'GET mutation method → invalid_request (side effects)',
|
|
168
|
+
as: 'authorized',
|
|
169
|
+
method: mutation,
|
|
170
|
+
request: { verb: 'GET', query },
|
|
171
|
+
expect
|
|
172
|
+
});
|
|
173
|
+
cases.push({
|
|
174
|
+
name: 'ordering: anonymous GET mutation method → invalid_request, not 401',
|
|
175
|
+
as: 'anonymous',
|
|
176
|
+
method: mutation,
|
|
177
|
+
request: { verb: 'GET', query },
|
|
178
|
+
expect
|
|
179
|
+
});
|
|
180
|
+
cases.push({
|
|
181
|
+
name: 'ordering: anonymous batch (array) body → invalid_request, not 401',
|
|
182
|
+
as: 'anonymous',
|
|
183
|
+
method: mutation,
|
|
184
|
+
request: {
|
|
185
|
+
verb: 'POST',
|
|
186
|
+
body: JSON.stringify([{ jsonrpc: '2.0', id, method: mutation.name }])
|
|
187
|
+
},
|
|
188
|
+
expect: { status: 400, code: JSONRPC_ERROR_CODES.invalid_request, id: null, reason: null }
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return cases;
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* Build the `RequestInit` + path suffix for an envelope case.
|
|
195
|
+
*
|
|
196
|
+
* @param endpoint_path - the RPC endpoint path
|
|
197
|
+
* @param c - the case
|
|
198
|
+
* @param headers - auth headers to merge in
|
|
199
|
+
* @returns the URL (path + query for GET) and the init
|
|
200
|
+
*/
|
|
201
|
+
export const to_rpc_envelope_request = (endpoint_path, c, headers = {}) => c.request.verb === 'POST'
|
|
202
|
+
? {
|
|
203
|
+
url: endpoint_path,
|
|
204
|
+
init: {
|
|
205
|
+
method: 'POST',
|
|
206
|
+
headers: { 'Content-Type': 'application/json', ...headers },
|
|
207
|
+
body: c.request.body
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
: { url: `${endpoint_path}${c.request.query}`, init: { method: 'GET', headers } };
|
|
211
|
+
/**
|
|
212
|
+
* Assert a response body is the refusal an envelope case owes: a well-formed
|
|
213
|
+
* JSON-RPC error envelope with the case's code, echoed id, and `data.reason`.
|
|
214
|
+
*
|
|
215
|
+
* @param status - the response's HTTP status
|
|
216
|
+
* @param body - the parsed response body
|
|
217
|
+
* @param c - the case
|
|
218
|
+
*/
|
|
219
|
+
export const assert_rpc_envelope_refusal = (status, body, c) => {
|
|
220
|
+
const detail = `${c.name}: got ${status} ${JSON.stringify(body)}`;
|
|
221
|
+
assert.strictEqual(status, c.expect.status, detail);
|
|
222
|
+
assert_jsonrpc_error_response(body, c.expect.code);
|
|
223
|
+
const envelope = body;
|
|
224
|
+
assert.strictEqual(envelope.id, c.expect.id, `${detail} — echoed id`);
|
|
225
|
+
const data = envelope.error.data;
|
|
226
|
+
const reason = typeof data === 'object' && data !== null ? data.reason : undefined;
|
|
227
|
+
assert.strictEqual(reason ?? null, c.expect.reason, `${detail} — data.reason`);
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Generate the schema-invalid params cases for one RPC method's input.
|
|
231
|
+
*
|
|
232
|
+
* `generate_input_test_cases` minus its structural cases: a non-object body
|
|
233
|
+
* is a non-object `params`, which the JSON-RPC envelope refuses
|
|
234
|
+
* (`invalid_request`) before params validation runs, and the envelope cases
|
|
235
|
+
* cover it. Every case returned owes 400 `invalid_params`.
|
|
236
|
+
*
|
|
237
|
+
* @param input - the method's input schema
|
|
238
|
+
* @param options - a valid base `params` to seed the cases (`InputTestCaseOptions.base`),
|
|
239
|
+
* and the method name for error messages
|
|
240
|
+
* @returns the cases, each a `params` object
|
|
241
|
+
* @throws Error if the base `params`, seeded or generated, fails the input schema
|
|
242
|
+
*/
|
|
243
|
+
export const generate_rpc_params_test_cases = (input, options) => generate_input_test_cases(input, options).filter((tc) => tc.expected_error !== ERROR_INVALID_JSON_BODY);
|
|
@@ -156,6 +156,37 @@ export interface RpcCallArgs {
|
|
|
156
156
|
*/
|
|
157
157
|
suppress_default_origin?: boolean;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* The unparsed response `rpc_call_raw` returns: the HTTP status, the
|
|
161
|
+
* response-headers snapshot (lowercased keys), and the JSON body exactly as
|
|
162
|
+
* the server sent it — the whole envelope, `jsonrpc` and `id` included.
|
|
163
|
+
*/
|
|
164
|
+
export interface RpcCallRawResult {
|
|
165
|
+
status: number;
|
|
166
|
+
headers: Record<string, string>;
|
|
167
|
+
body: unknown;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Send one JSON-RPC request the way `rpc_call` does — same defaults, verbs
|
|
171
|
+
* and header merging — and return the response unparsed.
|
|
172
|
+
*
|
|
173
|
+
* For callers that compare whole bodies (the cross-backend differential),
|
|
174
|
+
* where `rpc_call`'s envelope parse would hide anything outside `result` /
|
|
175
|
+
* `error`.
|
|
176
|
+
*
|
|
177
|
+
* @throws Error if the response body is not JSON
|
|
178
|
+
*/
|
|
179
|
+
export declare const rpc_call_raw: (args: RpcCallArgs) => Promise<RpcCallRawResult>;
|
|
180
|
+
/**
|
|
181
|
+
* Parse a raw JSON-RPC response into `rpc_call`'s discriminated result.
|
|
182
|
+
*
|
|
183
|
+
* @param raw - the response `rpc_call_raw` returned
|
|
184
|
+
* @param method - the method called, for the error message
|
|
185
|
+
* @returns the success or error branch
|
|
186
|
+
* @throws Error if the body is neither a valid `JsonrpcResponse` nor
|
|
187
|
+
* `JsonrpcErrorResponse` envelope
|
|
188
|
+
*/
|
|
189
|
+
export declare const parse_rpc_call_result: (raw: RpcCallRawResult, method: string) => RpcCallResult;
|
|
159
190
|
/**
|
|
160
191
|
* One-shot JSON-RPC call over a Hono app.
|
|
161
192
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_helpers.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_helpers.ts"],"names":[],"mappings":"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
|
|
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,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EACX,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE;;;;;;;;;GASG;AACH,MAAM,MAAM,uBAAuB,GAClC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;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,IAa1F,CAAC;AAIF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAErF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,GACzB,KAAK;IACL,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;CAC5E,KAAG,gBAEmB,CAAC;AAEzB;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMzE,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC9E;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACxD,CAAC;AAEL;;;;GAIG;AACH,MAAM,MAAM,UAAU,GACnB;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;CAAE,GAC/E,gBAAgB,CAAC;AAEpB,gCAAgC;AAChC,MAAM,WAAW,WAAW;IAC3B,yDAAyD;IACzD,GAAG,EAAE,UAAU,CAAC;IAChB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACtB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAClC;AAgCD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,OAAO,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,gBAAgB,CAiC9E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,gBAAgB,EAAE,QAAQ,MAAM,KAAG,aAwB7E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,GAAU,MAAM,WAAW,KAAG,OAAO,CAAC,aAAa,CACX,CAAC;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAChC,MAAM,IAAI,CAAC,WAAW,EAAE,yBAAyB,CAAC,KAChD,OAAO,CAAC,aAAa,CAAyD,CAAC;AAElF;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,yBAAyB,IACrE;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;CAAE,GAC/F;IACA,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACxD,CAAC;AAEL,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,yBAAyB,IAAI,IAAI,CAC7E,WAAW,EACX,QAAQ,GAAG,QAAQ,CACnB,GAAG;IACH,2GAA2G;IAC3G,IAAI,EAAE,KAAK,CAAC;IACZ,0CAA0C;IAC1C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAU,KAAK,SAAS,yBAAyB,EAC9E,MAAM,kBAAkB,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAoBrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAU,CAAC,EACrC,MAAM,WAAW,EACjB,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KACzB,OAAO,CAAC,CAAC,CAkBX,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,eAAe,CAAC,EAC7C,QAAQ,MAAM,KACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG,SAOxC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAC3B,eAAe,aAAa,CAAC,qBAAqB,CAAC,EACnD,QAAQ,MAAM,KACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,mBAAmB,CAAA;CAAE,GAAG,SAOvD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACrC,eAAe,aAAa,CAAC,eAAe,CAAC,KAC3C,MAcF,CAAC"}
|
|
@@ -169,18 +169,16 @@ const RPC_CALL_DEFAULT_HEADERS = {
|
|
|
169
169
|
origin: 'http://localhost:5173'
|
|
170
170
|
};
|
|
171
171
|
/**
|
|
172
|
-
*
|
|
172
|
+
* Send one JSON-RPC request the way `rpc_call` does — same defaults, verbs
|
|
173
|
+
* and header merging — and return the response unparsed.
|
|
173
174
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
175
|
+
* For callers that compare whole bodies (the cross-backend differential),
|
|
176
|
+
* where `rpc_call`'s envelope parse would hide anything outside `result` /
|
|
177
|
+
* `error`.
|
|
177
178
|
*
|
|
178
|
-
* @throws Error if the response body is
|
|
179
|
-
* nor `JsonrpcErrorResponse` envelope — protocol-level failures the caller
|
|
180
|
-
* should never tolerate. All JSON-RPC errors come back via `{ok: false, error}`
|
|
181
|
-
* so assertions can focus on `error.code` / `error.data.reason`.
|
|
179
|
+
* @throws Error if the response body is not JSON
|
|
182
180
|
*/
|
|
183
|
-
export const
|
|
181
|
+
export const rpc_call_raw = async (args) => {
|
|
184
182
|
const { app, path, method, params, headers, id = 'test', verb = 'POST', suppress_default_origin } = args;
|
|
185
183
|
const defaults = suppress_default_origin
|
|
186
184
|
? RPC_CALL_DEFAULT_HEADERS_BASE
|
|
@@ -201,19 +199,29 @@ export const rpc_call = async (args) => {
|
|
|
201
199
|
};
|
|
202
200
|
}
|
|
203
201
|
const res = await (typeof app === 'function' ? app(url, init) : app.request(url, init));
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
return { status: res.status, headers: headers_to_record(res.headers), body: await res.json() };
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Parse a raw JSON-RPC response into `rpc_call`'s discriminated result.
|
|
206
|
+
*
|
|
207
|
+
* @param raw - the response `rpc_call_raw` returned
|
|
208
|
+
* @param method - the method called, for the error message
|
|
209
|
+
* @returns the success or error branch
|
|
210
|
+
* @throws Error if the body is neither a valid `JsonrpcResponse` nor
|
|
211
|
+
* `JsonrpcErrorResponse` envelope
|
|
212
|
+
*/
|
|
213
|
+
export const parse_rpc_call_result = (raw, method) => {
|
|
214
|
+
const { status, headers, body } = raw;
|
|
207
215
|
const success = JsonrpcResponse.safeParse(body);
|
|
208
216
|
if (success.success) {
|
|
209
|
-
return { ok: true, status, headers
|
|
217
|
+
return { ok: true, status, headers, result: success.data.result };
|
|
210
218
|
}
|
|
211
219
|
const error = JsonrpcErrorResponse.safeParse(body);
|
|
212
220
|
if (error.success) {
|
|
213
221
|
return {
|
|
214
222
|
ok: false,
|
|
215
223
|
status,
|
|
216
|
-
headers
|
|
224
|
+
headers,
|
|
217
225
|
error: {
|
|
218
226
|
code: error.data.error.code,
|
|
219
227
|
message: error.data.error.message,
|
|
@@ -223,6 +231,19 @@ export const rpc_call = async (args) => {
|
|
|
223
231
|
}
|
|
224
232
|
throw new Error(`rpc_call: response is not a valid JSON-RPC envelope (method=${method}, status=${status}): ${JSON.stringify(body)}`);
|
|
225
233
|
};
|
|
234
|
+
/**
|
|
235
|
+
* One-shot JSON-RPC call over a Hono app.
|
|
236
|
+
*
|
|
237
|
+
* Merges sensible defaults (`host`, `origin`, `Content-Type`) under
|
|
238
|
+
* caller-provided headers, fires POST (default) or GET, parses the envelope,
|
|
239
|
+
* and returns a discriminated result.
|
|
240
|
+
*
|
|
241
|
+
* @throws Error if the response body is neither a valid `JsonrpcResponse`
|
|
242
|
+
* nor `JsonrpcErrorResponse` envelope — protocol-level failures the caller
|
|
243
|
+
* should never tolerate. All JSON-RPC errors come back via `{ok: false, error}`
|
|
244
|
+
* so assertions can focus on `error.code` / `error.data.reason`.
|
|
245
|
+
*/
|
|
246
|
+
export const rpc_call = async (args) => parse_rpc_call_result(await rpc_call_raw(args), args.method);
|
|
226
247
|
/**
|
|
227
248
|
* Same as `rpc_call` but without the default `origin` header. Use for
|
|
228
249
|
* bearer-auth probes: `bearer_auth` discards the token when Origin or
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import './assert_dev_env.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TestAccount } from './app_server.js';
|
|
3
|
+
import type { AppSurfaceSpec, AppSurfaceRpcMethod } from '../http/surface.js';
|
|
3
4
|
import { type RpcEndpointsSuiteOption } from './rpc_helpers.js';
|
|
5
|
+
import { type AuthPrincipal, type KeeperHeaderProvider } from './integration_helpers.js';
|
|
4
6
|
import type { SetupTest, TestFixture } from './cross_backend/setup.js';
|
|
5
7
|
import type { SessionOptions } from '../auth/session_cookie.js';
|
|
6
8
|
/** Options for `describe_rpc_round_trip_tests`. */
|
|
@@ -51,9 +53,58 @@ export interface RpcRoundTripTestOptions {
|
|
|
51
53
|
*
|
|
52
54
|
* Fired as POST. The factory runs against the shared per-describe fixture,
|
|
53
55
|
* so it must not assume a clean slate between entries (seed unique state).
|
|
56
|
+
* By default the request carries the identity the generic loop picks for
|
|
57
|
+
* the method's auth (`authed` / `admin` / keeper); a case that returns
|
|
58
|
+
* `headers` sends those instead — for methods whose row must belong to the
|
|
59
|
+
* caller (revoking one's own token or session, retracting one's own offer).
|
|
60
|
+
* `create_spine_rpc_success_fixtures` (`cross_backend/rpc_success_fixtures.ts`)
|
|
61
|
+
* builds the map for the standard spine methods.
|
|
54
62
|
*/
|
|
55
|
-
success_fixtures?:
|
|
63
|
+
success_fixtures?: RpcSuccessFixtures;
|
|
56
64
|
}
|
|
65
|
+
/** One success-fixture request: the params, and optionally the caller's headers. */
|
|
66
|
+
export interface RpcSuccessFixtureCase {
|
|
67
|
+
/** Params that drive a success response. */
|
|
68
|
+
params: Record<string, unknown>;
|
|
69
|
+
/**
|
|
70
|
+
* Auth headers to send in place of the identity the suite picks from the
|
|
71
|
+
* method's auth — for a row that only its owner may act on.
|
|
72
|
+
*/
|
|
73
|
+
headers?: Record<string, string>;
|
|
74
|
+
}
|
|
75
|
+
/** One success-fixture factory: builds the row against the per-test fixture, then returns the request. */
|
|
76
|
+
export type RpcSuccessFixture = (fixture: TestFixture) => Promise<RpcSuccessFixtureCase>;
|
|
77
|
+
/** Success-case fixtures, method name → async factory. See `RpcRoundTripTestOptions.success_fixtures`. */
|
|
78
|
+
export type RpcSuccessFixtures = Map<string, RpcSuccessFixture>;
|
|
79
|
+
/** A picked principal and the headers that carry its credential. */
|
|
80
|
+
export interface RpcRoundTripAuth {
|
|
81
|
+
principal: AuthPrincipal;
|
|
82
|
+
headers: Record<string, string>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Pick the principal matching an RPC method's auth requirement
|
|
86
|
+
* (`pick_auth_principal`, shared with the REST round-trip), and the headers
|
|
87
|
+
* carrying its credential. Accepts any `KeeperHeaderProvider` — both `TestApp`
|
|
88
|
+
* (in-process) and `TestFixture` (cross-backend) satisfy the shape
|
|
89
|
+
* structurally.
|
|
90
|
+
*/
|
|
91
|
+
export declare const pick_rpc_auth: (method: AppSurfaceRpcMethod, keeper: KeeperHeaderProvider, authed_account: TestAccount, admin_account: TestAccount) => RpcRoundTripAuth;
|
|
92
|
+
/**
|
|
93
|
+
* Guard against a refusal that says the call carried no valid credential
|
|
94
|
+
* when it carried one (`is_unauthenticated_refusal`). The round-trip sends
|
|
95
|
+
* every non-public method a live credential its auth admits, so such a 401
|
|
96
|
+
* means the backend failed to authenticate it — most often because an earlier
|
|
97
|
+
* call destroyed it (a self-delete, a revoke-all), which would turn every
|
|
98
|
+
* later method's coverage into a vacuous refusal. A public method may still
|
|
99
|
+
* answer 401 (a login with a wrong password), and so may a handler refusing
|
|
100
|
+
* an authenticated call with a reason of its own (`invalid_credentials`).
|
|
101
|
+
*
|
|
102
|
+
* @param method - the RPC method name
|
|
103
|
+
* @param status - the HTTP status
|
|
104
|
+
* @param body - the parsed response body (or raw text when not JSON)
|
|
105
|
+
* @param principal - the principal the call was sent as
|
|
106
|
+
*/
|
|
107
|
+
export declare const assert_rpc_authenticated: (method: string, status: number, body: unknown, principal: AuthPrincipal) => void;
|
|
57
108
|
/**
|
|
58
109
|
* Run schema-driven round-trip validation for RPC endpoints.
|
|
59
110
|
*
|
|
@@ -66,10 +117,15 @@ export interface RpcRoundTripTestOptions {
|
|
|
66
117
|
*
|
|
67
118
|
* Error responses (from missing DB state, etc.) are expected and validated
|
|
68
119
|
* as well-formed JSON-RPC errors. Successful responses are validated against
|
|
69
|
-
* `action.spec.output`.
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
120
|
+
* `action.spec.output`. Two error classes fail loud instead of passing as a
|
|
121
|
+
* valid envelope: `method not found` (-32601) means the backend is missing a
|
|
122
|
+
* method the local surface advertises (`assert_method_implemented`), and a
|
|
123
|
+
* crash — HTTP 500, `internal_error` (-32603), or a ≥500 with no JSON-RPC
|
|
124
|
+
* envelope — means the backend failed on schema-valid input
|
|
125
|
+
* (`assert_not_crash`). A declared ≥500 code (`service_unavailable`,
|
|
126
|
+
* `timeout`) passes as a refusal. A method the suite can't drive generically
|
|
127
|
+
* goes in `skip_methods`; one whose generated params can't reach its handler
|
|
128
|
+
* gets an `input_overrides` entry.
|
|
73
129
|
*/
|
|
74
130
|
export declare const describe_rpc_round_trip_tests: (options: RpcRoundTripTestOptions) => void;
|
|
75
131
|
//# sourceMappingURL=rpc_round_trip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"rpc_round_trip.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/rpc_round_trip.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsC7B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAQN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAKN,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACvC,kEAAkE;IAClE,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B;;;;;OAKG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC,qDAAqD;IACrD,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;CACtC;AAED,oFAAoF;AACpF,MAAM,WAAW,qBAAqB;IACrC,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,0GAA0G;AAC1G,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEzF,0GAA0G;AAC1G,MAAM,MAAM,kBAAkB,GAAG,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAEhE,oEAAoE;AACpE,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GACzB,QAAQ,mBAAmB,EAC3B,QAAQ,oBAAoB,EAC5B,gBAAgB,WAAW,EAC3B,eAAe,WAAW,KACxB,gBAMF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,GACpC,QAAQ,MAAM,EACd,QAAQ,MAAM,EACd,MAAM,OAAO,EACb,WAAW,aAAa,KACtB,IAiBF,CAAC;AA+GF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,6BAA6B,GAAI,SAAS,uBAAuB,KAAG,IAiKhF,CAAC"}
|