Connect SDK
Connect a browser application
Declare a workout contract, authorize one collection, complete the browser callback, and make a revision-safe update.The production service currently accepts private-beta accounts. The public SDK packages are also awaiting their first npm release. Start with the local sandbox guide if you do not have beta access.
Before you begin
This guide expects:
- a private-beta account or the repository's local Connect stack;
- a browser application running at
http://localhost:5173; - Node 24 LTS and the repository's pinned pnpm version;
- a Connect SDK source build or beta artifact.
The example manifest carries a complete transactional contract/type pack. Connect can install it during approval when the chosen collection does not yet provide workout.record 1.0.0.
1. Add a bundled application manifest
Save this file at public/.well-known/mdbase-app.json. The local URLs are valid for development and require the validator's --allow-local option.
{
"manifest_version": 1,
"id": "dev.example.workouts",
"name": "Example Workouts",
"homepage": "http://localhost:5173",
"redirect_uris": [
"http://localhost:5173/auth/mdbase/callback"
],
"requirements": {
"contracts": [
{ "id": "workout.record", "version": "1.0.0" }
]
},
"provisions": {
"type_packs": [
{
"provides": [
{ "id": "workout.record", "version": "1.0.0" }
],
"manifest": {
"kind": "mdbase.type-pack",
"id": "example.workouts",
"version": "1.0.0",
"resources": [
{
"kind": "contract",
"source": "contracts/workout.record.md",
"target": "_contracts/workout.record.md",
"digest": "sha256:e0c2f77dd7158ca7e6b52b13da8c306f0a7e1b97582a1024f00ec0cf7fe5f259"
},
{
"kind": "type",
"source": "types/workout.md",
"target": "_types/workout.md",
"digest": "sha256:ff35309cd4598182d2021f698ee85cad4d320d965cd5f7c1bd608ee2eb16505b"
}
]
},
"resources": [
{
"source": "contracts/workout.record.md",
"document": "---\nkind: mdbase.contract\ncontract_type: record\nid: workout.record\nversion: 1.0.0\nrecord_schema:\n dialect: json-schema-2020-12\n value:\n $schema: https://json-schema.org/draft/2020-12/schema\n type: object\n additionalProperties: false\n properties:\n title: { type: string }\n completed: { type: boolean, default: false }\n required: [title]\n---\n"
},
{
"source": "types/workout.md",
"document": "---\nkind: mdbase.type\nname: workout\nversion: 1\nschema:\n dialect: json-schema-2020-12\n value:\n type: object\n additionalProperties: true\n properties:\n title: { type: string }\n completed: { type: boolean }\n required: [title]\nimplements:\n - contract: workout.record\n version: 1.0.0\n fields:\n title: title\n completed: completed\n---\n"
}
]
}
]
}
}The contract requirement limits compatible collections. The type pack makes a collection safely provisionable during approval and does not give the application general type-management access.
2. Add the SDK and validator
After the public npm release, installation uses:
pnpm add @mdbase/connect
pnpm add -D @mdbase/connect-devDuring the private beta, create immutable consumer archives from a clean Connect checkout. The command prints the exact artifact filenames and source revision. Add the printed protocol and client archives to the application with pnpm add <archive>.
# Run in the mdbase-connect checkout.
mkdir -p ../workouts-app/vendor
pnpm package:consumer -- \
--destination ../workouts-app/vendor \
--packages connect,protocolThe validator is currently run from the Connect workspace or supplied as a beta artifact:
mdbase-connect-dev validate-manifest \
public/.well-known/mdbase-app.json \
--allow-local3. Create one stable Connect client
import {
MdbaseBrowserLocation,
MdbaseConnect,
type JsonObject
} from "@mdbase/connect";
export interface Workout extends JsonObject {
title: string;
completed?: boolean;
}
export const mdbase = new MdbaseConnect<Workout>({
serverUrl: "https://connect.mdbase.dev",
manifest: new URL(
"/.well-known/mdbase-app.json",
location.origin
).href,
redirectUri: new URL(
"/auth/mdbase/callback",
location.origin
).href
});
export const collectionLocation =
new MdbaseBrowserLocation(mdbase);The manager owns saved authorizations. The location helper owns the bookmarkable collection ID, browser history changes, and authorization return cleanup.
4. Start authorization from a user action
import { collectionLocation, mdbase } from "./connect";
export async function connectCollection() {
await mdbase.authorize({
operations: ["describe", "read", "query", "create", "update"],
collectionId:
collectionLocation.selectedCollectionId() ?? undefined,
returnTo: collectionLocation.authorizationReturnTo()
});
// authorize() navigates to Connect and does not return.
}Connect presents ready and provisionable collections, then asks the user to approve the listed operations. Collection records remain private until approval succeeds.
5. Complete the exact callback route
import { collectionLocation } from "./connect";
export async function completeMdbaseCallback() {
const connection =
await collectionLocation.completeAuthorization();
console.log(
"Connected collection:",
connection.collectionId
);
return connection;
}Call this once at the manifest's callback path. PKCE is mandatory. A successful callback stores the grant-bound authorization and returns a collection-bound connection.
import {
completeMdbaseCallback
} from "./mdbase-callback";
import { connectCollection } from "./connect-button";
document
.querySelector("[data-connect-mdbase]")
?.addEventListener("click", () => connectCollection());
if (location.pathname === "/auth/mdbase/callback") {
await completeMdbaseCallback();
}6. Query and update with a revision
import { unwrapOperation } from "@mdbase/connect";
import { collectionLocation } from "./connect";
const collection = collectionLocation.activeConnection();
if (!collection) throw new Error("Choose a collection.");
const page = unwrapOperation(await collection.query({
contract: {
id: "workout.record",
version: "1.0.0"
},
limit: 50
}));
const first = page.results
.filter((row) => row.completed !== true)
.sort((left, right) =>
left.title.localeCompare(right.title)
)[0];
if (first) {
unwrapOperation(await collection.update({
path: first.path,
patch: { completed: true },
contract: {
id: "workout.record",
version: "1.0.0"
},
if_revision: first.revision
}));
}Query results carry an opaque revision. Passing it as if_revision prevents one application from silently overwriting a newer change.
Contract-scoped queries expose normalized mapped fields only. They union every approved implementation and deliberately leave filtering and sorting those normalized values to the application.
What success looks like
- The Connect approval screen names Example Workouts.
- The collection chooser marks a matching collection as ready or provisionable.
- The approval screen lists the five requested operations.
- The browser returns to
/auth/mdbase/callback. - The console prints the stable ID of the approved collection.
- The first incomplete workout receives
completed: true.
MdbaseBrowserLocation writes ?collection=<id> and follows browser back and forward navigation. Collection IDs are opaque locators and can appear in browser history and logs. They are not credentials.