@fuzdev/fuz_app 0.141.0 → 0.143.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 +10 -5
- package/dist/actions/connection_closer.d.ts +19 -2
- package/dist/actions/connection_closer.d.ts.map +1 -1
- package/dist/actions/connection_closer.js +25 -2
- 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_ws_endpoint.d.ts.map +1 -1
- package/dist/actions/register_ws_endpoint.js +5 -2
- package/dist/auth/CLAUDE.md +33 -13
- 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.map +1 -1
- package/dist/auth/account_route_schema.js +8 -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/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/request_context.d.ts +4 -0
- package/dist/auth/request_context.d.ts.map +1 -1
- package/dist/auth/request_context.js +6 -1
- 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/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/http/CLAUDE.md +1 -1
- 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 +56 -5
- package/dist/http/ip_canonical.d.ts.map +1 -1
- package/dist/http/ip_canonical.js +147 -35
- 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/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 +15 -6
- package/dist/testing/CLAUDE.md +16 -7
- 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/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/expected_schema.json +0 -1
- package/dist/testing/cross_backend/full_spine_mount.js +2 -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/origin_conformance.d.ts +1 -1
- package/dist/testing/cross_backend/origin_conformance.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin_conformance.js +1 -1
- 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_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +64 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +13 -21
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +13 -21
- package/dist/testing/cross_backend/testing_origin_check.d.ts +128 -0
- package/dist/testing/cross_backend/testing_origin_check.d.ts.map +1 -0
- package/dist/testing/cross_backend/testing_origin_check.js +87 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +7 -119
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +8 -92
- 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/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/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
|
@@ -13,6 +13,7 @@ import { z } from 'zod';
|
|
|
13
13
|
import { Uuid, bounded_string } from '../primitive_schemas.js';
|
|
14
14
|
import { FRACTIONAL_INDEX_LENGTH_MAX, FRACTIONAL_INDEX_REGEX } from '@fuzdev/fuz_util/fractional_index.ts';
|
|
15
15
|
import { ActingActor } from '../http/auth_shape.js';
|
|
16
|
+
import { CellRelationListLimit } from './cell_relation_list_limit.js';
|
|
16
17
|
// -- Error reasons ----------------------------------------------------------
|
|
17
18
|
/** Error reason — `cell_item_list` got neither `parent_id` nor `child_id`. */
|
|
18
19
|
export const ERROR_CELL_ITEM_LIST_REQUIRES_PARENT_OR_CHILD = 'cell_item_list_requires_parent_or_child';
|
|
@@ -101,10 +102,11 @@ export const CellItemDeleteOutput = z.strictObject({
|
|
|
101
102
|
* authz (child view-check gates the call; per-parent view-check filters
|
|
102
103
|
* the rows).
|
|
103
104
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
105
|
+
* Either direction returns a page of up to `limit` items (default
|
|
106
|
+
* `CELL_RELATION_LIST_LIMIT_DEFAULT`) whose other end the caller can view —
|
|
107
|
+
* the view check runs before the limit. Forward listing pages on via
|
|
108
|
+
* `position_after` (return rows with `position > position_after`); the
|
|
109
|
+
* reverse listing has no cursor, oldest item first.
|
|
108
110
|
*/
|
|
109
111
|
export const CellItemListInput = z
|
|
110
112
|
.strictObject({
|
|
@@ -117,9 +119,7 @@ export const CellItemListInput = z
|
|
|
117
119
|
position_after: CellItemPosition.optional().meta({
|
|
118
120
|
description: 'Cursor for forward pagination — return rows whose position > this.'
|
|
119
121
|
}),
|
|
120
|
-
limit:
|
|
121
|
-
description: 'Page size cap (max 500). Omit for unbounded — explicit list calls escape the bundled `cell_get` cap.'
|
|
122
|
-
}),
|
|
122
|
+
limit: CellRelationListLimit,
|
|
123
123
|
acting: ActingActor
|
|
124
124
|
})
|
|
125
125
|
.refine((v) => Boolean(v.parent_id) !== Boolean(v.child_id), {
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
* collision-error shape as insert.
|
|
13
13
|
* - `cell_item_delete` — admin / owner / editor-grant on `parent`.
|
|
14
14
|
* Idempotent: `deleted: false` when no row matched.
|
|
15
|
-
* - `cell_item_list` — bidirectional
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* - `cell_item_list` — bidirectional, a page of up to `limit` items whose
|
|
16
|
+
* other end the caller may view (filtered in SQL, before the limit).
|
|
17
|
+
* Forward (pass `parent_id`) is gated on `can_view_cell(parent)` and
|
|
18
|
+
* pages the items whose child is viewable (strict target-visibility).
|
|
19
|
+
* Reverse (pass `child_id`) has 2-layer authz: gate on
|
|
20
|
+
* `can_view_cell(child)`, then page the items whose parent is viewable.
|
|
20
21
|
*
|
|
21
22
|
* IDOR-mask 404s on cell-miss / cell-unviewable, mirroring the existence-
|
|
22
23
|
* leak guards in `auth/cell_actions.ts`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_item_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_item_actions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cell_item_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_item_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAIN,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAeN,KAAK,QAAQ,EACb,MAAM,6BAA6B,CAAC;AAMrC,OAAO,EAMN,KAAK,WAAW,EAChB,MAAM,4BAA4B,CAAC;AAOpC,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEnD,eAAO,MAAM,YAAY,GAAI,KAAK,WAAW,KAAG,QAS9C,CAAC;AAOH,iDAAiD;AACjD,eAAO,MAAM,wBAAwB,GAAI,MAAM,kBAAkB,KAAG,KAAK,CAAC,SAAS,CAwKlF,CAAC"}
|
|
@@ -12,11 +12,12 @@
|
|
|
12
12
|
* collision-error shape as insert.
|
|
13
13
|
* - `cell_item_delete` — admin / owner / editor-grant on `parent`.
|
|
14
14
|
* Idempotent: `deleted: false` when no row matched.
|
|
15
|
-
* - `cell_item_list` — bidirectional
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* - `cell_item_list` — bidirectional, a page of up to `limit` items whose
|
|
16
|
+
* other end the caller may view (filtered in SQL, before the limit).
|
|
17
|
+
* Forward (pass `parent_id`) is gated on `can_view_cell(parent)` and
|
|
18
|
+
* pages the items whose child is viewable (strict target-visibility).
|
|
19
|
+
* Reverse (pass `child_id`) has 2-layer authz: gate on
|
|
20
|
+
* `can_view_cell(child)`, then page the items whose parent is viewable.
|
|
20
21
|
*
|
|
21
22
|
* IDOR-mask 404s on cell-miss / cell-unviewable, mirroring the existence-
|
|
22
23
|
* leak guards in `auth/cell_actions.ts`.
|
|
@@ -31,8 +32,8 @@ import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
|
31
32
|
import { is_pg_unique_violation } from '../db/pg_error.js';
|
|
32
33
|
import { cell_item_insert_action_spec, cell_item_move_action_spec, cell_item_delete_action_spec, cell_item_list_action_spec, ERROR_CELL_ITEM_POSITION_TAKEN } from './cell_item_action_specs.js';
|
|
33
34
|
import { ERROR_CELL_NOT_FOUND } from './cell_action_specs.js';
|
|
34
|
-
import { can_view_cell, can_edit_cell } from './cell_authorize.js';
|
|
35
|
-
import {
|
|
35
|
+
import { can_view_cell, can_edit_cell, cell_viewer_from_auth } from './cell_authorize.js';
|
|
36
|
+
import { CELL_RELATION_LIST_LIMIT_DEFAULT } from './cell_relation_list_limit.js';
|
|
36
37
|
import { query_cell_get } from '../db/cell_queries.js';
|
|
37
38
|
import { query_cell_grant_list_for_cell } from '../db/cell_grant_queries.js';
|
|
38
39
|
import { query_cell_item_insert, query_cell_item_move, query_cell_item_delete, query_cell_item_list_for_parent, query_cell_item_list_for_child } from '../db/cell_item_queries.js';
|
|
@@ -160,8 +161,11 @@ export const create_cell_item_actions = (deps) => {
|
|
|
160
161
|
};
|
|
161
162
|
const list_handler = async (input, ctx) => {
|
|
162
163
|
const auth = ctx.auth;
|
|
163
|
-
//
|
|
164
|
-
|
|
164
|
+
// an omitted limit is the default page, either direction
|
|
165
|
+
const limit = input.limit ?? CELL_RELATION_LIST_LIMIT_DEFAULT;
|
|
166
|
+
// Forward listing: gate on can_view_cell(parent), then page the items
|
|
167
|
+
// whose child the caller may view (strict target-visibility, in SQL
|
|
168
|
+
// before the limit).
|
|
165
169
|
if (input.parent_id !== undefined) {
|
|
166
170
|
const parent = await query_cell_get(ctx, input.parent_id);
|
|
167
171
|
if (!parent) {
|
|
@@ -171,12 +175,8 @@ export const create_cell_item_actions = (deps) => {
|
|
|
171
175
|
if (!can_view_cell(auth, parent, parent_grants)) {
|
|
172
176
|
throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
|
|
173
177
|
}
|
|
174
|
-
const rows = await query_cell_item_list_for_parent(ctx, parent.id, {
|
|
175
|
-
|
|
176
|
-
position_after: input.position_after
|
|
177
|
-
});
|
|
178
|
-
const visible_children = await filter_visible_target_ids(ctx, auth, rows.map((r) => r.child_id));
|
|
179
|
-
return { items: rows.filter((r) => visible_children.has(r.child_id)).map(to_item_json) };
|
|
178
|
+
const rows = await query_cell_item_list_for_parent(ctx, cell_viewer_from_auth(auth), parent.id, { limit, position_after: input.position_after });
|
|
179
|
+
return { items: rows.map(to_item_json) };
|
|
180
180
|
}
|
|
181
181
|
// Reverse listing: 2-layer authz. First, can_view_cell(child).
|
|
182
182
|
const child = await query_cell_get(ctx, input.child_id);
|
|
@@ -187,13 +187,14 @@ export const create_cell_item_actions = (deps) => {
|
|
|
187
187
|
if (!can_view_cell(auth, child, child_grants)) {
|
|
188
188
|
throw jsonrpc_errors.not_found('cell', { reason: ERROR_CELL_NOT_FOUND });
|
|
189
189
|
}
|
|
190
|
-
// Then
|
|
191
|
-
//
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
const rows = await query_cell_item_list_for_child(ctx, child.id, {
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
// Then page the items whose parent the caller may view — filtered in
|
|
191
|
+
// SQL before the limit, so hidden parents never crowd out visible ones,
|
|
192
|
+
// and bounded so a heavily inbound-linked child can't force an
|
|
193
|
+
// unbounded read on this public endpoint.
|
|
194
|
+
const rows = await query_cell_item_list_for_child(ctx, cell_viewer_from_auth(auth), child.id, {
|
|
195
|
+
limit
|
|
196
|
+
});
|
|
197
|
+
return { items: rows.map(to_item_json) };
|
|
197
198
|
};
|
|
198
199
|
return [
|
|
199
200
|
rpc_action(cell_item_insert_action_spec, insert_handler),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page bound the two relation lists share — `cell_field_list` and
|
|
3
|
+
* `cell_item_list`, forward and reverse alike. A page is up to `limit` edges
|
|
4
|
+
* whose other end the caller can view. Both are public reads, so an omitted
|
|
5
|
+
* `limit` is the default page, never unbounded: anyone can pad a public
|
|
6
|
+
* cell's inbound links, and the reverse lists have no cursor.
|
|
7
|
+
*
|
|
8
|
+
* Twin of the Rust spine's `CELL_RELATION_LIST_LIMIT_MAX` /
|
|
9
|
+
* `CELL_RELATION_LIST_LIMIT_DEFAULT`.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
/** Cap on a relation-list page, forward and reverse alike. */
|
|
15
|
+
export declare const CELL_RELATION_LIST_LIMIT_MAX = 500;
|
|
16
|
+
/** The page size a relation list that omits `limit` gets, forward and reverse alike. */
|
|
17
|
+
export declare const CELL_RELATION_LIST_LIMIT_DEFAULT = 50;
|
|
18
|
+
/** The `limit` input of `cell_field_list` and `cell_item_list`. */
|
|
19
|
+
export declare const CellRelationListLimit: z.ZodOptional<z.ZodNumber>;
|
|
20
|
+
//# sourceMappingURL=cell_relation_list_limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cell_relation_list_limit.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_relation_list_limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8DAA8D;AAC9D,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,wFAAwF;AACxF,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAEnD,mEAAmE;AACnE,eAAO,MAAM,qBAAqB,4BAQ/B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page bound the two relation lists share — `cell_field_list` and
|
|
3
|
+
* `cell_item_list`, forward and reverse alike. A page is up to `limit` edges
|
|
4
|
+
* whose other end the caller can view. Both are public reads, so an omitted
|
|
5
|
+
* `limit` is the default page, never unbounded: anyone can pad a public
|
|
6
|
+
* cell's inbound links, and the reverse lists have no cursor.
|
|
7
|
+
*
|
|
8
|
+
* Twin of the Rust spine's `CELL_RELATION_LIST_LIMIT_MAX` /
|
|
9
|
+
* `CELL_RELATION_LIST_LIMIT_DEFAULT`.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
/** Cap on a relation-list page, forward and reverse alike. */
|
|
15
|
+
export const CELL_RELATION_LIST_LIMIT_MAX = 500;
|
|
16
|
+
/** The page size a relation list that omits `limit` gets, forward and reverse alike. */
|
|
17
|
+
export const CELL_RELATION_LIST_LIMIT_DEFAULT = 50;
|
|
18
|
+
/** The `limit` input of `cell_field_list` and `cell_item_list`. */
|
|
19
|
+
export const CellRelationListLimit = z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.positive()
|
|
23
|
+
.max(CELL_RELATION_LIST_LIMIT_MAX)
|
|
24
|
+
.optional()
|
|
25
|
+
.meta({
|
|
26
|
+
description: `The most edges a page holds, each one whose other end the caller can view — forward and reverse alike: default ${CELL_RELATION_LIST_LIMIT_DEFAULT}, max ${CELL_RELATION_LIST_LIMIT_MAX}.`
|
|
27
|
+
});
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* target the caller cannot view — otherwise an editor of a public parent
|
|
7
7
|
* could enumerate private children by id, or a public cell could leak the
|
|
8
8
|
* existence of private linked cells. This helper bulk-loads the target
|
|
9
|
-
* cells
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* cells' view facts (`CELL_VIEW_COLUMNS` — never the `data` payload) and
|
|
10
|
+
* their grants, then runs `can_view_cell` per target in memory, returning
|
|
11
|
+
* the set of viewable target ids. Batched (two queries for the whole
|
|
12
|
+
* id-set) to avoid the N+1 a naive per-row check would cause.
|
|
12
13
|
*
|
|
13
14
|
* @module
|
|
14
15
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_relation_visibility.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_relation_visibility.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cell_relation_visibility.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_relation_visibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACrC,MAAM,SAAS,EACf,MAAM,cAAc,GAAG,IAAI,EAC3B,YAAY,aAAa,CAAC,IAAI,CAAC,KAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAwBnB,CAAC"}
|
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
* target the caller cannot view — otherwise an editor of a public parent
|
|
7
7
|
* could enumerate private children by id, or a public cell could leak the
|
|
8
8
|
* existence of private linked cells. This helper bulk-loads the target
|
|
9
|
-
* cells
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* cells' view facts (`CELL_VIEW_COLUMNS` — never the `data` payload) and
|
|
10
|
+
* their grants, then runs `can_view_cell` per target in memory, returning
|
|
11
|
+
* the set of viewable target ids. Batched (two queries for the whole
|
|
12
|
+
* id-set) to avoid the N+1 a naive per-row check would cause.
|
|
12
13
|
*
|
|
13
14
|
* @module
|
|
14
15
|
*/
|
|
15
16
|
import { can_view_cell } from './cell_authorize.js';
|
|
16
|
-
import {
|
|
17
|
+
import { query_cell_view_load_many } from '../db/cell_queries.js';
|
|
17
18
|
import { query_cell_grant_list_for_cells } from '../db/cell_grant_queries.js';
|
|
18
19
|
/**
|
|
19
20
|
* Return the subset of `target_ids` the caller may view.
|
|
@@ -33,7 +34,7 @@ export const filter_visible_target_ids = async (deps, auth, target_ids) => {
|
|
|
33
34
|
if (target_ids.length === 0)
|
|
34
35
|
return visible;
|
|
35
36
|
const unique = [...new Set(target_ids)];
|
|
36
|
-
const cells = await
|
|
37
|
+
const cells = await query_cell_view_load_many(deps, unique);
|
|
37
38
|
// Grants only matter for authenticated callers — null auth admits via
|
|
38
39
|
// the public branch alone, so skip the grant load entirely.
|
|
39
40
|
const grants_by_cell = new Map();
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The steward read arm, with the governing-root load it needs.
|
|
3
|
+
*
|
|
4
|
+
* `can_steward_cell` (`auth/cell_authorize.ts`) is pure over
|
|
5
|
+
* `(auth, cell, root)`; `cell_steward_admits` is the composition every steward
|
|
6
|
+
* site runs after `can_view_cell` denies: it loads the governing root (active
|
|
7
|
+
* rows only, so a soft-deleted root stewards nothing) and applies the
|
|
8
|
+
* predicate. It short-circuits with no query unless the caller is
|
|
9
|
+
* authenticated and the cell is a pending or rejected contribution.
|
|
10
|
+
*
|
|
11
|
+
* **Where the steward arm applies** — the surfaces a moderator works from:
|
|
12
|
+
* `cell_get`, `cell_moderate` (whose root-authority check it lets a non-admin
|
|
13
|
+
* root owner reach), the cell-scoped fact route, and `cell_list`'s general
|
|
14
|
+
* predicate (the SQL twin in `query_cell_list`).
|
|
15
|
+
*
|
|
16
|
+
* **Where it must not** — every other read keeps `can_view_cell` alone:
|
|
17
|
+
* `cell_clone` (a steward copying a contribution out from under its
|
|
18
|
+
* moderation), the parent check on `cell_create` (a steward contributing under
|
|
19
|
+
* a pending post), the relation endpoint gates, `filter_visible_target_ids`
|
|
20
|
+
* (the `cell_get` bundle), the field / item lists' SQL view filter
|
|
21
|
+
* (`db/cell_view_sql.ts`),
|
|
22
|
+
* `cell_list`'s `shared_with` semi-join (a grant footprint, not a moderation
|
|
23
|
+
* queue), and `cell_grant_revoke`'s `still_admitted` recompute. Widening one of
|
|
24
|
+
* these is a decision, not a sweep. Twin of the Rust `fuz_cell::cell_steward`.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import type { QueryDeps } from '../db/query_deps.js';
|
|
29
|
+
import { type CellRow } from '../db/cell_queries.js';
|
|
30
|
+
import type { RequestContext } from './request_context.js';
|
|
31
|
+
/**
|
|
32
|
+
* Whether `auth` stewards `cell` — loads the governing root and applies
|
|
33
|
+
* `can_steward_cell`.
|
|
34
|
+
*
|
|
35
|
+
* Resolves `false` without a query for an unauthenticated caller, a root, or a
|
|
36
|
+
* cell whose moderation isn't `'pending'` / `'rejected'`; a missing or
|
|
37
|
+
* soft-deleted root is `false` too.
|
|
38
|
+
*
|
|
39
|
+
* @param deps - query deps
|
|
40
|
+
* @param auth - request context, or `null` for unauthenticated callers
|
|
41
|
+
* @param cell - the cell the caller couldn't otherwise view
|
|
42
|
+
* @returns whether the steward arm admits the caller
|
|
43
|
+
*/
|
|
44
|
+
export declare const cell_steward_admits: (deps: QueryDeps, auth: RequestContext | null, cell: CellRow) => Promise<boolean>;
|
|
45
|
+
//# sourceMappingURL=cell_steward.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cell_steward.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/cell_steward.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAC/B,MAAM,SAAS,EACf,MAAM,cAAc,GAAG,IAAI,EAC3B,MAAM,OAAO,KACX,OAAO,CAAC,OAAO,CAMjB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The steward read arm, with the governing-root load it needs.
|
|
3
|
+
*
|
|
4
|
+
* `can_steward_cell` (`auth/cell_authorize.ts`) is pure over
|
|
5
|
+
* `(auth, cell, root)`; `cell_steward_admits` is the composition every steward
|
|
6
|
+
* site runs after `can_view_cell` denies: it loads the governing root (active
|
|
7
|
+
* rows only, so a soft-deleted root stewards nothing) and applies the
|
|
8
|
+
* predicate. It short-circuits with no query unless the caller is
|
|
9
|
+
* authenticated and the cell is a pending or rejected contribution.
|
|
10
|
+
*
|
|
11
|
+
* **Where the steward arm applies** — the surfaces a moderator works from:
|
|
12
|
+
* `cell_get`, `cell_moderate` (whose root-authority check it lets a non-admin
|
|
13
|
+
* root owner reach), the cell-scoped fact route, and `cell_list`'s general
|
|
14
|
+
* predicate (the SQL twin in `query_cell_list`).
|
|
15
|
+
*
|
|
16
|
+
* **Where it must not** — every other read keeps `can_view_cell` alone:
|
|
17
|
+
* `cell_clone` (a steward copying a contribution out from under its
|
|
18
|
+
* moderation), the parent check on `cell_create` (a steward contributing under
|
|
19
|
+
* a pending post), the relation endpoint gates, `filter_visible_target_ids`
|
|
20
|
+
* (the `cell_get` bundle), the field / item lists' SQL view filter
|
|
21
|
+
* (`db/cell_view_sql.ts`),
|
|
22
|
+
* `cell_list`'s `shared_with` semi-join (a grant footprint, not a moderation
|
|
23
|
+
* queue), and `cell_grant_revoke`'s `still_admitted` recompute. Widening one of
|
|
24
|
+
* these is a decision, not a sweep. Twin of the Rust `fuz_cell::cell_steward`.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import { query_cell_get } from '../db/cell_queries.js';
|
|
29
|
+
import { cell_moderation_is_stewardable } from '../db/cell_moderation.js';
|
|
30
|
+
import { can_steward_cell } from './cell_authorize.js';
|
|
31
|
+
/**
|
|
32
|
+
* Whether `auth` stewards `cell` — loads the governing root and applies
|
|
33
|
+
* `can_steward_cell`.
|
|
34
|
+
*
|
|
35
|
+
* Resolves `false` without a query for an unauthenticated caller, a root, or a
|
|
36
|
+
* cell whose moderation isn't `'pending'` / `'rejected'`; a missing or
|
|
37
|
+
* soft-deleted root is `false` too.
|
|
38
|
+
*
|
|
39
|
+
* @param deps - query deps
|
|
40
|
+
* @param auth - request context, or `null` for unauthenticated callers
|
|
41
|
+
* @param cell - the cell the caller couldn't otherwise view
|
|
42
|
+
* @returns whether the steward arm admits the caller
|
|
43
|
+
*/
|
|
44
|
+
export const cell_steward_admits = async (deps, auth, cell) => {
|
|
45
|
+
if (auth === null || cell.root_id === null)
|
|
46
|
+
return false;
|
|
47
|
+
if (!cell_moderation_is_stewardable(cell.moderation))
|
|
48
|
+
return false;
|
|
49
|
+
const root = await query_cell_get(deps, cell.root_id);
|
|
50
|
+
if (!root)
|
|
51
|
+
return false;
|
|
52
|
+
return can_steward_cell(auth, cell, root);
|
|
53
|
+
};
|
|
@@ -212,6 +212,10 @@ export type ResolveActingActorResult = {
|
|
|
212
212
|
* The available list is intentionally not echoed in this branch (treat
|
|
213
213
|
* as opaque rejection).
|
|
214
214
|
*
|
|
215
|
+
* `acting_actor_id` is compared lowercased, the form actor ids are stored and
|
|
216
|
+
* read back in, so a caller passing an id that skipped the `Uuid` schema
|
|
217
|
+
* still matches its actor whatever its case.
|
|
218
|
+
*
|
|
215
219
|
* @param deps - query dependencies
|
|
216
220
|
* @param account_id - the authenticated account
|
|
217
221
|
* @param acting_actor_id - the requested acting actor id, or `undefined`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,KAAK,EAEV,KAAK,SAAS,EACd,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAmBrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAA6C,KAAK,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElG,OAAO,EAIN,oBAAoB,EACpB,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AAErD;;;;;;;;GAQG;AACH,eAAO,MAAM,2BAA2B,4BAA4B,CAAC;AAErE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,GAAG,OAAO,KAAG,cAAc,GAAG,IAEjE,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,GAAI,GAAG,OAAO,KAAG,cAQpD,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IAC1D,KAAK,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,QAAQ,GACpB,KAAK,cAAc,GAAG,IAAI,EAC1B,MAAM,MAAM,EACZ,MAAK,IAAiB,KACpB,OACoF,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,eAAe,GAC3B,KAAK,cAAc,GAAG,IAAI,EAC1B,MAAM,MAAM,EACZ,UAAU,MAAM,GAAG,IAAI,EACvB,MAAK,IAAiB,KACpB,OAKF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC/B,KAAK,cAAc,GAAG,IAAI,EAC1B,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,UAAU,MAAM,GAAG,IAAI,EACvB,MAAK,IAAiB,KACpB,OAMF,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GACvF;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAEjD
|
|
1
|
+
{"version":3,"file":"request_context.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/request_context.ts"],"names":[],"mappings":"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"}
|
|
@@ -181,6 +181,10 @@ export const has_any_scoped_role = (ctx, roles, scope_id, now = new Date()) => {
|
|
|
181
181
|
* The available list is intentionally not echoed in this branch (treat
|
|
182
182
|
* as opaque rejection).
|
|
183
183
|
*
|
|
184
|
+
* `acting_actor_id` is compared lowercased, the form actor ids are stored and
|
|
185
|
+
* read back in, so a caller passing an id that skipped the `Uuid` schema
|
|
186
|
+
* still matches its actor whatever its case.
|
|
187
|
+
*
|
|
184
188
|
* @param deps - query dependencies
|
|
185
189
|
* @param account_id - the authenticated account
|
|
186
190
|
* @param acting_actor_id - the requested acting actor id, or `undefined`
|
|
@@ -198,7 +202,8 @@ export const resolve_acting_actor = async (deps, account_id, acting_actor_id) =>
|
|
|
198
202
|
available: actors.map((a) => ({ id: a.id, name: a.name }))
|
|
199
203
|
};
|
|
200
204
|
}
|
|
201
|
-
const
|
|
205
|
+
const acting = acting_actor_id.toLowerCase();
|
|
206
|
+
const match = actors.find((a) => a.id === acting);
|
|
202
207
|
if (!match)
|
|
203
208
|
return { ok: false, reason: 'actor_not_on_account' };
|
|
204
209
|
return { ok: true, actor_id: match.id };
|
|
@@ -310,6 +310,10 @@ export declare const role_grant_offer_create_action_spec: {
|
|
|
310
310
|
rate_limit: "account";
|
|
311
311
|
};
|
|
312
312
|
/**
|
|
313
|
+
* `rate_limit: 'account'`, matching `role_grant_offer_create`: every call locks
|
|
314
|
+
* the offer row and reads its grant, and a replay of an accepted offer answers
|
|
315
|
+
* without minting anything, so the account bucket is what bounds a loop of them.
|
|
316
|
+
*
|
|
313
317
|
* `credential_types: ['session']` — see `docs/security.md` §Credential-channel
|
|
314
318
|
* gating. The only offer verb that moves the *caller's own* authority:
|
|
315
319
|
* accepting a pending admin offer over a leaked API token is a privilege pivot
|
|
@@ -359,6 +363,7 @@ export declare const role_grant_offer_accept_action_spec: {
|
|
|
359
363
|
async: true;
|
|
360
364
|
description: string;
|
|
361
365
|
error_reasons: ("role_grant_offer_terminal" | "role_grant_offer_expired" | "role_grant_offer_not_found" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_mismatch" | "role_grant_builtin_scoped")[];
|
|
366
|
+
rate_limit: "account";
|
|
362
367
|
};
|
|
363
368
|
export declare const role_grant_offer_decline_action_spec: {
|
|
364
369
|
method: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -240,6 +240,10 @@ export const role_grant_offer_create_action_spec = {
|
|
|
240
240
|
rate_limit: 'account'
|
|
241
241
|
};
|
|
242
242
|
/**
|
|
243
|
+
* `rate_limit: 'account'`, matching `role_grant_offer_create`: every call locks
|
|
244
|
+
* the offer row and reads its grant, and a replay of an accepted offer answers
|
|
245
|
+
* without minting anything, so the account bucket is what bounds a loop of them.
|
|
246
|
+
*
|
|
243
247
|
* `credential_types: ['session']` — see `docs/security.md` §Credential-channel
|
|
244
248
|
* gating. The only offer verb that moves the *caller's own* authority:
|
|
245
249
|
* accepting a pending admin offer over a leaked API token is a privilege pivot
|
|
@@ -268,7 +272,8 @@ export const role_grant_offer_accept_action_spec = {
|
|
|
268
272
|
ERROR_ROLE_GRANT_OFFER_ROLE_NOT_GRANTABLE,
|
|
269
273
|
ERROR_ROLE_GRANT_BUILTIN_SCOPED,
|
|
270
274
|
ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED
|
|
271
|
-
]
|
|
275
|
+
],
|
|
276
|
+
rate_limit: 'account'
|
|
272
277
|
};
|
|
273
278
|
export const role_grant_offer_decline_action_spec = {
|
|
274
279
|
method: 'role_grant_offer_decline',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_offer_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAGN,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AA4B1B,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAON,KAAK,kBAAkB,EACvB,MAAM,qCAAqC,CAAC;AAyC7C;;;;;;;;GAQG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC3C,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACvE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EACrB,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,qDAAqD;AACrD,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,0FAA0F;IAC1F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,6BAA6B,CAAC;CAC1C;AA6CD;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,GAC3C,MAAM,iBAAiB,GAAG;IACzB,mBAAmB,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAChD,EACD,UAAS,2BAAgC,KACvC,KAAK,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"role_grant_offer_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_actions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAGN,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAKN,KAAK,gBAAgB,EACrB,MAAM,kBAAkB,CAAC;AA4B1B,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAON,KAAK,kBAAkB,EACvB,MAAM,qCAAqC,CAAC;AAyC7C;;;;;;;;GAQG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC3C,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACvE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EACrB,GAAG,EAAE,aAAa,KACd,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,qDAAqD;AACrD,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,0FAA0F;IAC1F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,6BAA6B,CAAC;CAC1C;AA6CD;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,GAC3C,MAAM,iBAAiB,GAAG;IACzB,mBAAmB,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAChD,EACD,UAAS,2BAAgC,KACvC,KAAK,CAAC,SAAS,CA8nBjB,CAAC"}
|
|
@@ -296,8 +296,9 @@ export const create_role_grant_offer_actions = (deps, options = {}) => {
|
|
|
296
296
|
// Look up the grantor's account_id inside the transaction so the
|
|
297
297
|
// post-commit notification has a valid target. One cheap SELECT by
|
|
298
298
|
// PK — the alternative (widening `query_accept_offer` again) would
|
|
299
|
-
// bleed transport concerns into the query layer.
|
|
300
|
-
|
|
299
|
+
// bleed transport concerns into the query layer. A replay
|
|
300
|
+
// (`created: false`) notifies nothing, so it skips the lookup.
|
|
301
|
+
const grantor_actor = notification_sender && result.created
|
|
301
302
|
? await query_actor_by_id(ctx, result.offer.from_actor_id)
|
|
302
303
|
: null;
|
|
303
304
|
const grantor_account_id = grantor_actor?.account_id ?? null;
|
|
@@ -312,21 +313,27 @@ export const create_role_grant_offer_actions = (deps, options = {}) => {
|
|
|
312
313
|
// grantor sees "accepted" and each superseded grantor sees "supersede"
|
|
313
314
|
// only once the accept has durably committed — and never if it rolls
|
|
314
315
|
// back (the dispatch site discards `post_commit_effects` on rollback).
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
reason: 'sibling_accepted',
|
|
325
|
-
cause_id: result.offer.id
|
|
326
|
-
}));
|
|
316
|
+
// A replay (or a race loser) wrote nothing — the accept that minted the
|
|
317
|
+
// grant already audited it and notified the grantor — so it queues
|
|
318
|
+
// nothing; repeating the notification would let any replay send them
|
|
319
|
+
// without bound.
|
|
320
|
+
if (result.created) {
|
|
321
|
+
emit_after_commit(ctx, () => {
|
|
322
|
+
fan_out_audit_events(result.audit_events, audit);
|
|
323
|
+
if (notification_sender && grantor_account_id) {
|
|
324
|
+
notification_sender.send_to_account(grantor_account_id, build_role_grant_offer_accepted_notification({ offer: offer_json }));
|
|
327
325
|
}
|
|
328
|
-
|
|
329
|
-
|
|
326
|
+
if (notification_sender) {
|
|
327
|
+
for (const sib of supersede_payloads) {
|
|
328
|
+
notification_sender.send_to_account(sib.from_account_id, build_role_grant_offer_supersede_notification({
|
|
329
|
+
offer: sib.offer,
|
|
330
|
+
reason: 'sibling_accepted',
|
|
331
|
+
cause_id: result.offer.id
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
330
337
|
return {
|
|
331
338
|
role_grant_id: result.role_grant.id,
|
|
332
339
|
offer: offer_json,
|
|
@@ -232,7 +232,7 @@ export interface AcceptOfferInput {
|
|
|
232
232
|
export interface AcceptOfferResult {
|
|
233
233
|
role_grant: RoleGrant;
|
|
234
234
|
offer: RoleGrantOffer;
|
|
235
|
-
/** `true` if this call is the one that accepted the offer (new role_grant inserted); `false` on a race returning the already-created role_grant. */
|
|
235
|
+
/** `true` if this call is the one that accepted the offer (new role_grant inserted); `false` on a replay (or a race loser) returning the already-created, still-held role_grant — the caller then audits and notifies nothing. */
|
|
236
236
|
created: boolean;
|
|
237
237
|
/**
|
|
238
238
|
* Sibling offers superseded by this accept — empty on the race-loser path.
|
|
@@ -252,15 +252,17 @@ export interface AcceptOfferResult {
|
|
|
252
252
|
* inside a transaction — the caller's route spec should declare
|
|
253
253
|
* `transaction: true` (or wrap explicitly).
|
|
254
254
|
*
|
|
255
|
-
* Idempotent on race:
|
|
256
|
-
*
|
|
257
|
-
* duplicate or throwing.
|
|
255
|
+
* Idempotent on replay and on race: a call that observes the offer already
|
|
256
|
+
* accepted returns the existing role_grant (`created: false`) rather than
|
|
257
|
+
* creating a duplicate or throwing — while that grant is still held. A grant
|
|
258
|
+
* revoked since the accept, or gone, makes the offer terminal.
|
|
258
259
|
*
|
|
259
260
|
* Error map:
|
|
260
261
|
* - `RoleGrantOfferNotFoundError` — offer does not exist, or belongs to a
|
|
261
262
|
* different recipient (IDOR guard). The offer row is untouched.
|
|
262
263
|
* - `RoleGrantOfferAlreadyTerminalError` — offer is declined, retracted, or
|
|
263
|
-
* superseded
|
|
264
|
+
* superseded; or accepted, and its grant revoked, gone, or bound to another
|
|
265
|
+
* actor.
|
|
264
266
|
* - `RoleGrantOfferExpiredError` — offer is pending but past `expires_at`.
|
|
265
267
|
* - `RoleGrantOfferActorMismatchError` — actor-targeted offer, different actor.
|
|
266
268
|
* - `RoleGrantOfferBuiltinRefusedError` — a builtin-role offer that must not
|
|
@@ -277,7 +279,7 @@ export interface AcceptOfferResult {
|
|
|
277
279
|
* @mutates `role_grant_offer` siblings - stamps `superseded_at` on every other pending offer for the tuple
|
|
278
280
|
* @mutates `audit_log` table - emits `role_grant_offer_accept` + `role_grant_create` + one `role_grant_offer_supersede` per sibling
|
|
279
281
|
* @throws RoleGrantOfferNotFoundError if the offer is missing or belongs to another recipient
|
|
280
|
-
* @throws RoleGrantOfferAlreadyTerminalError if the offer is declined, retracted, or superseded
|
|
282
|
+
* @throws RoleGrantOfferAlreadyTerminalError if the offer is declined, retracted, or superseded, or accepted with its grant revoked, gone, or bound to another actor
|
|
281
283
|
* @throws RoleGrantOfferExpiredError if the offer is pending but past `expires_at`
|
|
282
284
|
* @throws RoleGrantOfferActorMismatchError if the offer is actor-targeted to a different actor
|
|
283
285
|
* @throws RoleGrantOfferBuiltinRefusedError if a builtin-role offer must not mint (see `BuiltinOfferRefusal`)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_offer_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_queries.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"role_grant_offer_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_queries.ts"],"names":[],"mappings":"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"}
|