@spacelr/sdk
v0.10.11
Published
TypeScript SDK for the Spacelr API - auth and storage
Maintainers
Readme
@spacelr/sdk
Note: Spacelr is currently under active development. APIs may change between releases.
TypeScript SDK for the Spacelr API — authentication, storage, database and realtime notifications.
Installation
npm install @spacelr/sdkQuick Start
import { createClient } from '@spacelr/sdk';
const spacelr = createClient({
apiUrl: 'https://api.your-domain.com',
projectId: 'your-project-id',
clientId: 'your-client-id',
});
// Login
const { user } = await spacelr.auth.login({
username: '[email protected]',
password: 'password',
});
// Upload a file
await spacelr.storage.uploadFile({ file, path: '/images/photo.png' });
// Subscribe to database changes
spacelr.db.subscribe('my-collection', {
onChange: (event) => console.log('changed:', event),
});Modules
| Module | Description |
| --- | --- |
| auth | Login, registration, OAuth2 PKCE flow, token management, 2FA |
| storage | File upload (including multipart), download, sharing, quota |
| db | Database operations with realtime subscriptions via WebSocket; db.timeline for cold-tier history reads |
| notifications | Web Push notification subscription management |
Cold-tier history (db.timeline)
Collections can enable cold-tier archival: aged documents are moved to
object storage and purged from the live (hot) MongoDB tier. The normal query
methods (find, findById, count, search, paginate) operate on the hot
tier only — archived documents will not appear in their results.
To read archived history, use the timeline API, which transparently merges hot and cold data for a partition (e.g. a chat room) and paginates with an opaque cursor:
const page = await spacelr.db.timeline.query({
collection: 'chat_messages',
partitionValue: 'room-123', // the cold-tier partition (e.g. room id)
where: { authorId: { $eq: 'user-1' } }, // optional, allow-listed operators only
orderBy: { field: 'createdAt', direction: 'desc' },
limit: 50, // 1–200, default 50
});
page.items; // merged hot + cold documents
page.nextCursor; // pass back as `cursor` for the next page (null = end)
page.sourceStats; // { hot, cold, segmentsScanned? } — where the rows came fromNotes:
- Timeline paginates by partition + timestamp, not arbitrary Mongo queries;
whereaccepts only the allow-listed operators ($eq,$ne,$lt,$lte,$gt,$gte,$in,$nin,$and). - Enabling/configuring cold-tier on a collection is an admin operation and is not part of this client SDK.
Passkey authentication (WebAuthn)
The SDK never touches navigator.credentials and does not depend on
@simplewebauthn in any way (no runtime, dev, or peer dependency). It only
performs the HTTP begin/verify round trips against the gateway. The
browser WebAuthn ceremony itself — calling navigator.credentials.get() /
navigator.credentials.create() — is the caller's responsibility, typically
via the optional @simplewebauthn/browser package:
npm install @simplewebauthn/browser # optional, only needed for the ceremonyimport { startAuthentication, startRegistration } from '@simplewebauthn/browser';
// --- Login ---
const opts = await spacelr.auth.beginPasskeyLogin(email);
// The SDK vendors its own self-contained WebAuthn JSON types (see
// libs/sdk/src/types/auth.ts) so it never depends on `@simplewebauthn`.
// Because of that, an `as` cast is ALWAYS required here — `@simplewebauthn/browser`
// v13's `optionsJSON` parameter uses its own DOM literal-union/named types, which
// the vendored types don't nominally match even though they're structurally identical.
const assertion = await startAuthentication({ optionsJSON: opts as never });
await spacelr.auth.verifyPasskeyLogin(assertion); // tokens stored, 'authenticated' emitted
// --- Register (while already signed in) ---
const regOpts = await spacelr.auth.beginPasskeyRegistration();
const attestation = await startRegistration({ optionsJSON: regOpts as never }); // cast required, see above
await spacelr.auth.verifyPasskeyRegistration(attestation, 'My Laptop');
// --- Manage registered credentials ---
const creds = await spacelr.auth.listPasskeys();
await spacelr.auth.renamePasskey(creds[0].credentialId, 'Renamed');
await spacelr.auth.deletePasskey(creds[0].credentialId);Notes:
beginPasskeyLogin/verifyPasskeyLogincomplete the passkey login flow; on success tokens are stored and the SDK emitsauthenticated, the same asauth.login().beginPasskeyRegistration/verifyPasskeyRegistrationregister a new passkey for the current session; they don't emit auth events (the caller is already signed in).listPasskeys,renamePasskey, anddeletePasskeymanage the current user's registered credentials.@simplewebauthn/browseris entirely optional and only relevant to browser consumers performing the ceremony — Node/server usage of the SDK never needs it.
Requirements
- Node.js >= 18
- TypeScript >= 5 (recommended)
License
MIT
