@cfxlabsinc/b2b-services
    Preparing search index...

    Root of the organization class hierarchy: it owns the one organization-search cache both surfaces share and the seam that busts it.

    Every reader and writer of organization extends this class — OrganizationQueryService / OrganizationService on the consumer side, OrganizationAdminQueryService / OrganizationAdminService on the admin side (whose AiPrise verification callbacks write the table without going through OrganizationService). See SearchCache for why the cache lives at the root rather than beside each service.

    Collapsing the two former namespaces buys more than deduplication: the admin search previously tagged every entry with a single collection tag, so any write to any customer evicted every cached admin page. Admin entries now carry the customer ids their filter scoped to, and fall back to the collection tag only when genuinely unscoped.

    Hierarchy (View Summary)

    Index
    cache: ServiceCache<CachedSearchPage<OrgWithCustomer>>
    • Clear each customer's membership tag and each record tag wherever cached, and always this namespace's collection tag. keys are exact deletes in this instance's key space: the only bust a null client honours.

      Parameters

      • __namedParameters: {
            customerIds: readonly string[];
            keys?: readonly CacheKey[];
            records?: readonly string[];
        }

      Returns Promise<void>

    • The bust every organization write makes, whatever it changed: its record tag in every namespace projecting it, its customer's pages on both surfaces, and the writer's own folded get keys.

      Parameters

      • __namedParameters: { customerId: string; id: string; keys: readonly CacheKey[] }

      Returns Promise<void>

    • Tags for a page: the scope it searched, each customer whose name its rows copy, and the fields of records it may not hold that chose its rows.

      Parameters

      • __namedParameters: {
            customerIds: readonly string[] | undefined;
            fields?: readonly string[];
            items: readonly OrgWithCustomer[];
        }

      Returns string[]

    • Tags for a page: the scope its query searched (each customer's membership tag, else the collection tag), so an empty page is bustable too, plus the records it projects and the fields that chose or ordered its rows.

      Parameters

      • __namedParameters: {
            customerIds: readonly string[] | undefined;
            fields?: readonly string[];
            records?: readonly string[];
        }

      Returns string[]

    • The exact key OrganizationAdminQueryService.get reads through, for its includeDeleted: false callers.

      The includeDeleted: true variant hashes differently and is reached only by the collection tag, which every Valkey-backed environment has. That gap is deliberate and pre-existing: it only matters in memory mode, where no admin get runs with includeDeleted: true.

      Parameters

      • __namedParameters: { id: string }

      Returns Record<string, unknown>

    • The exact key OrganizationQueryService.get reads through.

      get folds onto search, so these args must stay identical to the ones it passes ({ customerId, ids: [id], pageSize: 1 }) plus the defaults search bakes into its own key — includeDeleted: false and page: 1. Every other filter is undefined there, and serviceCacheKey canonicalizes with JCS, which drops undefined properties. organizationCache.test.ts pins the equivalence.

      Parameters

      • __namedParameters: { customerId: string; id: string }

      Returns Record<string, unknown>