The TypeScript SDK is an ES module, published on npm asDocumentation Index
Fetch the complete documentation index at: https://docs.myme.so/llms.txt
Use this file to discover all available pages before exploring further.
@withmarfa/sdk. Works in Node.js, Bun, Deno, and modern browsers (with a compatible fetch). Depends on @withmarfa/shared for wire types and validation primitives.
Electron consumers: see Using the SDK in Electron for the externalizeDeps config the main-process bundler needs.
Install
Connect
Configuration
callback strategy pairs with a per-call resolver — see Conflict handling.
Namespaces
The client exposes one namespace per resource:client.items— create, read, list, update, delete, transitionclient.edges— create, update properties, delete, list, edge typesclient.metadata— tags, tier, state mutationsclient.blobs— upload, download, presigned URL, existsclient.types— list, register, describe, delete (custom types)client.keys— create, list, get, update, revoke (admin scope)client.webhooks— create, list, get, update, delete, deliveriesclient.tenants— current, configclient.connections— list, get, configure, pause, resume, uninstallclient.admin— operator surface (system-tenant admin)client.auth— sign-in flows plusaccount.{requestDelete, confirmDelete, cancel}post-sign-in lifecycleclient.profile— current user profile
Items
Natural-key upsert
Whencreate() is called with both source_id and a credential-stamped source that already resolve an existing non-trashed row in the tenant, the server short-circuits to update — properties shallow-merge, tags replace if provided, edges replace per-type if provided. The HTTP status flips from 201 to 200; the SDK returns the updated item either way. See Items — natural-key upsert for the wider semantics.
Update signature
items.update(id, properties, options?). The second argument is the property bag itself — { body: "..." } — not a wrapping object with a properties key. The optional third argument carries flow control: version for optimistic concurrency, conflict to override the strategy per call, resolve for the callback resolver.
conflictStrategy; the lazy type fetch on keep_both_copies paths still happens automatically. Pass type in options only if you also want to skip that specific lazy fetch.
Edges
Atomic item + edges
Bulk writes
client.items.bulk and client.edges.bulk are admin-only. The server stamps source from the credential, so only platform admins can bulk-write across sources — they’re the ingest / migration primitive, not the every-day integration path. Third-party integrations writing many items should call client.items.create with source_id per item; (source, source_id) is the natural upsert key, so re-posts merge in place. See Natural-key upsert above.
client.items.bulkAction is a filter-driven mass-mutation primitive — purge is admin-only; the other five verbs require write access on every matched type.
bulkAction POSTs, gets a 202 + job envelope from the server, and polls until the worker reaches a terminal status — then resolves with the same BulkActionResult shape callers got from the historical synchronous endpoint. Pass options to surface progress to a UI:
client.items.bulkActionAsync(input) returns the queued envelope without polling; bulkActionStatus(jobId) and bulkActionCancel(jobId) are thin wrappers over the GET / DELETE endpoints.
Semantics and outcome shape are documented on Bulk operations; the SDK methods are thin wrappers.
Metadata
tier field sits on the item itself, not in metadata — set it on create with tier: "library" or tier: "feed", or flip it post-creation via items.update(id, {}, { tier: "library" }). Tier-only updates don’t conflict — tier is metadata-axis, last-writer-wins. system.* items have no tier; the field is optional in the wire shape.
Blobs
Search
Conflict handling
The TypeScript SDK exposes the three modes asconflictStrategy on the client config and UpdateOptions.conflict per call. See Conflicts for the resolution model, keep-both semantics, and per-core-type defaults; Errors — version_conflict for the 409 payload.
callback strategy invokes a resolver with the three-way context plus the type’s resolved mergePolicy; auto (default) and manual need no resolver. A client-level conflictStrategy sets the default; UpdateOptions overrides it per call.
When auto runs the SDK emits a conflictAutoMerged event:
conflictedCopyId being present — the user’s in-flight edit was preserved as a sibling rather than discarded.
Errors
Typed error classes you can instanceof-check:MarfaError, which carries code, message, status, and optionally details. Branch on err.code (stable string) rather than message wording.
OAuth helpers (@withmarfa/sdk/auth)
A separately-exported subpath for apps that authenticate users through Marfa rather than holding an API key. Mirrors the OAuth 2.1 + Device Authorization Grant flows documented under Authentication.
MarfaAuth
The high-level helper for the Authorization Code + PKCE flow. Generates the PKCE verifier, builds the authorize URL, exchanges the redirected code for tokens, and refreshes on demand. Pair it with a TokenStorage to persist the resulting token pair.
startDeviceFlow
For headless and CLI contexts. Implements RFC 8628 — initiate, display the verification_uri + user_code, poll until the user approves.
Token storages
MemoryTokenStorage (per-process; default), LocalStorageTokenStorage (browser), and SecureStorageTokenStorage (Keychain on macOS, Credential Locker on Windows, libsecret on Linux — when running under Node) are bundled. Custom backends implement the TokenStorage interface — read, write, clear.
OAuthError
Thrown by every helper. Carries the OAuth error code (invalid_grant, slow_down, expired_token, access_denied, etc.) and the optional error_description. Apps branch on err.code to decide between user-facing messaging and re-flow logic.
PKCE primitives
generatePkcePair() returns { verifier, challenge, method: "S256" } for callers that need to drive the flow themselves rather than through MarfaAuth. The verifier is a 128-byte URL-safe random string.
Webhook signature verification
The top-levelverifyWebhookSignature helper validates an incoming inbound-webhook receipt against the subscription’s secret. Wraps the same canonical X-Marfa-Signature header check the server runs — handy for any consumer that wants to verify a forwarded payload (gateway, CI runner) without pulling in the full server.
{ verified: true; deliveryId?: string } shape on success and { verified: false; reason: string } on failure.
Realtime
The TypeScript SDK doesn’t wrap SSE — consumers connect toGET /events directly with the browser’s EventSource API (in a browser) or with fetch + a streaming body reader (in Node.js / Bun / Deno). The realtime page documents the event catalog, Last-Event-ID reconnection, filtering parameters, and the catch-up strategy.
Versioning
The TypeScript SDK follows semver. Major-version bumps mean breaking wire or API changes. Minor bumps add capabilities. Patch bumps are bug fixes. The SDK’s major version tracks the server it was built against.Browser use
The SDK works in browsers that supportfetch, TextDecoder, and ReadableStream. No polyfills needed for evergreen browsers. For older targets, bring your own polyfill.
When making requests from a browser, ensure the Marfa server’s CORS_ORIGINS includes your origin (see Configuration).