auth/cell_action_specs.ts

Cell RPC action specs — the declarative contract for the six generic cell verbs. App vocabulary (galleries, posts, events) lives in client-side helpers; the wire stays generic.

view source

Declarations
#

42 declarations

all_cell_action_specs
#

auth/cell_action_specs.ts view source

readonly [{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ data: ZodObject<{ label: ZodOptional<ZodString>; summary: ZodOptional<...>; }, $loose>; ... 4 more ...; acting: ZodOptional<...>; }, $strict>; output:... import {all_cell_action_specs} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

All cell-layer action specs — composed by app registries. Bundles the seven generic verbs (this module), the three cell_grant_* specs, the three cell_field_* specs, the four cell_item_* specs, and the cell_audit_list spec so codegen + UI clients see a single cell namespace.

cell_clone_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ source_id: $ZodBranded<ZodUUID, "Uuid", "out">; deep: ZodOptional<...>; with_data_patch: ZodOptional<...>; acting: ZodOptional<...>; }, $strict>; output: ZodObj... import {cell_clone_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

cell_create_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ data: ZodObject<{ label: ZodOptional<ZodString>; summary: ZodOptional<...>; }, $loose>; ... 4 more ...; acting: ZodOptional<...>; }, $strict>; output: ZodObject... import {cell_create_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

cell_delete_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; acting: ZodOptional<...>; }, $strict>; output: ZodObject<...>; async: true; description: string; } import {cell_delete_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

cell_get_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "optional"; actor: "optional"; }; side_effects: false; input: ZodObject<{ id: ZodOptional<$ZodBranded<ZodUUID, "Uuid", "out">>; path: ZodOptional<...>; acting: ZodOptional<...>; }, $strict>; output: ZodObject<...>; async: true; rate_... import {cell_get_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

cell_list_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "optional"; actor: "optional"; }; side_effects: false; input: ZodDefault<ZodObject<{ ids: ZodOptional<ZodArray<$ZodBranded<ZodUUID, "Uuid", "out">>>; ... 12 more ...; acting: ZodOptional<...>; }, $strict>>; output: ZodObject<...>; as... import {cell_list_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CELL_LIST_LIMIT_DEFAULT
#

CELL_LIST_LIMIT_MAX
#

auth/cell_action_specs.ts view source

200 import {CELL_LIST_LIMIT_MAX} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Soft cap on the size of a cell.list request page. Larger pages chew memory both server- and client-side; combined with the visibility predicate's filter cost, 200 is a safe ceiling.

cell_moderate_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; moderation: ZodEnum<...>; acting: ZodOptional<...>; }, $strict>; output: ZodObject<...>; async: true; rate_limit: ... import {cell_moderate_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CELL_PATH_LENGTH_MAX
#

auth/cell_action_specs.ts view source

256 import {CELL_PATH_LENGTH_MAX} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Wire form for cell.path.

At the spec level we only enforce that the value is a non-empty string with a sane upper bound — the cell layer is generic and doesn't impose a path grammar. App-side curation (well-known names like /map/main, /site/events) is admin-driven.

CELL_RELATIONS_BUNDLE_LIMIT
#

auth/cell_action_specs.ts view source

500 import {CELL_RELATIONS_BUNDLE_LIMIT} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Hard cap on bundled relation arrays in cell_get (per-relation LIMIT). Beyond this the response sets *_truncated: true and the client paginates via cell_item_list({parent_id, position_after}) / cell_field_list({source_id, name_after}).

cell_update_action_spec
#

auth/cell_action_specs.ts view source

{ method: string; kind: "request_response"; initiator: "frontend"; auth: { account: "required"; actor: "required"; }; side_effects: true; input: ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; data: ZodOptional<...>; visibility: ZodOptional<...>; path: ZodOptional<...>; acting: ZodOptional<...>; }, $strict... import {cell_update_action_spec} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellCloneInput
#

auth/cell_action_specs.ts view source

ZodObject<{ source_id: $ZodBranded<ZodUUID, "Uuid", "out">; deep: ZodOptional<ZodBoolean>; with_data_patch: ZodOptional<ZodObject<{ label: ZodOptional<ZodString>; summary: ZodOptional<...>; }, $loose>>; acting: ZodOptional<...>; }, $strict> import type {CellCloneInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_clone. Source must be view-admitted by can_view_cell (404 otherwise — IDOR mask). The clone is owned by the caller; path is always nulled (admin-only paths can't auto-clone). Provenance lives only in the cell_clone audit row's source_id — no provenance fields are stamped into data.

CellCloneOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>; }, $strict> import type {CellCloneOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellCreateInput
#

auth/cell_action_specs.ts view source

ZodObject<{ data: ZodObject<{ label: ZodOptional<ZodString>; summary: ZodOptional<ZodString>; }, $loose>; kind: ZodOptional<ZodNullable<ZodString>>; visibility: ZodOptional<...>; path: ZodOptional<...>; parent_id: ZodOptional<...>; acting: ZodOptional<...>; }, $strict> import type {CellCreateInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_create. created_by is NOT on the wire — the handler stamps it from auth.actor.id. path is admin-only; non-admin callers supplying path get ERROR_CELL_PATH_ADMIN_ONLY (forbidden).

CellCreateOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>; }, $strict> import type {CellCreateOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellDeleteInput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; acting: ZodOptional<$ZodBranded<ZodUUID, "Uuid", "out">>; }, $strict> import type {CellDeleteInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellDeleteOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ ok: ZodLiteral<true>; deleted: ZodBoolean; }, $strict> import type {CellDeleteOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellGetInput
#

auth/cell_action_specs.ts view source

ZodObject<{ id: ZodOptional<$ZodBranded<ZodUUID, "Uuid", "out">>; path: ZodOptional<$ZodBranded<ZodString, "CellPath", "out">>; acting: ZodOptional<...>; }, $strict> import type {CellGetInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_get. Pass id OR path (exactly one expected; both accepted, id takes precedence). The handler responds with 404 when no row matches OR when can_view_cell rejects the caller — same code so private-cell existence doesn't leak.

CellGetOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>; ... 5 more ...; can_grant: ZodBoolean; }, $strict> import type {CellGetOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Output for cell_get. Bundles relation arrays (fields + items) server-side via JOINs so the common "show this cell with its children" flow needs one round-trip. Targets are filtered to those the caller may view (strict target-visibility). Per-relation `LIMIT CELL_RELATIONS_BUNDLE_LIMIT`; clients paginate via cell_item_list({parent_id, position_after}) / cell_field_list({source_id}) when truncated.

CellJson
#

auth/cell_action_specs.ts view source

ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; data: ZodObject<...>; ... 11 more ...; grant_count: ZodNumber; }, $strict> import type {CellJson} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Wire form for a cell row. data is the typed-but-permissive CellData shape (kind / label / summary typed-and-optional, additional fields pass through). Per-kind shape validation is sub-API and handled by the app's validate_data deps callback (see auth/cell_actions.ts).

visibility is the access-control axis — a top-level column on the row, not a field inside data. cell_grant and visibility are the two ACL surfaces; both live as peers, not embedded in content.

path is the global namespace axis (no tenant/hub scoping).

Relations (items, fields) are NOT carried on the cell row — they live in the cell_item / cell_field sibling tables. Bundled arrays appear on CellGetOutput; other read verbs (cell_list) do not bundle.

CellListInput
#

auth/cell_action_specs.ts view source

ZodDefault<ZodObject<{ ids: ZodOptional<ZodArray<$ZodBranded<ZodUUID, "Uuid", "out">>>; kind: ZodOptional<ZodString>; ... 11 more ...; acting: ZodOptional<...>; }, $strict>> import type {CellListInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_list. Filters are optional and combine with AND. The handler applies the SQL-side visibility predicate from query_cell_list so the page-window stays correct under pagination — post-filtering in JS would silently truncate pages.

ids is the batch-read filter — pass a list of cell ids to fetch them in one round-trip (avoids N+1 when rendering a collection's items[]). The visibility predicate still runs, so callers passing ids they can't view simply get fewer rows back. Capped at CELL_LIST_LIMIT_MAX.

shared_with: 'me' narrows to cells that admit the caller via a cell_grant row (actor-shaped or role-shaped principal) AND that the caller does not own. Authenticated only; combine with kind / path_prefix etc. to scope further. Combining with created_by: <my-actor-id> produces an empty result by definition (owner is implicit, never appears as a grant principal); we don't reject the combination at the schema layer because SQL emptiness is correct.

CellListOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cells: ZodArray<ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>>; cell_grants: ZodOptional<...>; }, $strict> import type {CellListOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellModerateInput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; moderation: ZodEnum<{ approved: "approved"; rejected: "rejected"; }>; acting: ZodOptional<$ZodBranded<ZodUUID, "Uuid", "out">>; }, $strict> import type {CellModerateInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_moderate — the pending → approved | rejected transition, gated on moderation authority over the governing root (admin / root owner in v1), not the contribution (which the author manages, and could otherwise self-approve). 404 when the target isn't viewable; 403 when it is but the caller isn't a root manager (the author lands here).

CellModerateOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>; }, $strict> import type {CellModerateOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellModerationDecision
#

auth/cell_action_specs.ts view source

ZodEnum<{ approved: "approved"; rejected: "rejected"; }> import type {CellModerationDecision} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

The terminal transition a cell_moderate call applies to a gated contribution's moderation lifecycle. The born state ('pending') is set by the create authorizer, never on the wire; the verb only moves it to a terminal state. 'approved' publishes (also flips visibility → 'public'); 'rejected' leaves it private.

CellPath
#

auth/cell_action_specs.ts view source

$ZodBranded<ZodString, "CellPath", "out"> import type {CellPath} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Branded so the type system distinguishes a validated path from any other string. Construct via CellPath.parse(s) at external boundaries; the RPC dispatcher does this automatically when the wire schema (CellCreateInput, CellGetInput, CellUpdateInput, CellListInput) is parsed at the entry point. Frontend callers handing a raw string to api.cell_* cast at the callsite (as CellPath) — the runtime check still runs server-side.

CellUpdateInput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell_id: $ZodBranded<ZodUUID, "Uuid", "out">; data: ZodOptional<ZodObject<{ label: ZodOptional<ZodString>; summary: ZodOptional<ZodString>; }, $loose>>; visibility: ZodOptional<...>; path: ZodOptional<...>; acting: ZodOptional<...>; }, $strict> import type {CellUpdateInput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Input for cell_update. Fields left undefined keep their existing value. path writes are admin-only (handler-enforced); non-admin callers supplying path get ERROR_CELL_PATH_ADMIN_ONLY even if no other field is changing. visibility writes require the manage tier (can_manage_cell = admin / owner) — editor-grant holders editing data cannot flip visibility (ERROR_CELL_VISIBILITY_MANAGE_ONLY).

CellUpdateOutput
#

auth/cell_action_specs.ts view source

ZodObject<{ cell: ZodObject<{ id: $ZodBranded<ZodUUID, "Uuid", "out">; path: ZodNullable<$ZodBranded<ZodString, "CellPath", "out">>; ... 12 more ...; grant_count: ZodNumber; }, $strict>; }, $strict> import type {CellUpdateOutput} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

CellVisibility
#

auth/cell_action_specs.ts view source

ZodEnum<{ private: "private"; public: "public"; }> import type {CellVisibility} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Cell visibility — the coarse-grained access-control axis for a cell. Sibling to cell_grant (the fine-grained allowlist of actor- / role-shaped principals at viewer / editor levels). Together they form the cell-layer access-control surface:

  • cell.visibility = 'public' admits everyone, including unauthenticated visitors. cell_grant rows still apply for edit- level admit; read is universal.
  • cell.visibility = 'private' (default) restricts read to admin / owner (created_by) / cell_grant-admitted callers.

Stored as a top-level PG enum column (cell.visibility) — NOT inside cell.data, which is content metadata only. can_view_cell reads the column directly.

ERROR_CELL_CREATE_FORBIDDEN
#

auth/cell_action_specs.ts view source

"cell_create_forbidden" import {ERROR_CELL_CREATE_FORBIDDEN} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — the parent-aware CellCreateAuthorize denied the create for a viewable parent (or a root creation): "you see it, you can't contribute here." A 403 forbidden, distinct from the create-path 404 mask used when the parent itself isn't viewable (twin of the Rust ERROR_CELL_CREATE_FORBIDDEN).

ERROR_CELL_GET_REQUIRES_ID_OR_PATH
#

auth/cell_action_specs.ts view source

"cell_get_requires_id_or_path" import {ERROR_CELL_GET_REQUIRES_ID_OR_PATH} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — input shape for cell_get lacked both id and path.

ERROR_CELL_KIND_EMPTY
#

auth/cell_action_specs.ts view source

"cell_kind_empty" import {ERROR_CELL_KIND_EMPTY} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — cell_create was given an empty-string kind. kind is a non-empty capability tag or absent (null = typeless cell); "" (a tag that tags nothing) is rejected fail-loud so kind stays a clean null | non-empty-string (twin of the Rust ERROR_CELL_KIND_EMPTY).

ERROR_CELL_KIND_IN_DATA
#

auth/cell_action_specs.ts view source

"cell_kind_in_data" import {ERROR_CELL_KIND_IN_DATA} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — a kind key was supplied inside data. kind is a top-level column (cell.kind), not content metadata; accepting it inside data would create two sources of truth. Rejected fail-loud at the create / update / clone-patch boundary so the column stays canonical.

ERROR_CELL_LIST_CREATED_BY_REQUIRES_AUTH
#

auth/cell_action_specs.ts view source

"cell_list_created_by_requires_auth" import {ERROR_CELL_LIST_CREATED_BY_REQUIRES_AUTH} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — null-auth cell_list caller passed a created_by filter. The filter is a soft account-id enumeration vector ("does account X have any public cells?"), so we require an authenticated caller to use it.

ERROR_CELL_LIST_SHARED_WITH_REQUIRES_AUTH
#

auth/cell_action_specs.ts view source

"cell_list_shared_with_requires_auth" import {ERROR_CELL_LIST_SHARED_WITH_REQUIRES_AUTH} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — null-auth cell_list caller passed shared_with: 'me'. The filter resolves to the caller's account + role_grants, which only exist for an authenticated session.

ERROR_CELL_MODERATE_FORBIDDEN
#

auth/cell_action_specs.ts view source

"cell_moderate_forbidden" import {ERROR_CELL_MODERATE_FORBIDDEN} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — cell_moderate caller can view the contribution but lacks moderation authority over its governing root (not admin / not the root's manager). A 403 forbidden. The author can view their own pending contribution, so they reach this gate — and are denied here, which is the anti-self-approval guard (twin of the Rust ERROR_CELL_MODERATE_FORBIDDEN).

ERROR_CELL_NOT_A_CONTRIBUTION
#

auth/cell_action_specs.ts view source

"cell_not_a_contribution" import {ERROR_CELL_NOT_A_CONTRIBUTION} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — cell_moderate target has no governing root (root_id is null): it's a root or an unparented cell, not a gated contribution, so there is nothing to moderate. A 400 invalid_params (twin of the Rust ERROR_CELL_NOT_A_CONTRIBUTION).

ERROR_CELL_NOT_FOUND
#

auth/cell_action_specs.ts view source

"cell_not_found" import {ERROR_CELL_NOT_FOUND} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — cell id did not resolve, or caller can't view it.

ERROR_CELL_PATH_ADMIN_ONLY
#

auth/cell_action_specs.ts view source

"cell_path_admin_only" import {ERROR_CELL_PATH_ADMIN_ONLY} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — caller is not an admin and supplied a path write.

ERROR_CELL_PATH_TAKEN
#

auth/cell_action_specs.ts view source

"cell_path_taken" import {ERROR_CELL_PATH_TAKEN} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — a path write collided with an existing active cell's path. path is globally unique on active rows (idx_cell_path_unique); the create / update handlers translate the unique-index violation into this conflict (409) reason rather than leaking a raw internal error. Soft-deleted rows free their path (the index is partial on deleted_at IS NULL), so reusing a deleted cell's path does not collide.

ERROR_CELL_VISIBILITY_MANAGE_ONLY
#

auth/cell_action_specs.ts view source

"cell_visibility_manage_only" import {ERROR_CELL_VISIBILITY_MANAGE_ONLY} from '@fuzdev/fuz_app/auth/cell_action_specs.js';

Error reason — caller tried to write cell.visibility without the manage tier (can_manage_cell = admin / owner). Editor-grant holders may edit data but cannot flip a cell's visibility — that is a manage-tier-only operation.

Re-exports
#

Depends on
#

Imported by
#