@fuzdev/fuz_app 0.140.0 → 0.142.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 +72 -22
- package/dist/actions/action_rpc.d.ts +5 -1
- package/dist/actions/action_rpc.d.ts.map +1 -1
- package/dist/actions/action_rpc.js +9 -1
- package/dist/actions/connection_closer.d.ts +44 -4
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +33 -3
- package/dist/actions/perform_action.d.ts +10 -0
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +23 -9
- package/dist/actions/register_action_ws.d.ts +42 -6
- package/dist/actions/register_action_ws.d.ts.map +1 -1
- package/dist/actions/register_action_ws.js +87 -19
- package/dist/actions/register_ws_endpoint.d.ts +15 -6
- package/dist/actions/register_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +10 -4
- package/dist/actions/socket.svelte.d.ts +19 -4
- package/dist/actions/socket.svelte.d.ts.map +1 -1
- package/dist/actions/socket.svelte.js +31 -4
- package/dist/actions/transports.d.ts +30 -1
- package/dist/actions/transports.d.ts.map +1 -1
- package/dist/actions/transports.js +30 -1
- package/dist/actions/transports_ws_auth_guard.d.ts +13 -6
- package/dist/actions/transports_ws_auth_guard.d.ts.map +1 -1
- package/dist/actions/transports_ws_auth_guard.js +24 -10
- package/dist/actions/transports_ws_backend.d.ts +51 -5
- package/dist/actions/transports_ws_backend.d.ts.map +1 -1
- package/dist/actions/transports_ws_backend.js +62 -9
- package/dist/actions/ws_endpoint_spec.d.ts +11 -10
- package/dist/actions/ws_endpoint_spec.d.ts.map +1 -1
- package/dist/auth/CLAUDE.md +44 -22
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +12 -1
- package/dist/auth/account_route_schema.d.ts +1 -0
- package/dist/auth/account_route_schema.d.ts.map +1 -1
- package/dist/auth/account_route_schema.js +12 -0
- package/dist/auth/account_routes.d.ts +7 -2
- package/dist/auth/account_routes.d.ts.map +1 -1
- package/dist/auth/account_routes.js +240 -187
- package/dist/auth/admin_action_specs.d.ts +6 -1
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +6 -1
- package/dist/auth/admin_actions.d.ts.map +1 -1
- package/dist/auth/admin_actions.js +14 -2
- package/dist/auth/api_token.d.ts +20 -0
- package/dist/auth/api_token.d.ts.map +1 -1
- package/dist/auth/api_token.js +21 -1
- package/dist/auth/api_token_queries.d.ts +22 -4
- package/dist/auth/api_token_queries.d.ts.map +1 -1
- package/dist/auth/api_token_queries.js +11 -6
- package/dist/auth/audit_log_routes.d.ts +10 -0
- package/dist/auth/audit_log_routes.d.ts.map +1 -1
- package/dist/auth/audit_log_routes.js +20 -0
- package/dist/auth/audit_log_schema.d.ts +30 -5
- package/dist/auth/audit_log_schema.d.ts.map +1 -1
- package/dist/auth/audit_log_schema.js +30 -0
- package/dist/auth/bearer_auth.d.ts +4 -2
- package/dist/auth/bearer_auth.d.ts.map +1 -1
- package/dist/auth/bearer_auth.js +19 -8
- package/dist/auth/bootstrap_route_schema.d.ts +1 -0
- package/dist/auth/bootstrap_route_schema.d.ts.map +1 -1
- package/dist/auth/bootstrap_route_schema.js +1 -0
- package/dist/auth/bootstrap_routes.d.ts.map +1 -1
- package/dist/auth/bootstrap_routes.js +85 -76
- package/dist/auth/cell_action_specs.d.ts +7 -3
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +9 -5
- package/dist/auth/cell_actions.d.ts +3 -3
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +67 -38
- package/dist/auth/cell_authorize.d.ts +69 -8
- package/dist/auth/cell_authorize.d.ts.map +1 -1
- package/dist/auth/cell_authorize.js +89 -9
- package/dist/auth/cell_field_action_specs.d.ts +5 -4
- package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_field_action_specs.js +7 -7
- package/dist/auth/cell_field_actions.d.ts +7 -5
- package/dist/auth/cell_field_actions.d.ts.map +1 -1
- package/dist/auth/cell_field_actions.js +24 -22
- package/dist/auth/cell_grant_action_specs.d.ts +6 -0
- package/dist/auth/cell_grant_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_grant_action_specs.js +6 -0
- package/dist/auth/cell_grant_actions.d.ts +3 -1
- package/dist/auth/cell_grant_actions.d.ts.map +1 -1
- package/dist/auth/cell_grant_actions.js +16 -2
- package/dist/auth/cell_item_action_specs.d.ts +5 -4
- package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_item_action_specs.js +7 -7
- package/dist/auth/cell_item_actions.d.ts +6 -5
- package/dist/auth/cell_item_actions.d.ts.map +1 -1
- package/dist/auth/cell_item_actions.js +23 -22
- package/dist/auth/cell_relation_list_limit.d.ts +20 -0
- package/dist/auth/cell_relation_list_limit.d.ts.map +1 -0
- package/dist/auth/cell_relation_list_limit.js +27 -0
- package/dist/auth/cell_relation_visibility.d.ts +4 -3
- package/dist/auth/cell_relation_visibility.d.ts.map +1 -1
- package/dist/auth/cell_relation_visibility.js +6 -5
- package/dist/auth/cell_steward.d.ts +45 -0
- package/dist/auth/cell_steward.d.ts.map +1 -0
- package/dist/auth/cell_steward.js +53 -0
- package/dist/auth/cleanup.d.ts +9 -9
- package/dist/auth/cleanup.js +9 -9
- package/dist/auth/credential_deadline.d.ts +95 -0
- package/dist/auth/credential_deadline.d.ts.map +1 -0
- package/dist/auth/credential_deadline.js +139 -0
- package/dist/auth/daemon_token_middleware.d.ts.map +1 -1
- package/dist/auth/daemon_token_middleware.js +4 -1
- package/dist/auth/middleware.d.ts +90 -12
- package/dist/auth/middleware.d.ts.map +1 -1
- package/dist/auth/middleware.js +115 -16
- package/dist/auth/request_context.d.ts +8 -2
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +20 -4
- package/dist/auth/resolved_auth.d.ts +13 -2
- package/dist/auth/resolved_auth.d.ts.map +1 -1
- package/dist/auth/resolved_auth.js +5 -4
- package/dist/auth/role_grant_offer_action_specs.d.ts +5 -0
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +6 -1
- package/dist/auth/role_grant_offer_actions.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_actions.js +23 -16
- package/dist/auth/role_grant_offer_queries.d.ts +8 -6
- package/dist/auth/role_grant_offer_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_queries.js +16 -8
- package/dist/auth/session_cookie.d.ts +4 -0
- package/dist/auth/session_cookie.d.ts.map +1 -1
- package/dist/auth/session_cookie.js +3 -2
- package/dist/auth/session_middleware.d.ts +1 -1
- package/dist/auth/session_middleware.d.ts.map +1 -1
- package/dist/auth/session_middleware.js +4 -1
- package/dist/auth/session_queries.d.ts +19 -2
- package/dist/auth/session_queries.d.ts.map +1 -1
- package/dist/auth/session_queries.js +8 -2
- package/dist/auth/signup_route_schema.d.ts.map +1 -1
- package/dist/auth/signup_route_schema.js +1 -0
- package/dist/auth/signup_routes.d.ts +4 -3
- package/dist/auth/signup_routes.d.ts.map +1 -1
- package/dist/auth/signup_routes.js +157 -134
- package/dist/auth/token_scope.d.ts +7 -1
- package/dist/auth/token_scope.d.ts.map +1 -1
- package/dist/auth/token_scope.js +8 -2
- package/dist/db/CLAUDE.md +32 -19
- package/dist/db/cell_ddl.d.ts +1 -2
- package/dist/db/cell_ddl.d.ts.map +1 -1
- package/dist/db/cell_ddl.js +1 -2
- package/dist/db/cell_field_queries.d.ts +20 -18
- package/dist/db/cell_field_queries.d.ts.map +1 -1
- package/dist/db/cell_field_queries.js +28 -22
- package/dist/db/cell_item_queries.d.ts +20 -14
- package/dist/db/cell_item_queries.d.ts.map +1 -1
- package/dist/db/cell_item_queries.js +28 -18
- package/dist/db/cell_moderation.d.ts +67 -0
- package/dist/db/cell_moderation.d.ts.map +1 -0
- package/dist/db/cell_moderation.js +66 -0
- package/dist/db/cell_queries.d.ts +44 -14
- package/dist/db/cell_queries.d.ts.map +1 -1
- package/dist/db/cell_queries.js +68 -45
- package/dist/db/cell_view_sql.d.ts +102 -0
- package/dist/db/cell_view_sql.d.ts.map +1 -0
- package/dist/db/cell_view_sql.js +112 -0
- package/dist/db/db_pg.d.ts +1 -1
- package/dist/db/db_pg.js +1 -1
- package/dist/hono_context.d.ts +23 -0
- package/dist/hono_context.d.ts.map +1 -1
- package/dist/hono_context.js +19 -0
- package/dist/http/CLAUDE.md +41 -15
- package/dist/http/auth_shape.d.ts +5 -2
- package/dist/http/auth_shape.d.ts.map +1 -1
- package/dist/http/auth_shape.js +5 -2
- package/dist/http/ip_canonical.d.ts +30 -3
- package/dist/http/ip_canonical.d.ts.map +1 -1
- package/dist/http/ip_canonical.js +50 -3
- package/dist/http/middleware_spec.d.ts +16 -0
- package/dist/http/middleware_spec.d.ts.map +1 -1
- package/dist/http/origin.d.ts +113 -18
- package/dist/http/origin.d.ts.map +1 -1
- package/dist/http/origin.js +247 -127
- package/dist/http/route_spec.d.ts +21 -0
- package/dist/http/route_spec.d.ts.map +1 -1
- package/dist/http/schema_helpers.d.ts +22 -0
- package/dist/http/schema_helpers.d.ts.map +1 -1
- package/dist/http/schema_helpers.js +24 -0
- package/dist/http/surface.d.ts +6 -1
- package/dist/http/surface.d.ts.map +1 -1
- package/dist/http/surface.js +12 -5
- package/dist/primitive_schemas.d.ts +10 -1
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +11 -2
- package/dist/rate_limiter.d.ts +179 -12
- package/dist/rate_limiter.d.ts.map +1 -1
- package/dist/rate_limiter.js +352 -42
- package/dist/realtime/sse_auth_guard.d.ts +22 -6
- package/dist/realtime/sse_auth_guard.d.ts.map +1 -1
- package/dist/realtime/sse_auth_guard.js +31 -12
- package/dist/realtime/subscriber_registry.d.ts +10 -1
- package/dist/realtime/subscriber_registry.d.ts.map +1 -1
- package/dist/realtime/subscriber_registry.js +10 -1
- package/dist/server/app_server.d.ts +20 -7
- package/dist/server/app_server.d.ts.map +1 -1
- package/dist/server/app_server.js +8 -3
- package/dist/server/env.d.ts +2 -1
- package/dist/server/env.d.ts.map +1 -1
- package/dist/server/env.js +7 -17
- package/dist/server/serve_fact_route.d.ts +8 -4
- package/dist/server/serve_fact_route.d.ts.map +1 -1
- package/dist/server/serve_fact_route.js +16 -6
- package/dist/testing/CLAUDE.md +164 -25
- package/dist/testing/adversarial_headers.d.ts.map +1 -1
- package/dist/testing/adversarial_headers.js +13 -6
- package/dist/testing/connection_closer_helpers.d.ts +6 -1
- package/dist/testing/connection_closer_helpers.d.ts.map +1 -1
- package/dist/testing/connection_closer_helpers.js +4 -0
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +37 -2
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +14 -65
- package/dist/testing/cross_backend/capabilities.d.ts +26 -2
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +9 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts +38 -0
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +401 -5
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.js +145 -2
- package/dist/testing/cross_backend/conformance_case.d.ts +11 -3
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_case.js +6 -0
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +20 -19
- package/dist/testing/cross_backend/credential_deadline.d.ts +25 -0
- package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -0
- package/dist/testing/cross_backend/credential_deadline.js +185 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +13 -2
- package/dist/testing/cross_backend/expected_schema.json +0 -1
- package/dist/testing/cross_backend/full_spine_mount.d.ts +3 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +7 -1
- package/dist/testing/cross_backend/login_security.d.ts +16 -0
- package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
- package/dist/testing/cross_backend/login_security.js +154 -0
- package/dist/testing/cross_backend/narrowed_api_token.d.ts +23 -0
- package/dist/testing/cross_backend/narrowed_api_token.d.ts.map +1 -0
- package/dist/testing/cross_backend/narrowed_api_token.js +40 -0
- package/dist/testing/cross_backend/origin.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin.js +6 -26
- package/dist/testing/cross_backend/origin_conformance.d.ts +152 -0
- package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_conformance.js +136 -0
- package/dist/testing/cross_backend/origin_conformance.json +1679 -0
- package/dist/testing/cross_backend/origin_scope.d.ts +16 -0
- package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -0
- package/dist/testing/cross_backend/origin_scope.js +140 -0
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
- package/dist/testing/cross_backend/query_shape.js +24 -2
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +35 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_cross_helpers.js +64 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +8 -0
- 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 +44 -33
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +64 -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 +6 -4
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +20 -1
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +23 -1
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +20 -7
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +180 -5
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +154 -5
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_scope_surface.js +25 -21
- package/dist/testing/cross_backend/transport_composition.d.ts +60 -0
- package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -0
- package/dist/testing/cross_backend/transport_composition.js +364 -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 +21 -6
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_action_rate_limit.js +21 -1
- package/dist/testing/cross_backend/ws_role_gated.d.ts +38 -0
- package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_role_gated.js +142 -0
- package/dist/testing/entities.d.ts +23 -0
- package/dist/testing/entities.d.ts.map +1 -1
- package/dist/testing/entities.js +37 -0
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +3 -1
- package/dist/testing/middleware.d.ts +10 -0
- package/dist/testing/middleware.d.ts.map +1 -1
- package/dist/testing/middleware.js +31 -7
- package/dist/testing/schema_introspect.js +1 -1
- package/dist/testing/schema_parity.d.ts +4 -3
- package/dist/testing/schema_parity.d.ts.map +1 -1
- package/dist/testing/schema_parity.js +4 -3
- package/dist/testing/schema_ready_fixture.d.ts +2 -4
- package/dist/testing/schema_ready_fixture.d.ts.map +1 -1
- package/dist/testing/schema_ready_fixture.js +2 -4
- package/dist/testing/stubs.d.ts +16 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +20 -7
- package/dist/testing/surface_invariants.js +2 -2
- package/dist/ui/auth_state.svelte.d.ts +10 -0
- package/dist/ui/auth_state.svelte.d.ts.map +1 -1
- package/dist/ui/auth_state.svelte.js +22 -4
- package/package.json +1 -1
- package/dist/db/cell_history_ddl.d.ts +0 -38
- package/dist/db/cell_history_ddl.d.ts.map +0 -1
- package/dist/db/cell_history_ddl.js +0 -61
package/dist/db/cell_queries.js
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { fact_hash_extract_refs } from '@fuzdev/fuz_util/fact_hash.ts';
|
|
24
24
|
import { assert_row } from './assert_row.js';
|
|
25
|
-
import { iso8601_timestamp_expr, qualify_columns } from './sql_columns.js';
|
|
25
|
+
import { columns_sql, iso8601_timestamp_expr, qualify_columns } from './sql_columns.js';
|
|
26
|
+
import { cell_moderation_admits_audience_sql, cell_moderation_is_stewardable_sql } from './cell_moderation.js';
|
|
27
|
+
import { can_view_cell_sql, caller_role_grants_cte, cell_grant_admits_caller_sql } from './cell_view_sql.js';
|
|
26
28
|
/**
|
|
27
29
|
* The full `cell` column set, named explicitly so a row read fails loud on
|
|
28
30
|
* schema drift — a `SELECT *` silently omits a dropped column and the
|
|
@@ -69,6 +71,18 @@ const cell_expr = iso8601_timestamp_expr(CELL_COLUMNS, ['created_at', 'updated_a
|
|
|
69
71
|
* actually produces one.
|
|
70
72
|
*/
|
|
71
73
|
export const cell_row_projection = (alias) => `${qualify_columns(CELL_COLUMNS, alias, cell_expr(alias))}, (SELECT COUNT(*)::int FROM cell_grant WHERE cell_id = ${alias}.id) AS grant_count`;
|
|
74
|
+
/**
|
|
75
|
+
* The columns a view check reads (`can_view_cell`) — the `CELL_COLUMNS`
|
|
76
|
+
* subset `query_cell_view_load_many` projects, typed against `CELL_COLUMNS`
|
|
77
|
+
* so the base const's drift guard covers it. Twin of `fuz_cell`'s
|
|
78
|
+
* `CELL_VIEW_COLUMNS`.
|
|
79
|
+
*/
|
|
80
|
+
export const CELL_VIEW_COLUMNS = [
|
|
81
|
+
'id',
|
|
82
|
+
'visibility',
|
|
83
|
+
'moderation',
|
|
84
|
+
'created_by'
|
|
85
|
+
];
|
|
72
86
|
/**
|
|
73
87
|
* Insert a cell row, deriving `refs` from `data`.
|
|
74
88
|
*
|
|
@@ -133,11 +147,10 @@ export const query_cell_get_by_path = async (deps, path) => {
|
|
|
133
147
|
return row ?? null;
|
|
134
148
|
};
|
|
135
149
|
/**
|
|
136
|
-
* Bulk-load active cell rows by id, **no visibility filter applied
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* to tombstones never surface.
|
|
150
|
+
* Bulk-load active cell rows by id, **no visibility filter applied** — the
|
|
151
|
+
* full rows, for a caller that copies or returns them (the deep-clone walk).
|
|
152
|
+
* A caller that needs only the view check reads `query_cell_view_load_many`.
|
|
153
|
+
* Soft-deleted rows are excluded so relations to tombstones never surface.
|
|
141
154
|
*
|
|
142
155
|
* @param deps - query deps
|
|
143
156
|
* @param ids - cell ids to load (duplicates are harmless)
|
|
@@ -150,6 +163,24 @@ export const query_cell_load_many = async (deps, ids) => {
|
|
|
150
163
|
FROM cell
|
|
151
164
|
WHERE id = ANY($1::uuid[]) AND deleted_at IS NULL`, [ids]);
|
|
152
165
|
};
|
|
166
|
+
/**
|
|
167
|
+
* Bulk-load the active cells among `ids` for a view check — the
|
|
168
|
+
* `CELL_VIEW_COLUMNS` alone, never the payload. Backs the strict
|
|
169
|
+
* relation-read filter (`auth/cell_relation_visibility.ts`'s
|
|
170
|
+
* `filter_visible_target_ids`), which runs `can_view_cell` per row in memory
|
|
171
|
+
* rather than in SQL. Soft-deleted rows and ids with no row are absent.
|
|
172
|
+
*
|
|
173
|
+
* @param deps - query deps
|
|
174
|
+
* @param ids - cell ids to load (duplicates are harmless)
|
|
175
|
+
* @returns active rows in arbitrary order (caller indexes by `id`)
|
|
176
|
+
*/
|
|
177
|
+
export const query_cell_view_load_many = async (deps, ids) => {
|
|
178
|
+
if (ids.length === 0)
|
|
179
|
+
return [];
|
|
180
|
+
return deps.db.query(`SELECT ${columns_sql(CELL_VIEW_COLUMNS)}
|
|
181
|
+
FROM cell
|
|
182
|
+
WHERE id = ANY($1::uuid[]) AND deleted_at IS NULL`, [ids]);
|
|
183
|
+
};
|
|
153
184
|
/**
|
|
154
185
|
* Update a cell. Fields left `undefined` in the patch keep their existing
|
|
155
186
|
* value; explicit `null` writes `NULL`. `refs` is re-derived from `data`
|
|
@@ -274,15 +305,24 @@ export const query_cell_list_by_creator = async (deps, actor_id, options) => dep
|
|
|
274
305
|
* dimension — keep it simple) plus an optional viewer-aware visibility
|
|
275
306
|
* predicate.
|
|
276
307
|
*
|
|
277
|
-
* The visibility predicate mirrors `can_view_cell` in SQL
|
|
308
|
+
* The visibility predicate mirrors `can_view_cell || can_steward_cell` in SQL
|
|
309
|
+
* form:
|
|
278
310
|
*
|
|
279
311
|
* ```
|
|
280
312
|
* (viewer_is_admin
|
|
281
|
-
* OR cell.visibility = 'public'
|
|
282
313
|
* OR (viewer_actor_id IS NOT NULL AND created_by = viewer_actor_id)
|
|
283
|
-
* OR (
|
|
314
|
+
* OR (<moderation admits an audience> AND (
|
|
315
|
+
* cell.visibility = 'public'
|
|
316
|
+
* OR (viewer_actor_id IS NOT NULL AND <grant admits caller>)))
|
|
317
|
+
* OR (viewer_actor_id IS NOT NULL AND <pending or rejected contribution>
|
|
318
|
+
* AND <viewer owns its live governing root>))
|
|
284
319
|
* ```
|
|
285
320
|
*
|
|
321
|
+
* The moderation rules are `cell_moderation_admits_audience_sql` and
|
|
322
|
+
* `cell_moderation_is_stewardable_sql` (`db/cell_moderation.ts`). The last arm
|
|
323
|
+
* is the steward arm (`auth/cell_steward.ts`) — a root owner reads the
|
|
324
|
+
* moderation queue under their root; a global admin is already admitted.
|
|
325
|
+
*
|
|
286
326
|
* The grants branch closes parity with `can_view_cell`: a SQL `EXISTS`
|
|
287
327
|
* over `cell_grant`, parameterized by the caller's `actor_id` and the
|
|
288
328
|
* parallel `(role[], scope_id[])` projection of `auth.role_grants`. The
|
|
@@ -304,7 +344,9 @@ export const query_cell_list_by_creator = async (deps, actor_id, options) => dep
|
|
|
304
344
|
* owner-excluding, but the explicit `created_by IS DISTINCT FROM caller`
|
|
305
345
|
* guards against any future deviation. The shared_with branch does NOT
|
|
306
346
|
* bypass for admin: an admin asking "what's shared with me" wants their
|
|
307
|
-
* own grant footprint, not every cell.
|
|
347
|
+
* own grant footprint, not every cell. A grant admits there only while the
|
|
348
|
+
* cell's moderation admits an audience, as in `can_view_cell`, and the steward
|
|
349
|
+
* arm doesn't apply — a grant footprint is not a moderation queue.
|
|
308
350
|
*
|
|
309
351
|
* Soft-deleted rows are excluded by default; opt-in via `include_deleted`.
|
|
310
352
|
*
|
|
@@ -369,36 +411,17 @@ export const query_cell_list = async (deps, params) => {
|
|
|
369
411
|
]);
|
|
370
412
|
};
|
|
371
413
|
/**
|
|
372
|
-
* The `
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* Resolves true when the grant row at `g_alias` admits the caller via
|
|
376
|
-
* either an actor-shaped principal (`g.actor_id = $11`) or a
|
|
377
|
-
* role-shaped principal whose `(role, scope_id)` matches a row in the
|
|
378
|
-
* `caller_role_grants` CTE. NULL `g.scope_id` matches any scope, mirroring
|
|
379
|
-
* `grant_admits` in `auth/cell_authorize.ts`.
|
|
414
|
+
* The caller's `(role, scope_id)` role_grant pairs, materialized once per
|
|
415
|
+
* query so the role-grant predicate doesn't re-scan `unnest()` per outer row.
|
|
416
|
+
* Shared by both SQL shapes.
|
|
380
417
|
*/
|
|
381
|
-
const
|
|
382
|
-
($11::uuid IS NOT NULL AND ${g_alias}.actor_id = $11)
|
|
383
|
-
OR (
|
|
384
|
-
${g_alias}.role IS NOT NULL
|
|
385
|
-
AND EXISTS (
|
|
386
|
-
SELECT 1 FROM caller_role_grants p
|
|
387
|
-
WHERE p.role = ${g_alias}.role
|
|
388
|
-
AND (${g_alias}.scope_id IS NULL OR p.scope_id IS NOT DISTINCT FROM ${g_alias}.scope_id)
|
|
389
|
-
)
|
|
390
|
-
)
|
|
391
|
-
)`;
|
|
418
|
+
const CALLER_ROLE_GRANTS_CTE = `WITH ${caller_role_grants_cte('$12', '$13')}`;
|
|
392
419
|
/**
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
420
|
+
* General `cell_list` SQL: cell-driven scan, full visibility predicate — the
|
|
421
|
+
* `can_view_cell` arms (`can_view_cell_sql`), then the steward arm
|
|
422
|
+
* (`can_steward_cell`: the caller owns the live governing root of a pending or
|
|
423
|
+
* rejected contribution; a global admin is already in through `$6`).
|
|
397
424
|
*/
|
|
398
|
-
const CALLER_ROLE_GRANTS_CTE = `WITH caller_role_grants AS (
|
|
399
|
-
SELECT role, scope_id FROM unnest($12::text[], $13::uuid[]) AS p(role, scope_id)
|
|
400
|
-
)`;
|
|
401
|
-
/** General `cell_list` SQL: cell-driven scan, full visibility predicate. */
|
|
402
425
|
const build_general_sql = (order_column, order_direction) => `${CALLER_ROLE_GRANTS_CTE}
|
|
403
426
|
SELECT ${cell_row_projection('c')} FROM cell c
|
|
404
427
|
WHERE ($1::bool OR c.deleted_at IS NULL)
|
|
@@ -411,13 +434,12 @@ const build_general_sql = (order_column, order_direction) => `${CALLER_ROLE_GRAN
|
|
|
411
434
|
AND ($15::uuid IS NULL OR c.root_id = $15)
|
|
412
435
|
AND ($16::text IS NULL OR c.moderation = $16::text)
|
|
413
436
|
AND (
|
|
414
|
-
$6
|
|
415
|
-
OR c.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
))
|
|
437
|
+
${can_view_cell_sql('c', { is_admin: '$6', actor_id: '$7', grant_actor_id: '$11' })}
|
|
438
|
+
OR ($7::uuid IS NOT NULL AND c.root_id IS NOT NULL AND ${cell_moderation_is_stewardable_sql('c')}
|
|
439
|
+
AND EXISTS (
|
|
440
|
+
SELECT 1 FROM cell r
|
|
441
|
+
WHERE r.id = c.root_id AND r.deleted_at IS NULL AND r.created_by = $7
|
|
442
|
+
))
|
|
421
443
|
)
|
|
422
444
|
ORDER BY c.${order_column} ${order_direction} NULLS LAST
|
|
423
445
|
LIMIT $8 OFFSET $9`;
|
|
@@ -450,9 +472,10 @@ const build_shared_with_sql = (order_column, order_direction) => `${CALLER_ROLE_
|
|
|
450
472
|
AND ($16::text IS NULL OR c.moderation = $16::text)
|
|
451
473
|
AND $7::uuid IS NOT NULL
|
|
452
474
|
AND c.created_by IS DISTINCT FROM $7
|
|
475
|
+
AND ${cell_moderation_admits_audience_sql('c')}
|
|
453
476
|
AND c.id IN (
|
|
454
477
|
SELECT g.cell_id FROM cell_grant g
|
|
455
|
-
WHERE ${
|
|
478
|
+
WHERE ${cell_grant_admits_caller_sql('g', '$11')}
|
|
456
479
|
)
|
|
457
480
|
-- $6 (viewer_is_admin) intentionally not consulted: an admin
|
|
458
481
|
-- asking "what's shared with me" wants their grant footprint, not
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `can_view_cell` in SQL — the view predicate a query applies to a cell row
|
|
3
|
+
* before `LIMIT`, so a page holds only rows the caller may view.
|
|
4
|
+
*
|
|
5
|
+
* `can_view_cell_sql` is the one SQL form of the predicate: `query_cell_list`
|
|
6
|
+
* embeds it (adding the steward arm beside it), and the relation lists apply
|
|
7
|
+
* it to the cell at the other end of each edge. It binds the caller through a
|
|
8
|
+
* `CellViewer` (`auth/cell_authorize.ts`'s `cell_viewer_from_auth` builds one
|
|
9
|
+
* from a request context), and the role-shaped grant arm reads the
|
|
10
|
+
* `caller_role_grants` CTE `caller_role_grants_cte` defines. Twin of the Rust
|
|
11
|
+
* `fuz_cell::cell_view_sql`.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import type { Uuid } from '../primitive_schemas.js';
|
|
16
|
+
/**
|
|
17
|
+
* The caller a view predicate binds — what `can_view_cell` reads off the
|
|
18
|
+
* request context.
|
|
19
|
+
*
|
|
20
|
+
* `role_grant_roles` and `role_grant_scope_ids` are parallel, one entry per
|
|
21
|
+
* active role grant (`null` = a global grant): `unnest` pads the shorter with
|
|
22
|
+
* NULLs, and a NULL scope reads as a global grant, so `cell_viewer_params`
|
|
23
|
+
* refuses a mismatch.
|
|
24
|
+
*/
|
|
25
|
+
export interface CellViewer {
|
|
26
|
+
/** The acting actor; `null` for an anonymous or account-grain caller. */
|
|
27
|
+
readonly actor_id: Uuid | null;
|
|
28
|
+
/** Whether the caller holds the global admin role — the arm that admits every cell. */
|
|
29
|
+
readonly is_admin: boolean;
|
|
30
|
+
/** The roles of the caller's active role grants, parallel to `role_grant_scope_ids`. */
|
|
31
|
+
readonly role_grant_roles: ReadonlyArray<string>;
|
|
32
|
+
/** The scopes of the caller's active role grants, parallel to `role_grant_roles`. */
|
|
33
|
+
readonly role_grant_scope_ids: ReadonlyArray<Uuid | null>;
|
|
34
|
+
}
|
|
35
|
+
/** An anonymous caller — admitted by the public arm alone. */
|
|
36
|
+
export declare const CELL_VIEWER_ANONYMOUS: CellViewer;
|
|
37
|
+
/**
|
|
38
|
+
* A server-side read that filters nothing — the admin arm admits every cell.
|
|
39
|
+
* For a caller that applies its own view check afterwards (the `cell_get`
|
|
40
|
+
* bundle) or acts for the server itself.
|
|
41
|
+
*/
|
|
42
|
+
export declare const CELL_VIEWER_UNRESTRICTED: CellViewer;
|
|
43
|
+
/** Where a query binds the `CellViewer` facts `can_view_cell_sql` reads — each a `$N` placeholder. */
|
|
44
|
+
export interface CellViewerSqlParams {
|
|
45
|
+
/** The global-admin flag (`bool`). */
|
|
46
|
+
readonly is_admin: string;
|
|
47
|
+
/** The acting actor (`uuid`, NULL when anonymous) — the owner arm and the grant arm's guard. */
|
|
48
|
+
readonly actor_id: string;
|
|
49
|
+
/**
|
|
50
|
+
* The actor an actor-shaped grant matches, when a query binds it apart
|
|
51
|
+
* from `actor_id` (`query_cell_list` does). Defaults to `actor_id`.
|
|
52
|
+
*/
|
|
53
|
+
readonly grant_actor_id?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The viewer's bind values, in the order `[is_admin, actor_id, roles,
|
|
57
|
+
* scope_ids]`.
|
|
58
|
+
*
|
|
59
|
+
* @param viewer - the caller
|
|
60
|
+
* @returns the four bind values
|
|
61
|
+
* @throws {Error} when the role-grant arrays aren't parallel
|
|
62
|
+
*/
|
|
63
|
+
export declare const cell_viewer_params: (viewer: CellViewer) => [boolean, Uuid | null, ReadonlyArray<string>, ReadonlyArray<Uuid | null>];
|
|
64
|
+
/**
|
|
65
|
+
* The `caller_role_grants` CTE body (no `WITH`): the caller's
|
|
66
|
+
* `(role, scope_id)` pairs, unnested once per query from the parallel arrays
|
|
67
|
+
* at placeholders `roles` and `scope_ids`. PG 12+ inlines a non-recursive
|
|
68
|
+
* single-use CTE, so this is planner-equivalent to a subquery — the form is
|
|
69
|
+
* for clarity.
|
|
70
|
+
*
|
|
71
|
+
* @param roles - the placeholder of the roles array (`text[]`)
|
|
72
|
+
* @param scope_ids - the placeholder of the scope-id array (`uuid[]`)
|
|
73
|
+
* @returns the CTE body
|
|
74
|
+
*/
|
|
75
|
+
export declare const caller_role_grants_cte: (roles: string, scope_ids: string) => string;
|
|
76
|
+
/**
|
|
77
|
+
* The `cell_grant` admits-caller predicate over grant alias `g_alias`: an
|
|
78
|
+
* actor-shaped grant matches the actor at placeholder `actor_id`; a
|
|
79
|
+
* role-shaped grant matches a `(role, scope_id)` pair in the
|
|
80
|
+
* `caller_role_grants` CTE (a NULL grant `scope_id` matches any scope).
|
|
81
|
+
* Mirrors `grant_admits` in `auth/cell_authorize.ts`.
|
|
82
|
+
*
|
|
83
|
+
* @param g_alias - the `cell_grant` alias in the enclosing query
|
|
84
|
+
* @param actor_id - the placeholder of the caller's actor (`uuid`)
|
|
85
|
+
* @returns the SQL predicate
|
|
86
|
+
*/
|
|
87
|
+
export declare const cell_grant_admits_caller_sql: (g_alias: string, actor_id: string) => string;
|
|
88
|
+
/**
|
|
89
|
+
* `can_view_cell` over the cell alias `c_alias`: admin, the owner, or — while
|
|
90
|
+
* the cell's `moderation` admits an audience — `public` or a `cell_grant`
|
|
91
|
+
* admitting the caller.
|
|
92
|
+
*
|
|
93
|
+
* Reads the caller at `params`; the grant arm needs the
|
|
94
|
+
* `caller_role_grants_cte` in scope. Liveness (`deleted_at IS NULL`) is the
|
|
95
|
+
* query's own clause, as `can_view_cell` reads a loaded live row.
|
|
96
|
+
*
|
|
97
|
+
* @param c_alias - the `cell` alias in the enclosing query
|
|
98
|
+
* @param params - where the query binds the caller
|
|
99
|
+
* @returns the SQL predicate (parenthesized)
|
|
100
|
+
*/
|
|
101
|
+
export declare const can_view_cell_sql: (c_alias: string, params: CellViewerSqlParams) => string;
|
|
102
|
+
//# sourceMappingURL=cell_view_sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cell_view_sql.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/db/cell_view_sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAGpD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IAC/B,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjD,qFAAqF;IACrF,QAAQ,CAAC,oBAAoB,EAAE,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;CAC1D;AAED,8DAA8D;AAC9D,eAAO,MAAM,qBAAqB,EAAE,UAKnC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,UAKtC,CAAC;AAEF,sGAAsG;AACtG,MAAM,WAAW,mBAAmB;IACnC,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAC9B,QAAQ,UAAU,KAChB,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC,CAQ1E,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,EAAE,WAAW,MAAM,KAAG,MAGtE,CAAC;AAEL;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MAU3E,CAAC;AAEP;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,QAAQ,mBAAmB,KAAG,MAchF,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `can_view_cell` in SQL — the view predicate a query applies to a cell row
|
|
3
|
+
* before `LIMIT`, so a page holds only rows the caller may view.
|
|
4
|
+
*
|
|
5
|
+
* `can_view_cell_sql` is the one SQL form of the predicate: `query_cell_list`
|
|
6
|
+
* embeds it (adding the steward arm beside it), and the relation lists apply
|
|
7
|
+
* it to the cell at the other end of each edge. It binds the caller through a
|
|
8
|
+
* `CellViewer` (`auth/cell_authorize.ts`'s `cell_viewer_from_auth` builds one
|
|
9
|
+
* from a request context), and the role-shaped grant arm reads the
|
|
10
|
+
* `caller_role_grants` CTE `caller_role_grants_cte` defines. Twin of the Rust
|
|
11
|
+
* `fuz_cell::cell_view_sql`.
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { cell_moderation_admits_audience_sql } from './cell_moderation.js';
|
|
16
|
+
/** An anonymous caller — admitted by the public arm alone. */
|
|
17
|
+
export const CELL_VIEWER_ANONYMOUS = {
|
|
18
|
+
actor_id: null,
|
|
19
|
+
is_admin: false,
|
|
20
|
+
role_grant_roles: [],
|
|
21
|
+
role_grant_scope_ids: []
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A server-side read that filters nothing — the admin arm admits every cell.
|
|
25
|
+
* For a caller that applies its own view check afterwards (the `cell_get`
|
|
26
|
+
* bundle) or acts for the server itself.
|
|
27
|
+
*/
|
|
28
|
+
export const CELL_VIEWER_UNRESTRICTED = {
|
|
29
|
+
actor_id: null,
|
|
30
|
+
is_admin: true,
|
|
31
|
+
role_grant_roles: [],
|
|
32
|
+
role_grant_scope_ids: []
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The viewer's bind values, in the order `[is_admin, actor_id, roles,
|
|
36
|
+
* scope_ids]`.
|
|
37
|
+
*
|
|
38
|
+
* @param viewer - the caller
|
|
39
|
+
* @returns the four bind values
|
|
40
|
+
* @throws {Error} when the role-grant arrays aren't parallel
|
|
41
|
+
*/
|
|
42
|
+
export const cell_viewer_params = (viewer) => {
|
|
43
|
+
if (viewer.role_grant_roles.length !== viewer.role_grant_scope_ids.length) {
|
|
44
|
+
throw new Error(`CellViewer: role_grant_roles (len=${viewer.role_grant_roles.length}) and ` +
|
|
45
|
+
`role_grant_scope_ids (len=${viewer.role_grant_scope_ids.length}) must be parallel arrays`);
|
|
46
|
+
}
|
|
47
|
+
return [viewer.is_admin, viewer.actor_id, viewer.role_grant_roles, viewer.role_grant_scope_ids];
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The `caller_role_grants` CTE body (no `WITH`): the caller's
|
|
51
|
+
* `(role, scope_id)` pairs, unnested once per query from the parallel arrays
|
|
52
|
+
* at placeholders `roles` and `scope_ids`. PG 12+ inlines a non-recursive
|
|
53
|
+
* single-use CTE, so this is planner-equivalent to a subquery — the form is
|
|
54
|
+
* for clarity.
|
|
55
|
+
*
|
|
56
|
+
* @param roles - the placeholder of the roles array (`text[]`)
|
|
57
|
+
* @param scope_ids - the placeholder of the scope-id array (`uuid[]`)
|
|
58
|
+
* @returns the CTE body
|
|
59
|
+
*/
|
|
60
|
+
export const caller_role_grants_cte = (roles, scope_ids) => `caller_role_grants AS (
|
|
61
|
+
SELECT role, scope_id FROM unnest(${roles}::text[], ${scope_ids}::uuid[]) AS p(role, scope_id)
|
|
62
|
+
)`;
|
|
63
|
+
/**
|
|
64
|
+
* The `cell_grant` admits-caller predicate over grant alias `g_alias`: an
|
|
65
|
+
* actor-shaped grant matches the actor at placeholder `actor_id`; a
|
|
66
|
+
* role-shaped grant matches a `(role, scope_id)` pair in the
|
|
67
|
+
* `caller_role_grants` CTE (a NULL grant `scope_id` matches any scope).
|
|
68
|
+
* Mirrors `grant_admits` in `auth/cell_authorize.ts`.
|
|
69
|
+
*
|
|
70
|
+
* @param g_alias - the `cell_grant` alias in the enclosing query
|
|
71
|
+
* @param actor_id - the placeholder of the caller's actor (`uuid`)
|
|
72
|
+
* @returns the SQL predicate
|
|
73
|
+
*/
|
|
74
|
+
export const cell_grant_admits_caller_sql = (g_alias, actor_id) => `(
|
|
75
|
+
(${actor_id}::uuid IS NOT NULL AND ${g_alias}.actor_id = ${actor_id})
|
|
76
|
+
OR (
|
|
77
|
+
${g_alias}.role IS NOT NULL
|
|
78
|
+
AND EXISTS (
|
|
79
|
+
SELECT 1 FROM caller_role_grants p
|
|
80
|
+
WHERE p.role = ${g_alias}.role
|
|
81
|
+
AND (${g_alias}.scope_id IS NULL OR p.scope_id IS NOT DISTINCT FROM ${g_alias}.scope_id)
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
)`;
|
|
85
|
+
/**
|
|
86
|
+
* `can_view_cell` over the cell alias `c_alias`: admin, the owner, or — while
|
|
87
|
+
* the cell's `moderation` admits an audience — `public` or a `cell_grant`
|
|
88
|
+
* admitting the caller.
|
|
89
|
+
*
|
|
90
|
+
* Reads the caller at `params`; the grant arm needs the
|
|
91
|
+
* `caller_role_grants_cte` in scope. Liveness (`deleted_at IS NULL`) is the
|
|
92
|
+
* query's own clause, as `can_view_cell` reads a loaded live row.
|
|
93
|
+
*
|
|
94
|
+
* @param c_alias - the `cell` alias in the enclosing query
|
|
95
|
+
* @param params - where the query binds the caller
|
|
96
|
+
* @returns the SQL predicate (parenthesized)
|
|
97
|
+
*/
|
|
98
|
+
export const can_view_cell_sql = (c_alias, params) => {
|
|
99
|
+
const { is_admin, actor_id } = params;
|
|
100
|
+
const grant_actor_id = params.grant_actor_id ?? actor_id;
|
|
101
|
+
return `(
|
|
102
|
+
${is_admin}::bool
|
|
103
|
+
OR (${actor_id}::uuid IS NOT NULL AND ${c_alias}.created_by = ${actor_id})
|
|
104
|
+
OR (${cell_moderation_admits_audience_sql(c_alias)} AND (
|
|
105
|
+
${c_alias}.visibility = 'public'
|
|
106
|
+
OR (${actor_id}::uuid IS NOT NULL AND EXISTS (
|
|
107
|
+
SELECT 1 FROM cell_grant g
|
|
108
|
+
WHERE g.cell_id = ${c_alias}.id AND ${cell_grant_admits_caller_sql('g', grant_actor_id)}
|
|
109
|
+
))
|
|
110
|
+
))
|
|
111
|
+
)`;
|
|
112
|
+
};
|
package/dist/db/db_pg.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { type DbDriverResult } from './db.js';
|
|
|
18
18
|
* call this, don't need `pg` installed) and coerces int8 (`BIGINT`, OID 20)
|
|
19
19
|
* to a JS number. pg defaults to returning
|
|
20
20
|
* int8 as a string to avoid 2^53 precision loss; our int8 columns today
|
|
21
|
-
* (`audit_log.seq`, `
|
|
21
|
+
* (`audit_log.seq`, `fact.size`) stay well under that
|
|
22
22
|
* bound, and reading as a number keeps the wire shape uniform with PGlite —
|
|
23
23
|
* which returns int8 as a number — so `AuditLogEvent.seq` and friends
|
|
24
24
|
* validate identically across both drivers.
|
package/dist/db/db_pg.js
CHANGED
|
@@ -17,7 +17,7 @@ import { Db, no_nested_transaction } from './db.js';
|
|
|
17
17
|
* call this, don't need `pg` installed) and coerces int8 (`BIGINT`, OID 20)
|
|
18
18
|
* to a JS number. pg defaults to returning
|
|
19
19
|
* int8 as a string to avoid 2^53 precision loss; our int8 columns today
|
|
20
|
-
* (`audit_log.seq`, `
|
|
20
|
+
* (`audit_log.seq`, `fact.size`) stay well under that
|
|
21
21
|
* bound, and reading as a number keeps the wire shape uniform with PGlite —
|
|
22
22
|
* which returns int8 as a number — so `AuditLogEvent.seq` and friends
|
|
23
23
|
* validate identically across both drivers.
|
package/dist/hono_context.d.ts
CHANGED
|
@@ -57,6 +57,25 @@ export declare const TOKEN_SCOPE_KEY = "token_scope";
|
|
|
57
57
|
* read it directly.
|
|
58
58
|
*/
|
|
59
59
|
export declare const ACCOUNT_ID_KEY = "auth_account_id";
|
|
60
|
+
/**
|
|
61
|
+
* Hono context variable name for the credential's deadline — when it stops
|
|
62
|
+
* authenticating, as a monotonic `performance.now()` timestamp
|
|
63
|
+
* (`auth/credential_deadline.ts`), or `null` for one with no expiry (a daemon
|
|
64
|
+
* token, an eternal API token) and for an unauthenticated request.
|
|
65
|
+
*
|
|
66
|
+
* Set by every auth middleware that resolves a credential: session (the
|
|
67
|
+
* earlier of the signed cookie's expiry and the row's), bearer (the row's),
|
|
68
|
+
* daemon token (`null`). A long-lived connection opened on the credential
|
|
69
|
+
* closes at it (`ResolvedAuth.credential_deadline`).
|
|
70
|
+
*/
|
|
71
|
+
export declare const CREDENTIAL_DEADLINE_KEY = "credential_deadline";
|
|
72
|
+
/**
|
|
73
|
+
* Hono context variable name for the session cookie's signed expiry, in
|
|
74
|
+
* seconds since the Unix epoch — set by the session middleware on a cookie
|
|
75
|
+
* that verified and has not expired, `null` otherwise. The request-context
|
|
76
|
+
* middleware folds it into `CREDENTIAL_DEADLINE_KEY`.
|
|
77
|
+
*/
|
|
78
|
+
export declare const SESSION_COOKIE_EXPIRES_AT_KEY = "auth_session_cookie_expires_at";
|
|
60
79
|
/**
|
|
61
80
|
* Hono context variable name for the test-harness pre-baked context flag.
|
|
62
81
|
*
|
|
@@ -112,6 +131,10 @@ declare module 'hono' {
|
|
|
112
131
|
* up the token.
|
|
113
132
|
*/
|
|
114
133
|
auth_api_token_id: string | null;
|
|
134
|
+
/** The credential's deadline (`CREDENTIAL_DEADLINE_KEY`). */
|
|
135
|
+
credential_deadline: number | null;
|
|
136
|
+
/** The session cookie's signed expiry, epoch seconds (`SESSION_COOKIE_EXPIRES_AT_KEY`). */
|
|
137
|
+
auth_session_cookie_expires_at: number | null;
|
|
115
138
|
/**
|
|
116
139
|
* Eager fire-and-forget pool writes for this request — audit emits,
|
|
117
140
|
* session-touch UPDATE, api-token usage tracking. Producers push the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono_context.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hono_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,mDAInB,CAAC;AAEX,yDAAyD;AACzD,eAAO,MAAM,cAAc;;;;EAA2B,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D,OAAO,QAAQ,MAAM,CAAC;IACrB,UAAU,kBAAkB;QAC3B,+DAA+D;QAC/D,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;QACvC,eAAe,EAAE,OAAO,CAAC;QACzB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;QACzB,2FAA2F;QAC3F,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;QACvC;;;;;;WAMG;QACH,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC;QACpC;;;;;WAKG;QACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B;;;;;WAKG;QACH,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;QACvC;;;;;;WAMG;QACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC;;;;;;;WAOG;QACH,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC;;;;;;;;;;;;WAYG;QACH,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD;;;;WAIG;QACH,mBAAmB,EAAE,OAAO,CAAC;KAC7B;CACD"}
|
|
1
|
+
{"version":3,"file":"hono_context.d.ts","sourceRoot":"../src/lib/","sources":["../src/lib/hono_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,mDAInB,CAAC;AAEX,yDAAyD;AACzD,eAAO,MAAM,cAAc;;;;EAA2B,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,mCAAmC,CAAC;AAE9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D,OAAO,QAAQ,MAAM,CAAC;IACrB,UAAU,kBAAkB;QAC3B,+DAA+D;QAC/D,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;QACvC,eAAe,EAAE,OAAO,CAAC;QACzB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,OAAO,CAAC;QACzB,2FAA2F;QAC3F,eAAe,EAAE,cAAc,GAAG,IAAI,CAAC;QACvC;;;;;;WAMG;QACH,WAAW,EAAE,UAAU,GAAG,SAAS,CAAC;QACpC;;;;;WAKG;QACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B;;;;;WAKG;QACH,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAC;QACvC;;;;;;WAMG;QACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,6DAA6D;QAC7D,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;QACnC,2FAA2F;QAC3F,8BAA8B,EAAE,MAAM,GAAG,IAAI,CAAC;QAC9C;;;;;;;WAOG;QACH,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC;;;;;;;;;;;;WAYG;QACH,mBAAmB,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACvD;;;;WAIG;QACH,mBAAmB,EAAE,OAAO,CAAC;KAC7B;CACD"}
|
package/dist/hono_context.js
CHANGED
|
@@ -55,6 +55,25 @@ export const TOKEN_SCOPE_KEY = 'token_scope';
|
|
|
55
55
|
* read it directly.
|
|
56
56
|
*/
|
|
57
57
|
export const ACCOUNT_ID_KEY = 'auth_account_id';
|
|
58
|
+
/**
|
|
59
|
+
* Hono context variable name for the credential's deadline — when it stops
|
|
60
|
+
* authenticating, as a monotonic `performance.now()` timestamp
|
|
61
|
+
* (`auth/credential_deadline.ts`), or `null` for one with no expiry (a daemon
|
|
62
|
+
* token, an eternal API token) and for an unauthenticated request.
|
|
63
|
+
*
|
|
64
|
+
* Set by every auth middleware that resolves a credential: session (the
|
|
65
|
+
* earlier of the signed cookie's expiry and the row's), bearer (the row's),
|
|
66
|
+
* daemon token (`null`). A long-lived connection opened on the credential
|
|
67
|
+
* closes at it (`ResolvedAuth.credential_deadline`).
|
|
68
|
+
*/
|
|
69
|
+
export const CREDENTIAL_DEADLINE_KEY = 'credential_deadline';
|
|
70
|
+
/**
|
|
71
|
+
* Hono context variable name for the session cookie's signed expiry, in
|
|
72
|
+
* seconds since the Unix epoch — set by the session middleware on a cookie
|
|
73
|
+
* that verified and has not expired, `null` otherwise. The request-context
|
|
74
|
+
* middleware folds it into `CREDENTIAL_DEADLINE_KEY`.
|
|
75
|
+
*/
|
|
76
|
+
export const SESSION_COOKIE_EXPIRES_AT_KEY = 'auth_session_cookie_expires_at';
|
|
58
77
|
/**
|
|
59
78
|
* Hono context variable name for the test-harness pre-baked context flag.
|
|
60
79
|
*
|
package/dist/http/CLAUDE.md
CHANGED
|
@@ -25,7 +25,7 @@ effects, see ../../../docs/architecture.md.
|
|
|
25
25
|
- `http/proxy.ts` — trusted-proxy middleware, CIDR parsing, rightmost-first XFF resolution. Pulls `hono/utils/ipaddr` for CIDR matching.
|
|
26
26
|
- `http/client_ip.ts` — `get_client_ip(c)` — reads the resolved IP off the context (set by `proxy.ts`'s middleware). Split out of `proxy.ts` so it's hono-free: dispatch + route modules that only _read_ the IP don't pull `hono/utils/ipaddr`, keeping cross-process test surfaces free of the optional `hono` peer.
|
|
27
27
|
- `http/ip_canonical.ts` — RFC 5952 IPv6 canonicalization + IPv4-mapped collapse; `IP_LITERAL_CHARS` regex.
|
|
28
|
-
- `http/origin.ts` — origin allowlist
|
|
28
|
+
- `http/origin.ts` — origin allowlist: the strict pattern grammar shared with the Rust spine, typed refusals, and the Origin-only middleware.
|
|
29
29
|
- `http/jsonrpc.ts` — JSON-RPC 2.0 envelope schemas (MCP superset), `JsonrpcErrorCode`, `_meta`.
|
|
30
30
|
- `http/jsonrpc_errors.ts` — `ThrownJsonrpcError`, `jsonrpc_errors` throwers, HTTP-status mappings.
|
|
31
31
|
- `http/jsonrpc_helpers.ts` — message builders, type guards, input/result normalizers.
|
|
@@ -51,6 +51,8 @@ consumers.
|
|
|
51
51
|
- `query?: z.ZodObject` — strict-object schema for URL query string
|
|
52
52
|
- `input: z.ZodType` — request body schema; `z.null()` for no-body (GET/DELETE)
|
|
53
53
|
- `output: z.ZodType` — success response schema
|
|
54
|
+
- `mints_credential?: boolean` — the route issues a session cookie while declaring no auth (login, signup, bootstrap); assembly refuses it outside `AUTH_MIDDLEWARE_PATH`, as it does any route whose `auth.account` is not `'none'` (`assert_credential_routes_in_auth_scope` in `auth/middleware.ts`)
|
|
55
|
+
- `reads_credential?: boolean` — the handler reads the resolved account while the route declares no auth gate, answering an anonymous caller itself (account status, the cell-scoped fact read, `create_rpc_endpoint`'s pair, whose dispatcher gates per action); held inside `AUTH_MIDDLEWARE_PATH` by the same assertion
|
|
54
56
|
- `rate_limit?: RateLimitKey` — metadata only (`'ip' | 'account' | 'both'`); auto-derives 429
|
|
55
57
|
- `errors?: RouteErrorSchemas` — handler-specific error schemas keyed by HTTP status
|
|
56
58
|
- `transaction?: boolean` — declarative transaction wrapping (see below)
|
|
@@ -237,6 +239,7 @@ Key helpers:
|
|
|
237
239
|
- `is_strict_object_schema(schema)` — detects `z.strictObject()` by checking `schema.def.catchall instanceof z.ZodNever`
|
|
238
240
|
- `schema_to_surface(schema)` — Zod → JSON Schema, with `$schema` and `default` keys stripped recursively (defaults may be non-deterministic; `$schema` is snapshot noise)
|
|
239
241
|
- `middleware_applies(mw_path, route_path)` — Hono pattern matching: `'*'`, exact, `'/api/*'` prefix (handles `prefix.slice(0, -1)` so `/api/*` also matches the bare `/api`)
|
|
242
|
+
- `middleware_spec_applies(spec, route_path)` — the layer runs on the route: its `path` applies and none of its `carve_outs` does; what surface generation merges middleware errors by
|
|
240
243
|
- `merge_error_schemas(spec, middleware_errors?)` — the three-layer merge described above
|
|
241
244
|
|
|
242
245
|
## Surface Generation
|
|
@@ -327,9 +330,10 @@ operator configuration in practice.
|
|
|
327
330
|
Origin allowlisting for locally-running services — **not** the CSRF layer.
|
|
328
331
|
CSRF is handled by `SameSite: strict` on session cookies (`auth/session_middleware.ts`).
|
|
329
332
|
|
|
330
|
-
- `parse_allowed_origins(
|
|
331
|
-
- `
|
|
332
|
-
- `
|
|
333
|
+
- `parse_allowed_origins(raw)` — comma-separated entries → `Result<{origins: Array<RegExp>}, {errors: Array<AllowedOriginsError>}>`; every refused entry is reported (`{kind, index, entry}`, 1-based), a blank value is `{kind: 'no_origins'}`
|
|
334
|
+
- `OriginPatternErrorKind` / `AllowedOriginsErrorKind` — the refusal kinds, wire names shared with the Rust spine; `ALLOWED_ORIGINS_ERROR_MESSAGES` the reason per kind, `format_allowed_origins_error` one refusal as a boot-error line (entry quoted and escaped)
|
|
335
|
+
- `should_allow_origin(origin, patterns)` — case-insensitive match; a value that isn't visible ASCII matches nothing
|
|
336
|
+
- `verify_request_source(allowed_patterns, carve_outs?)` — Hono handler: `Origin` present → must match allowlist or 403 `ERROR_FORBIDDEN_ORIGIN`; no `Origin` → allow through (curl, CLI, token auth is primary control). A repeated `Origin` reaches it joined (`a, b`) and is refused. A request whose path a `carve_outs` entry (`MiddlewareCarveOut`, `{path, reason}`) matches passes unchecked
|
|
333
337
|
- `is_browser_context(c)` — true when `Origin` or `Referer` is present (`!== undefined`, so empty-string counts). The bearer + daemon-token middleware discard their credential when true; twin of the Rust spine's `bearer_auth::is_browser_context`. Distinct from `verify_request_source` (allowlist gate) — this only detects browser context
|
|
334
338
|
|
|
335
339
|
**Origin-only by design.** Fetch spec mandates `Origin` on every unsafe
|
|
@@ -337,17 +341,39 @@ method, so a real browser request on any state-changing surface always
|
|
|
337
341
|
carries it. Non-browser clients don't ship auto-attached session cookies,
|
|
338
342
|
so CSRF isn't the relevant threat there — auth (bearer / daemon token) is
|
|
339
343
|
the actual control. A `Referer` fallback would only widen the
|
|
340
|
-
accepted-shape envelope without closing a real CSRF hole.
|
|
341
|
-
`
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
`
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
344
|
+
accepted-shape envelope without closing a real CSRF hole. The Rust
|
|
345
|
+
spine's `origin_layer` is the twin.
|
|
346
|
+
|
|
347
|
+
**Every path by default.** `create_app_server` mounts the check at `'*'`
|
|
348
|
+
(`ORIGIN_MIDDLEWARE_PATH`), the static fallback included, so a foreign page is
|
|
349
|
+
refused wherever it points — the Rust spine's `fuz_http::compose_stack` checks
|
|
350
|
+
every route group and its fallback the same way. Probes and CLI clients send no
|
|
351
|
+
`Origin` and pass. A path leaves the check only by a named carve-out with its
|
|
352
|
+
reason (`AppServerOptions.origin_carve_outs`), for a route that refuses browser
|
|
353
|
+
callers by other means; one overlapping the auth middleware's scope
|
|
354
|
+
(`AUTH_MIDDLEWARE_PATH`, where every route that reads or mints a credential
|
|
355
|
+
sits) is refused at assembly. A carve-out skips every path it matches, routed
|
|
356
|
+
or not, so an unrouted path under it reaches the static fallback unchecked;
|
|
357
|
+
the Rust stack checks unrouted paths in its fallback group whatever a
|
|
358
|
+
carve-out names.
|
|
359
|
+
|
|
360
|
+
**Grammar** (shared with the Rust spine's `AllowedOrigins::parse`, pinned by
|
|
361
|
+
`testing/cross_backend/origin_conformance.json`): entries are trimmed of ASCII
|
|
362
|
+
whitespace and written as a browser writes an `Origin` — exact
|
|
363
|
+
`https://api.fuz.dev`; wildcard label `https://*.fuz.dev` (one label in any
|
|
364
|
+
position — matches `api.fuz.dev`, NOT `fuz.dev` or `a.b.fuz.dev`); several
|
|
365
|
+
`https://*.*.corp.fuz.dev`; port wildcard `http://localhost:*` (any port or
|
|
366
|
+
none); IPv6 `http://[::1]:3000` (exact, no wildcard inside the brackets).
|
|
367
|
+
**Nothing is normalized** — the matcher is built from the entry as written, so
|
|
368
|
+
an entry a browser would never send is refused rather than rewritten: non-ASCII
|
|
369
|
+
(punycode an IDN host), a scheme other than http/https (`null`, `file://`,
|
|
370
|
+
`chrome-extension://`), a path/query/fragment/trailing slash, userinfo, a
|
|
371
|
+
character no hostname holds (`%`, `\`, `^`, `|`, `<`, `>`, `[`, `]`), a partial
|
|
372
|
+
wildcard, an IPv4 address not written as four canonical decimal numbers, an IPv6
|
|
373
|
+
address not in the browser's form (the URL parser serves as the serializer and
|
|
374
|
+
any difference refuses), a port outside `1..=65535` or with leading zeros, the
|
|
375
|
+
scheme's default port, and an empty entry. The checks run in a fixed order so
|
|
376
|
+
both spines name the same kind for the same entry.
|
|
351
377
|
|
|
352
378
|
## JSON-RPC (`http/jsonrpc.ts`, `http/jsonrpc_errors.ts`, `http/jsonrpc_helpers.ts`)
|
|
353
379
|
|
|
@@ -68,9 +68,12 @@ export type ActingActor = z.infer<typeof ActingActor>;
|
|
|
68
68
|
* instead would put an input-shape complaint ahead of the authority gates,
|
|
69
69
|
* which is the ordering this pipeline exists to avoid.
|
|
70
70
|
*
|
|
71
|
-
*
|
|
71
|
+
* The dispatchers pass through here so that rule has one home: the action
|
|
72
72
|
* dispatcher's `read_acting` and the REST authorization handler's
|
|
73
|
-
* `read_route_acting`. Twin of the Rust dispatcher's `read_acting`.
|
|
73
|
+
* `read_route_acting`. Twin of the Rust dispatcher's `read_acting`. The status
|
|
74
|
+
* route and the WS upgrade read the raw `?acting=` through it too; neither has
|
|
75
|
+
* an input schema behind it, so there a malformed selector is final (the
|
|
76
|
+
* status route answers account-only).
|
|
74
77
|
*
|
|
75
78
|
* @param value - the raw `acting` field, from params / query / body
|
|
76
79
|
* @returns the actor id, or `undefined` when absent or malformed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_shape.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/auth_shape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,WAAW,6DAGtB,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"auth_shape.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/http/auth_shape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,WAAW,6DAGtB,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,SAGtD,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa;;;;EAA2C,CAAC;AACtE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;kBAyEnB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAUlD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,KAAG,OACA,CAAC;AAElD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,MAAM,SAAS,KAAG,OAAgC,CAAC;AAE/E;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,SAAS,KAAG,OAAkC,CAAC;AAEnF,wEAAwE;AACxE,eAAO,MAAM,YAAY,GAAI,MAAM,SAAS,KAAG,OAA+B,CAAC;AAE/E,8FAA8F;AAC9F,eAAO,MAAM,wBAAwB,GAAI,MAAM,SAAS,KAAG,OAC3B,CAAC;AAEjC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,SAAS,KAAG,OACQ,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,GAAI,MAAM,SAAS,KAAG,OACwB,CAAC;AAYvF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,GAAI,QAAQ,CAAC,CAAC,OAAO,KAAG,OAIhE,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,sCAAsC,GAClD,MAAM,SAAS,EACf,OAAO,WAAW,EAClB,SAAS,MAAM,KACb,IAmBF,CAAC"}
|
package/dist/http/auth_shape.js
CHANGED
|
@@ -71,9 +71,12 @@ export const ActingActor = Uuid.optional().meta({
|
|
|
71
71
|
* instead would put an input-shape complaint ahead of the authority gates,
|
|
72
72
|
* which is the ordering this pipeline exists to avoid.
|
|
73
73
|
*
|
|
74
|
-
*
|
|
74
|
+
* The dispatchers pass through here so that rule has one home: the action
|
|
75
75
|
* dispatcher's `read_acting` and the REST authorization handler's
|
|
76
|
-
* `read_route_acting`. Twin of the Rust dispatcher's `read_acting`.
|
|
76
|
+
* `read_route_acting`. Twin of the Rust dispatcher's `read_acting`. The status
|
|
77
|
+
* route and the WS upgrade read the raw `?acting=` through it too; neither has
|
|
78
|
+
* an input schema behind it, so there a malformed selector is final (the
|
|
79
|
+
* status route answers account-only).
|
|
77
80
|
*
|
|
78
81
|
* @param value - the raw `acting` field, from params / query / body
|
|
79
82
|
* @returns the actor id, or `undefined` when absent or malformed
|