Track HiveGrid Cloud planning reference

This commit is contained in:
david committed 2026-06-26 20:48:01 +02:00
1 parent b3d5ea6764
commit e341c5938a
5784 files changed
+1104929 -3

No files matched your search

@@ -0,0 +1,80 @@
// @vitest-environment node
import { describe, expect, it, vi } from "vitest";
// Subscription-product mutations (the path an in-app plan upgrade runs)
// must purge the cache cross-replica. Assert each wrapper routes through the
// publishing helper `clearTenantSubscriptionCache` rather than a bare,
// local-only `clearCacheKey`.
//
// The mock fn is parked on `globalThis` so the hoisted `vi.mock` factory can
// reach it without a top-level reference (vitest 0.29 has no `vi.hoisted`).
type CacheMocks = { clearTenantSubscriptionCache: ReturnType<typeof vi.fn> };
function getMocks(): CacheMocks {
const store = globalThis as typeof globalThis & { __tenantSubProductDbCacheMocks__?: CacheMocks };
store.__tenantSubProductDbCacheMocks__ ??= { clearTenantSubscriptionCache: vi.fn() };
return store.__tenantSubProductDbCacheMocks__;
}
vi.mock("@toolctrl/db/subscriptions.server", () => ({
addTenantSubscriptionProduct: vi.fn(),
cancelTenantSubscriptionProduct: vi.fn(),
updateTenantSubscriptionProduct: vi.fn(),
}));
vi.mock("~/utils/services/.server/subscriptionService", () => ({
clearTenantSubscriptionCache: getMocks().clearTenantSubscriptionCache,
}));
import {
addTenantSubscriptionProduct,
cancelTenantSubscriptionProduct,
updateTenantSubscriptionProduct,
} from "./tenantSubscriptionProducts.db.server";
import {
addTenantSubscriptionProduct as persistAdd,
cancelTenantSubscriptionProduct as persistCancel,
updateTenantSubscriptionProduct as persistUpdate,
} from "@toolctrl/db/subscriptions.server";
const mocks = getMocks();
describe("tenantSubscriptionProducts db wrapper — cross-replica cache invalidation", () => {
it("addTenantSubscriptionProduct publishes a cross-replica invalidation for the tenant", async () => {
mocks.clearTenantSubscriptionCache.mockClear();
vi.mocked(persistAdd).mockResolvedValueOnce({
tenantSubscription: { tenantId: "tenant-a" },
} as Awaited<ReturnType<typeof persistAdd>>);
await addTenantSubscriptionProduct({} as Parameters<typeof addTenantSubscriptionProduct>[0]);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledTimes(1);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledWith("tenant-a");
});
it("updateTenantSubscriptionProduct publishes a cross-replica invalidation for the tenant", async () => {
mocks.clearTenantSubscriptionCache.mockClear();
vi.mocked(persistUpdate).mockResolvedValueOnce({
tenantSubscription: { tenantId: "tenant-b" },
} as Awaited<ReturnType<typeof persistUpdate>>);
await updateTenantSubscriptionProduct("p1", "tenant-b", {} as Parameters<typeof updateTenantSubscriptionProduct>[2]);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledTimes(1);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledWith("tenant-b");
});
it("cancelTenantSubscriptionProduct publishes cross-replica before and after the persist", async () => {
mocks.clearTenantSubscriptionCache.mockClear();
vi.mocked(persistCancel).mockResolvedValueOnce({
tenantId: "tenant-c",
} as Awaited<ReturnType<typeof persistCancel>>);
await cancelTenantSubscriptionProduct("p1", "tenant-c", {} as Parameters<typeof cancelTenantSubscriptionProduct>[2]);
// Pre-invalidate on the passed tenantId + re-invalidate on the persisted
// record's tenantId — both publish cross-replica.
expect(mocks.clearTenantSubscriptionCache).toHaveBeenCalledTimes(2);
expect(mocks.clearTenantSubscriptionCache).toHaveBeenNthCalledWith(1, "tenant-c");
expect(mocks.clearTenantSubscriptionCache).toHaveBeenNthCalledWith(2, "tenant-c");
});
});
@@ -0,0 +1,44 @@
import {
addTenantSubscriptionProduct as persistTenantSubscriptionProduct,
cancelTenantSubscriptionProduct as persistTenantSubscriptionProductCancellation,
updateTenantSubscriptionProduct as persistTenantSubscriptionProductUpdate,
type TenantSubscriptionProductCreateInput,
type TenantSubscriptionProductUpdateInput,
type TenantSubscriptionProductCancelInput,
} from "@toolctrl/db/subscriptions.server";
import { clearTenantSubscriptionCache } from "~/utils/services/.server/subscriptionService";
export {
adminGetTenantSubscriptionProductById,
getAllTenantSubscriptionProducts,
getTenantSubscriptionProduct,
getTenantSubscriptionProductById,
getTenantSubscriptionProductByStripeSubscriptionId,
type TenantSubscriptionProductPage,
type TenantSubscriptionProductWithDetails,
type TenantSubscriptionProductWithTenant,
} from "@toolctrl/db/subscriptions.server";
export async function addTenantSubscriptionProduct(data: TenantSubscriptionProductCreateInput) {
const item = await persistTenantSubscriptionProduct(data);
// Cross-replica purge: clearTenantSubscriptionCache publishes on the
// subscription pub/sub channel so peer web replicas drop their L1 too.
clearTenantSubscriptionCache(item.tenantSubscription.tenantId);
return item;
}
export async function updateTenantSubscriptionProduct(id: string, tenantId: string, data: TenantSubscriptionProductUpdateInput) {
const item = await persistTenantSubscriptionProductUpdate({ id, tenantId }, data);
clearTenantSubscriptionCache(item.tenantSubscription.tenantId);
return item;
}
export async function cancelTenantSubscriptionProduct(id: string, tenantId: string, data: TenantSubscriptionProductCancelInput) {
// Pre-invalidate the affected tenant only — no need to wipe every tenant's
// subscription cache for a single tenant cancellation.
clearTenantSubscriptionCache(tenantId);
const item = await persistTenantSubscriptionProductCancellation({ id, tenantId }, data);
// Re-invalidate against the persisted record's tenantId in case it differs;
// publishes cross-replica so no peer keeps a stale entry.
clearTenantSubscriptionCache(item.tenantId);
}