@motherbase/contracts is a small TypeScript package with one source file: packages/contracts/src/index.ts. It owns route constants, path builders, payload interfaces, realtime protocol types, and lightweight runtime guards. It has no runtime dependency.
HTTP routes
HTTP_ROUTES is an as const map:
| Key | Value | Main consumers |
|---|---|---|
auth | /api/auth | Shared base constant |
authSignIn | /api/auth/sign-in/email | packages/client/src/auth.ts |
authSession | /api/auth/get-session | packages/client/src/auth.ts |
authSignOut | /api/auth/sign-out | packages/client/src/auth.ts |
authSignUp | /api/auth/sign-up/email | packages/client/src/auth.ts |
authRequestPasswordReset | /api/auth/email-otp/request-password-reset | packages/client/src/auth.ts |
authResetPassword | /api/auth/email-otp/reset-password | packages/client/src/auth.ts |
authSendOtp | /api/auth/email-otp/send-verification-otp | packages/client/src/auth.ts |
authSignInEmailOtp | /api/auth/sign-in/email-otp | packages/client/src/auth.ts |
authSignInSocial | /api/auth/sign-in/social | packages/client/src/auth.ts |
authUpdateUser | /api/auth/update-user | packages/client/src/auth.ts |
authChangePassword | /api/auth/change-password | packages/client/src/auth.ts |
authDeleteUser | /api/auth/delete-user | packages/client/src/auth.ts |
files | /api/files | packages/client/src/storage.ts and apps/server/controllers/file.controller.ts |
rest | /rest/v1 | REST path construction |
edge | /api/edge | Edge-function path construction |
realtimeBroadcast | /realtime/v1/api/broadcast | apps/server/controllers/realtime-broadcast.controller.ts |
The server also imports the route map in apps/server/auth/routes.ts, apps/server/controllers/edge-invoke.controller.ts, and apps/server/controllers/rest-api.controller.ts so route ownership does not drift from the client.
Path builders
contractPath derives encoded paths from the constants:
contractPath.edge(name)
contractPath.file(id)
contractPath.file(id, 'raw')
contractPath.file(id, 'url')
contractPath.rest(model)
contractPath.realtime(model, 'created')| Builder | Shape | Consumers |
|---|---|---|
edge(name) | /api/edge/:encodedName | packages/client/src/functions.ts |
file(id, action?) | /api/files/:encodedId with optional /raw or /url | packages/client/src/storage.ts |
rest(model) | /rest/v1/:encodedModel | packages/client/src/index.ts, packages/client/src/postgrest.ts, and packages/client/src/realtime.ts |
realtime(model, mutation) | lowercaseModel:mutation | packages/client/src/realtime.ts and apps/server/services/realtime/realtime-broadcast.service.ts |
RealtimeMutation is the union 'created' | 'updated' | 'deleted' used by contractPath.realtime.
HTTP and storage payload contracts
| Export | Shape | Consumers |
|---|---|---|
AuthUserContract | Required id and email plus arbitrary fields | Base type for AuthSessionContract; no external source import |
AuthSessionContract | token and user | Public package contract; no external source import in this revision |
FileContract | Required id plus arbitrary fields | Generic constraint for uploads |
StorageUploadContract<TFile> | { file: TFile, url: string } | apps/server/controllers/file.controller.ts and packages/client/src/types.ts |
StorageRemoveContract | { deleted: true } | apps/server/controllers/file.controller.ts, apps/server/services/storage/storage.service.ts, and packages/client/src/types.ts |
ApiEnvelopeContract<T> | status is 0 or 1, message, optional data | Public envelope contract; the client keeps its parallel ApiEnvelope in packages/client/src/types.ts |
StorageUploadContract defaults its generic to FileContract. The client specializes it with FileObject and re-exports the alias as StorageUploadResponse.
Runtime guards
isApiEnvelope(value) returns true only for a non-null object whose status is 0 or 1 and whose message is a string.
isStorageUpload(value) returns true only for an object with file.id and url strings.
The SDK/server contract integration test consumes both guards in apps/server/tests/sdk-server-contract.integration.test.ts. They are also available to external packages validating unknown JSON.
Legacy table realtime
REALTIME_SOCKET_EVENTS defines:
{
subscribe: 'realtime:subscribe',
unsubscribe: 'realtime:unsubscribe',
}normalizeRealtimeModel(model) trims, lowercases, and accepts only a PostgreSQL-style identifier beginning with a letter or underscore and containing at most 63 letters, digits, or underscores. Invalid names return null.
The client uses both exports in packages/client/src/realtime.ts. The server uses them in apps/server/services/socket.service.ts and validates models again in apps/server/services/realtime/realtime-postgres.service.ts.
Topic realtime protocol
REALTIME_TOPIC_EVENTS defines join: 'rt:join', leave: 'rt:leave', and message: 'rt:msg'.
| Export | Shape | Consumers |
|---|---|---|
RealtimeTopicMessageType | broadcast, presence, postgres_changes, or system | packages/client/src/realtime.ts |
RealtimePostgresChangeConfig | Event, optional schema, table, optional filter | packages/client/src/channel.ts and apps/server/services/realtime/realtime-postgres.service.ts |
RealtimeJoinConfig | Optional broadcast, presence, and Postgres-change configuration | packages/client/src/channel.ts, packages/client/src/realtime.ts, and apps/server/services/realtime/realtime-topic.service.ts |
RealtimeJoinAck | status is ok or error, optional subscription ids and error | Client realtime module and server topic service |
RealtimeTopicEnvelope | Topic, message type, event, and unknown payload | packages/client/src/channel.ts and packages/client/src/realtime.ts |
Server-side event consumers include apps/server/services/realtime/realtime-topic.service.ts, apps/server/services/realtime/realtime-presence.service.ts, apps/server/services/realtime/realtime-postgres.service.ts, and apps/server/services/socket.service.ts.
isValidRealtimeTopic(topic) accepts strings of 1–255 printable ASCII characters and rejects control characters and newlines. realtimeTopicRoom(topic) prefixes a validated topic with rt: for its Socket.IO room. Both are used by the server topic/socket services; the broadcast controller also validates topics in apps/server/controllers/realtime-broadcast.controller.ts.
RealtimeTopicEnvelope.payload is deliberately unknown. The client narrows it according to type before routing it to broadcast, presence, or Postgres-change callbacks.
Related
- Realtime — channels, broadcast and presence built on these contracts.
- REST engine — the server side of the shared route paths.