Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ MDBASE_CONNECT_REGISTRATION=closed

# Password authentication can coexist with external providers or operate on its
# own. This stable HMAC secret protects privacy-safe shared rate-limit keys.
# Configure both legal document URLs before enabling invited signup.
# Configure both legal document URLs before enabling invited or public signup.
# MDBASE_CONNECT_AUTH_RATE_LIMIT_SECRET=replace-with-at-least-32-random-characters
# Optional public beta-access form origin. Requests are accepted only from this
# exact browser origin and use the shared database-backed rate limiter.
# Optional legacy beta-access origin. The retired request endpoint returns 410
# to this exact browser origin and never stores a new request.
# MDBASE_CONNECT_BETA_ACCESS_ORIGIN=https://mdbase.dev
# MDBASE_CONNECT_TERMS_URL=https://example.com/terms/
# MDBASE_CONNECT_PRIVACY_URL=https://example.com/privacy/
Expand All @@ -50,6 +50,9 @@ MDBASE_CONNECT_TRUST_PROXY=0

# Local agent only: fixed browser loopback port. The SDK default is 28485.
# MDBASE_CONNECT_LOOPBACK_PORT=28485
# Non-secret deployment identity published by /health. Managed deployments set
# production, staging, or lab; the local compose environment sets local.
# MDBASE_CONNECT_ENVIRONMENT=local

# Optional Web Push. Generate one VAPID keypair and configure all three values
# together. The subject must be a mailto: or HTTPS URI.
Expand Down
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# mdbase connect

> [!IMPORTANT]
> **Invite-only beta:** The managed mdbase connect cloud service is currently
> available by invitation only. Access to `connect.mdbase.dev`, including
> hosted collections and the managed connection service, requires beta access.
> If you have been invited, follow the access instructions you received.
> **Beta:** The managed mdbase connect cloud service is transitioning from
> invite-only access to public signup. Existing invitation links remain valid.

mdbase connect lets you use the applications you choose with the Markdown data
you control. An application gets access to one collection only after you
Expand Down Expand Up @@ -69,12 +67,10 @@ can be revoked with `mdbase connect hosted disconnect <collection-id>`.

## Getting started during the beta

There is no public signup for the managed cloud service while it is in
invite-only beta.
To use the managed cloud service, create an account from the Connect sign-in
page or follow an existing invitation link. Then:

If you have beta access:

1. Follow your invitation to create or access your mdbase connect account.
1. Create or sign in to your mdbase connect account.
2. Install the desktop build provided for your platform.
3. Open the desktop app and pair your computer.
4. Add an existing mdbase collection or create a hosted collection.
Expand Down
3 changes: 2 additions & 1 deletion apps/editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ for CI, sign in with Wrangler once, then run:

```sh
pnpm dlx wrangler@4.114.0 login
pnpm deploy:dev
pnpm deploy:dev # lab (experimental default)
MDBASE_ENV=staging pnpm deploy:dev # staging release rehearsal
```

The command builds workspace packages, generates the editor for the staging
Expand Down
24 changes: 24 additions & 0 deletions apps/editor/src/EnvironmentBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { JSX } from "react";

export type VisibleEnvironment = "lab" | "staging" | "local";

const visibleEnvironments = new Set<VisibleEnvironment>(["lab", "staging", "local"]);

export function visibleEnvironment(value: string | undefined): VisibleEnvironment | null {
const normalized = value?.trim().toLowerCase() as VisibleEnvironment | undefined;
return normalized && visibleEnvironments.has(normalized) ? normalized : null;
}

export function EnvironmentBadge(): JSX.Element | null {
const environment = visibleEnvironment(import.meta.env.VITE_MDBASE_ENV);
if (!environment) return null;
return (
<div
className={`environment-badge is-${environment}`}
role="status"
aria-label={`${environment} environment`}
>
{environment}
</div>
);
}
39 changes: 39 additions & 0 deletions apps/editor/src/environment-badge.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.environment-badge {
position: fixed;
z-index: 10000;
top: 5px;
right: 5px;
padding: 4px 7px 3px;
border: 1px solid currentColor;
background: #f4f7f7;
box-shadow: 2px 2px 0 rgb(20 34 35 / 14%);
color: #34585d;
font: 500 9px/1.2 "Azeret Mono", ui-monospace, monospace;
letter-spacing: 0.14em;
pointer-events: none;
text-transform: uppercase;
}

.environment-badge.is-lab {
background: #fff2c7;
color: #7b4d00;
}

.environment-badge.is-staging {
background: #ffebe8;
color: #8d3029;
}

.environment-badge.is-local {
background: #e5f5f8;
color: #176377;
}

@media (max-width: 640px) {
.environment-badge {
top: 3px;
right: 3px;
padding: 3px 5px 2px;
font-size: 8px;
}
}
4 changes: 3 additions & 1 deletion apps/editor/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { createRoot } from "react-dom/client";
import { AppErrorBoundary } from "./AppErrorBoundary";
import { DemoCollectionGateway } from "./demo-gateway";
import { ConnectCollectionGateway } from "./gateway";
import { EnvironmentBadge } from "./EnvironmentBadge";
import "@mdbase/connect-ui/motion.css";
import "./phosphor-icons.generated.css";
import "./styles.css";
import "./environment-badge.css";

const EditorApp = lazy(() => import("./App").then((module) => ({ default: module.App })));
const ConnectWorkspace = lazy(() => import("./ConnectApp").then((module) => ({ default: module.ConnectApp })));
Expand All @@ -25,5 +27,5 @@ const gateway = demoCount > 0
: new ConnectCollectionGateway();

createRoot(document.getElementById("root")!).render(
<StrictMode><AppErrorBoundary><Suspense fallback={<div className="route-loading" aria-live="polite">Opening mdbase…</div>}>{connectWorkspace ? <ConnectWorkspace /> : <EditorApp gateway={gateway} />}</Suspense></AppErrorBoundary></StrictMode>
<StrictMode><AppErrorBoundary><EnvironmentBadge /><Suspense fallback={<div className="route-loading" aria-live="polite">Opening mdbase…</div>}>{connectWorkspace ? <ConnectWorkspace /> : <EditorApp gateway={gateway} />}</Suspense></AppErrorBoundary></StrictMode>
);
9 changes: 7 additions & 2 deletions apps/portal/portal-model.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ test("captures one-time auth fragments before rendering and removes them from hi
const replacements = [];
const secrets = capturePortalBootstrapSecrets(
{
hash: "#invitation=%20invite-secret%20&reset=reset-secret",
hash: "#invitation=%20invite-secret%20&verification=verify-secret&reset=reset-secret",
pathname: "/signup",
search: "?return_to=%2Fauthorize%2Frequest"
},
Expand All @@ -20,6 +20,7 @@ test("captures one-time auth fragments before rendering and removes them from hi

assert.deepEqual(secrets, {
invitationToken: "invite-secret",
verificationToken: "verify-secret",
resetToken: "reset-secret"
});
assert.deepEqual(replacements, [{
Expand All @@ -37,7 +38,11 @@ test("does not rewrite unrelated fragments", () => {
{ state: null, replaceState() { replaced = true; } }
);

assert.deepEqual(secrets, { invitationToken: "", resetToken: "" });
assert.deepEqual(secrets, {
invitationToken: "",
verificationToken: "",
resetToken: ""
});
assert.equal(replaced, false);
});

Expand Down
Loading
Loading