Files
skills/docs/networking/drive/drive-sharing/src/partitions/partition-manager/partition-manager.md
2026-05-29 08:20:56 +01:00

5.3 KiB

partitions/partition-manager/partition-manager.ts

(no submodules)

Purpose

PartitionManager orchestrates the lifecycle of partition records. It accepts a PartitionStore for persistence and a KeyRing for per-user key material, validates every mutation against the active policy via validateAction, and emits partition:* and member:* events on a caller-supplied EventBusLike. The manager is the single throat through which all partition state changes pass; downstream modules (grants, tokens, transfer) treat the partition as immutable input.

Features

  • Five mutating operations (create, delete, addMember, removeMember, update) plus three read-only operations (get, list, getKeyRing).
  • Zod-validated inputs at every public entrypoint via CreatePartitionOptionsSchema / AddMemberOptionsSchema / UpdatePartitionOptionsSchema.
  • Injectable Clock for deterministic timestamping and an injectable id generator for deterministic IDs in tests.
  • EventBusLike<PartitionManagerEvents> carries partition:created, partition:deleted, partition:updated, member:added, member:removed. No key material in event payloads.
  • OTel spans on every mutating operation; counter share.partition.member_total per partition; counter share.partition.create_total.
  • Graceful-degradation read-only toggle (setReadOnly) — mutations throw SHARE_POLICY_VIOLATION while the flag is true.

Usage: Basic Example

import { PartitionManager } from "@suaveplan/drive-sharing/partitions/partition-manager";
import { InMemoryPartitionStore } from "@suaveplan/drive-sharing/partitions/partition-store";
import { KeyRing } from "@suaveplan/drive-sharing/encryption/key-ring";
import { userId } from "@suaveplan/drive-sharing/types/common";

const manager = new PartitionManager({
    store: new InMemoryPartitionStore(),
    keyRing: new KeyRing(),
});

const partition = await manager.create({
    name: "research",
    type: "shared",
    ownerId: userId("alice"),
});

Usage: Advanced Example

import { PartitionManager } from "@suaveplan/drive-sharing/partitions/partition-manager";
import { InMemoryPartitionStore } from "@suaveplan/drive-sharing/partitions/partition-store";
import { KeyRing } from "@suaveplan/drive-sharing/encryption/key-ring";
import { partitionId, userId } from "@suaveplan/drive-sharing/types/common";

let now = 0;
let counter = 0;
const events = new Map<string, unknown[]>();
const bus = {
    on: () => () => {},
    emit: (k: string, p: unknown) => {
        const arr = events.get(k) ?? [];
        arr.push(p);
        events.set(k, arr);
    },
};

const manager = new PartitionManager({
    store: new InMemoryPartitionStore(),
    keyRing: new KeyRing(),
    clock: () => (now += 1000),
    idGenerator: () => `id-${(counter += 1)}`,
    events: bus,
});

const p = await manager.create({
    name: "vault",
    type: "encrypted",
    ownerId: userId("alice"),
    policy: { maxMembers: 3 },
});

await manager.addMember(p.id, userId("bob"), { permissions: ["read"] });
manager.setReadOnly(true);
// further mutations throw SHARE_POLICY_VIOLATION

API Reference

class PartitionManager

  • constructor(config: PartitionManagerConfig)
  • create(options): Promise<Partition>
  • get(id): Promise<Partition> — throws SHARE_PARTITION_NOT_FOUND.
  • list(): Promise<Partition[]>
  • delete(id): Promise<void>
  • addMember(id, userId, options?): Promise<Partition> — throws SHARE_POLICY_VIOLATION when policy denies.
  • removeMember(id, userId): Promise<Partition> — idempotent.
  • update(id, options): Promise<Partition>
  • setReadOnly(value): void / isReadOnly(): boolean
  • getKeyRing(): KeyRing

interface CreatePartitionOptions

{ name, type, ownerId, policy? }.

interface AddMemberOptions

{ permissions?, wrappedKey? }. Default permissions are ["read"].

interface UpdatePartitionOptions

{ name?, policy? }.

interface PartitionManagerEvents

partition:created / partition:deleted / partition:updated / member:added / member:removed. No key material.

interface PartitionManagerConfig

{ store, keyRing, policy?, clock?, events?, idGenerator? }.

Implementation Notes

  • The default policy is computed once in the constructor (createPolicy(config.policy ?? {})). Per-partition policies are layered on top via mergePolicies in create and update.
  • addMember validates the partition's policy against the action share (the canonical "I am modifying membership" verb); when the policy denies, the call throws SHARE_POLICY_VIOLATION. Importantly, the check is performed against the partition's CURRENT membership — adding the Nth member when maxMembers is N triggers the denial branch.
  • removeMember is intentionally idempotent. Calling it twice with the same userId returns the same partition the second time and does NOT emit member:removed. This matches the spec scenario "RemoveMember restores count".
  • setReadOnly(true) is the spec's documented graceful-degradation hook; the partition store's health check is the trigger but the toggle is exposed publicly so consumers can wire any policy they like.
  • Event emission is fire-and-forget — the EventBusLike.emit contract is synchronous and does not surface listener errors. Asynchronous side effects belong to the listener, not the manager.