@superbright/indexeddb-orm
v1.0.71
Published
Vite + TypeScript IndexedDB ORM.
Downloads
710
Readme
InResi ORM
Shared state and analytics layer for InResi apps. Built on Dexie (IndexedDB), Zustand, and Zod.
Docs: https://superbright.github.io/inResi-indexedDB-ORM/
Install
pnpm install @superbright/indexeddb-orm zustandUsage
Provider setup
import { AnalyticsProvider } from "@superbright/indexeddb-orm";
import { useVisitorSession } from "./hooks/useVisitorSession";
function Providers({ children }: { children: React.ReactNode }) {
const visitor_uuid = useVisitorSession(slug);
return (
<AnalyticsProvider
visitor_uuid={visitor_uuid}
mixpanelToken={import.meta.env.VITE_MIXPANEL_TOKEN}
posthogKey={import.meta.env.VITE_POSTHOG_KEY}
posthogHost={import.meta.env.VITE_POSTHOG_HOST}
envMode={import.meta.env.MODE ?? "production"}
>
{children}
</AnalyticsProvider>
);
}Store + analytics in components
import { useInResiStore, useTrackingEvents } from "@superbright/indexeddb-orm";
function MyComponent() {
const store = useInResiStore();
const { trackClickUnit, trackFilterApplied } = useTrackingEvents();
store.handleTempFilterChange("qty_bedrooms", [1, 2]);
store.submitFilterUpdate();
}Visitor UUID
const uuid = await store.getVisitorUUID();
await store.setVisitorUUID("550e8400-...");useVisitorSession(slug) handles creation and persistence — prefer it in React.
Dimension helpers
import { mmToInches, formatDimensions, dimensionToMmNumber } from "@superbright/indexeddb-orm";
formatDimensions({ width: 800, depth: 600, height: 750 });
// → "31.5"W x 23.6"D x 29.5"H"Analytics validation
Events are validated via Zod before dispatch. Invalid payloads are silently dropped in production and logged as console.warn in dev (isDev flag on AnalyticsProvider). If events aren't firing, check required fields on the schema for that event type.
Key transform behaviour
Always pass snake_case to tracking helpers. Internally, payloads are normalised to camelCase for Zod validation, then converted to snake_case before dispatch — so both snake_case and camelCase inputs are accepted, but snake_case is the convention.
Deprecated:
skipKeyTransformhas been removed. It was a no-op becauseconvertKeysToSnakeCaseis idempotent for snake_case inputs.
Schema tooling
API types and Zod schemas are generated from the live OpenAPI spec. Scalar is used to validate and mock the spec locally.
pnpm generate:api-schema:local # generate against local dev server (http://localhost:3000)
pnpm generate:api-schema:dev # generate against https://api.dev.inresi.link
pnpm generate:api-schema:prod # generate against https://api.inresiapp.com
pnpm validate:api # validate openapi.json only (Scalar)
pnpm mock:api # run a mock API server on :4010 (Scalar)prepublishOnly runs generate:api-schema:prod automatically.
Each generate:api-schema:* script calls scripts/generate-api-schema.mjs --url <url>, which:
- Validates the spec at the given URL via Scalar
- Generates
src/api/api.generated.ts— TypeScript interfaces for all paths and operations (openapi-typescript) - Runs
scripts/gen-schemas.mjs, which emits:src/api/schemas.generated.ts— Zod schemas inferred fromopenapi.jsoncomponent schemas (circular refs usez.lazy())src/api/embed-schemas.generated.ts— strict embed API response schemas fromsrc/scripts/embed-schema-overrides.json(see below)src/api/cms-schemas.generated.ts— CMS admin API response schemas fromsrc/scripts/cms-schema-overrides.json(permanent)
Never edit *.generated.ts files by hand — they will be overwritten on the next generation run.
embed-schema-overrides.json
src/scripts/embed-schema-overrides.json is a hand-maintained JSON Schema-like file that provides strict, fully-typed Zod schemas for the embed API responses. It exists because the live OpenAPI spec is incomplete in several ways:
Mediais under-specified — the spec has all fields optional; the real response has 20+ fields with required markers, and includessigned2180Url,signed1080Url,signed720Urlthat are absent from the spec entirely.- Embed-specific schemas are missing —
PropertyResponseData,BootstrapData,UnitsByIdsResponse,FiltersResponseData, and others do not exist in the spec at all. - Embed endpoint response types are wrong — e.g.
/embed/{slug}/filtersdeclaresUnit[]but actually returns a full filters + questionnaire payload.
gen-schemas.mjs reads the overrides file and compiles it into embed-schemas.generated.ts using a small code-generator that supports a subset of JSON Schema plus two escape hatches:
"x-zod": "<expr>"— emits a raw Zod expression verbatim. Use this for types that can't be expressed in JSON Schema (e.g.z.record(z.unknown()),z.union([...]))."x-coerce": true— on astring/date-timefield, emitsz.coerce.date()instead ofz.string().
Fields listed in "required" are emitted without .optional(); all others get .optional(). $ref values resolve to <Name>Schema within the same file. Nullable fields use "nullable": true alongside their type.
To remove the overrides once the API spec is fixed, the spec needs:
- Full
Mediashape with all required fields and thesigned*Urlvariants PropertyResponseData,BootstrapData,UnitsByIdsResponse,FiltersResponseData, and the remaining embed-specific schemas added as components- Correct response types on the embed endpoints that reference those components
Once those are in place, embed-schemas.generated.ts can be generated directly from schemas.generated.ts and the overrides file and its generator path can be removed.
Development
pnpm i
pnpm dev # playground at http://localhost:5173
pnpm build # production build
pnpm testLicense
UNLICENSED — proprietary, internal use only.
