Skip to content
Merged
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
6 changes: 3 additions & 3 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
},
"dependencies": {
"@fontsource-variable/source-serif-4": "^5.3.1",
"@mdbase-dev/sdk": "0.1.0-beta.187",
"@mdbase-dev/sdk-lab": "file:../../packages/connect/vendor/sdk-493d29ca-lab-beta157.tgz",
"@mdbase-dev/sdk-staging": "file:../../packages/connect/vendor/sdk-493d29ca-staging-beta157.tgz",
"@mdbase-dev/sdk": "0.1.0-beta.188",
"@mdbase-dev/sdk-lab": "file:../../packages/connect/vendor/sdk-e8ffb806-lab-beta188.tgz",
"@mdbase-dev/sdk-staging": "file:../../packages/connect/vendor/sdk-e8ffb806-staging-beta188.tgz",
"@lingui/core": "6.10.1",
"@lingui/react": "6.10.1",
"@mdbase-dev/i18n": "0.1.0-beta.149",
Expand Down
17 changes: 7 additions & 10 deletions apps/extension/src/connection-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { t } from "@lingui/core/macro";
import { describeError, type MdbaseApplicationSnapshot } from "@mdbase-reader/connect/native";
import { describeError, type MdbaseSnapshot } from "@mdbase-reader/connect/native";

/**
* What the extension's pages show for the SDK's application snapshot. The SDK owns
Expand Down Expand Up @@ -101,10 +101,7 @@ function recoveryActionLabel(action: RecoveryAction): string | null {
}

/** The SDK's description of a settled problem, as one extension control. */
function sdkProblem(
snapshot: MdbaseApplicationSnapshot,
readiness: boolean,
): ConnectionProblemView | null {
function sdkProblem(snapshot: MdbaseSnapshot, readiness: boolean): ConnectionProblemView | null {
const described = describeError(snapshot);
if (!described) {
return null;
Expand Down Expand Up @@ -134,7 +131,7 @@ function sdkProblem(
};
}

function identityLabel(signIn: MdbaseApplicationSnapshot["signIn"]): string | null {
function identityLabel(signIn: MdbaseSnapshot["signIn"]): string | null {
if (signIn?.state !== "paired") {
return null;
}
Expand All @@ -151,7 +148,7 @@ type Screen = Pick<ConnectionView, "status" | "problem">;
const plain = (status: ConnectionStatus): Screen => ({ status, problem: null });

/** Screens that win over everything else: closed, waiting in the mdbase tab, a problem. */
function interruption(snapshot: MdbaseApplicationSnapshot): Screen | null {
function interruption(snapshot: MdbaseSnapshot): Screen | null {
const { status, readiness, selection } = snapshot;
if (status === "closed") {
return plain("closed");
Expand All @@ -172,7 +169,7 @@ function interruption(snapshot: MdbaseApplicationSnapshot): Screen | null {
}

/** The step the reader (or the SDK) has to take next. */
function nextStep(snapshot: MdbaseApplicationSnapshot): ConnectionStatus | null {
function nextStep(snapshot: MdbaseSnapshot): ConnectionStatus | null {
const { status, readiness, selection } = snapshot;
if (selection.state === "approval_required") {
return "approval";
Expand All @@ -189,7 +186,7 @@ function nextStep(snapshot: MdbaseApplicationSnapshot): ConnectionStatus | null
return status === "unselected" || selection.state === "invalid" ? "choosing" : null;
}

function screen(snapshot: MdbaseApplicationSnapshot, usable: boolean): Screen {
function screen(snapshot: MdbaseSnapshot, usable: boolean): Screen {
const interrupted = interruption(snapshot);
if (interrupted) {
return interrupted;
Expand All @@ -212,7 +209,7 @@ function screen(snapshot: MdbaseApplicationSnapshot, usable: boolean): Screen {
* mdbase opening; the SDK's own status is not changed.
*/
export function connectionView(
snapshot: MdbaseApplicationSnapshot,
snapshot: MdbaseSnapshot,
usable: boolean,
hostAvailable = true,
): ConnectionView {
Expand Down
7 changes: 2 additions & 5 deletions apps/extension/src/offscreen.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { MdbaseConnect } from "@mdbase-reader/connect/native";
import { createMdbase } from "@mdbase-reader/connect/native";

import { credentiallessFetch } from "./credentialless-fetch.js";
import { holdSdkHostLock } from "./offscreen-document.js";
import { extensionDeclaration } from "./sdk-declaration.js";
import { sdkHostSource } from "./sdk-host-source.js";
Expand All @@ -12,13 +11,11 @@ import { broadcastLink } from "./sdk-rpc.js";
* service worker reach it over sdk-rpc.ts; it has no UI. Offscreen documents only get
* chrome.runtime, so sign-in opens from the page whose action started it.
*/
globalThis.fetch = credentiallessFetch(globalThis.fetch.bind(globalThis));

async function start(): Promise<void> {
await holdSdkHostLock();
const hostId = crypto.randomUUID();
let host: SdkHost | null = null;
const sdk = new MdbaseConnect(extensionDeclaration(), {
const sdk = createMdbase(extensionDeclaration(), {
signIn: { open: (url) => host?.openSignIn(url) },
});
const source = sdkHostSource(sdk, hostId);
Expand Down
14 changes: 7 additions & 7 deletions apps/extension/src/sdk-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import {
} from "./sdk-rpc.js";

import type { ReaderConnectedCollection } from "@mdbase-reader/connect";
import type { MdbaseApplication, MdbaseApplicationSnapshot } from "@mdbase-reader/connect/native";
import type { Mdbase, MdbaseSnapshot } from "@mdbase-reader/connect/native";

/** The parts of the SDK application the extension's pages use. */
export type RemoteApplication = Pick<
MdbaseApplication,
Mdbase,
| "getSnapshot"
| "subscribe"
| "start"
| "authorize"
| "signIn"
| "approve"
| "select"
| "chooseAnother"
Expand Down Expand Up @@ -76,7 +76,7 @@ class HostConnection {
readonly #unlisten: () => void;
#nextId = 0;
#host: string | null = null;
#snapshot: MdbaseApplicationSnapshot | null = null;
#snapshot: MdbaseSnapshot | null = null;
#shape: CollectionShape | null = null;
#proxy: { readonly key: string; readonly collection: ReaderConnectedCollection } | null = null;
#disposed = false;
Expand All @@ -94,7 +94,7 @@ class HostConnection {
});
}

get snapshot(): MdbaseApplicationSnapshot {
get snapshot(): MdbaseSnapshot {
if (!this.#snapshot) {
throw new Error(translate`mdbase has not started yet.`);
}
Expand Down Expand Up @@ -318,7 +318,7 @@ export async function createSdkClient(
/** An application command whose answer must be an SDK snapshot. */
const command =
(method: ApplicationCommand) =>
async (...args: unknown[]): Promise<MdbaseApplicationSnapshot> => {
async (...args: unknown[]): Promise<MdbaseSnapshot> => {
const answer = await connection.call({ app: true }, method, args);
if (!isApplicationSnapshot(answer)) {
throw new Error(`mdbase answered ${method} with something other than its state.`);
Expand All @@ -329,7 +329,7 @@ export async function createSdkClient(
getSnapshot: () => connection.snapshot,
subscribe: (listener) => connection.subscribe(listener),
start: command("start"),
authorize: command("authorize"),
signIn: command("signIn"),
approve: command("approve"),
select: command("select"),
chooseAnother: command("chooseAnother"),
Expand Down
17 changes: 8 additions & 9 deletions apps/extension/src/sdk-host-source.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
nativeReaderCollection,
type MdbaseApplicationConnection,
type MdbaseApplicationEntry,
type MdbaseApplicationSnapshot,
type Mdbase,
type MdbaseSnapshot,
type NativeReaderCollection,
} from "@mdbase-reader/connect/native";
import { MemoryStorage, StorageCreateJournal } from "@mdbase-reader/platform";
Expand All @@ -18,7 +18,7 @@ import type { SdkHostSource } from "./sdk-host.js";
*/
const createStorage = new MemoryStorage();

function readyEvidence(snapshot: MdbaseApplicationSnapshot): boolean {
function readyEvidence(snapshot: MdbaseSnapshot): boolean {
const { readiness } = snapshot;
return (
snapshot.status === "ready" &&
Expand All @@ -32,8 +32,8 @@ function readyEvidence(snapshot: MdbaseApplicationSnapshot): boolean {

/** The SDK's current READY connection for the selected collection, or null. */
export function readyConnection(
sdk: MdbaseApplicationEntry,
snapshot: MdbaseApplicationSnapshot,
sdk: Mdbase,
snapshot: MdbaseSnapshot,
): MdbaseApplicationConnection | null {
const selected = snapshot.selectedCollectionId;
if (!selected || !readyEvidence(snapshot)) {
Expand All @@ -48,13 +48,12 @@ export function readyConnection(
* keyed by connection scope: a later snapshot may hand back a new facade for the same
* connection, which must not retire them.
*/
export function sdkHostSource(sdk: MdbaseApplicationEntry, hostId: string): SdkHostSource {
const application = sdk.application();
export function sdkHostSource(sdk: Mdbase, hostId: string): SdkHostSource {
let opened: { readonly key: string; readonly collection: NativeReaderCollection } | null = null;
return {
application,
application: sdk,
currentCollection() {
const connection = readyConnection(sdk, application.getSnapshot());
const connection = readyConnection(sdk, sdk.getSnapshot());
const key = connection ? `${hostId}:${connection.id}:${connection.generation}` : null;
if (opened?.key !== key) {
opened?.collection.dispose();
Expand Down
6 changes: 3 additions & 3 deletions apps/extension/src/sdk-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import {
} from "./sdk-rpc.js";

import type { ReaderConnectedCollection } from "@mdbase-reader/connect";
import type { MdbaseApplication } from "@mdbase-reader/connect/native";
import type { Mdbase } from "@mdbase-reader/connect/native";

export interface SdkHostSource {
readonly application: MdbaseApplication;
readonly application: Mdbase;
/** The adapters over the SDK's current READY connection, keyed by connection scope. */
currentCollection(): {
readonly key: string;
Expand All @@ -38,7 +38,7 @@ type CallMessage = Extract<ClientMessage, { kind: "call" }>;
type Method = (...args: unknown[]) => unknown;

/** Calls a person starts; a sign-in they lead to opens from that person's page. */
const interactive = new Set(["authorize", "approve", "chooseAnother", "select", "configure"]);
const interactive = new Set(["signIn", "approve", "chooseAnother", "select", "configure"]);

function member(owner: unknown, name: string): Method | null {
if (typeof owner !== "object" || owner === null) {
Expand Down
8 changes: 4 additions & 4 deletions apps/extension/src/sdk-rpc-lifetime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ afterEach(() => {
async function fixture(): Promise<
ReturnType<typeof createApplicationFixture> & {
client: SdkClient;
application: ReturnType<ReturnType<typeof createApplicationFixture>["entry"]["application"]>;
application: ReturnType<typeof createApplicationFixture>["mdbase"];
}
> {
// Real public SDK lifecycle fixture, not a cast READY application/session.
Expand All @@ -43,7 +43,7 @@ async function fixture(): Promise<
initialSnapshot: signedOutSnapshot,
});
fixtures.push(sdk);
const application = sdk.entry.application();
const application = sdk.mdbase;
const bus = memoryBus();
hosts.push(
serveSdk(bus.endpoint(), { application, currentCollection: () => null }, "owned-host"),
Expand All @@ -62,7 +62,7 @@ it("an already-aborted caller cannot invoke a protected SDK action through the b
h.controls.setHandler("authorize", () => h.application.getSnapshot());
const caller = new AbortController();
caller.abort();
await h.client.application.authorize({ signal: caller.signal }).catch(() => undefined);
await h.client.application.signIn({ signal: caller.signal }).catch(() => undefined);
expect(h.controls.observedActions().filter((call) => call.action === "authorize")).toHaveLength(
0,
);
Expand All @@ -78,7 +78,7 @@ it("disposing only this caller rejects its pending call without closing the SDK
finish = () => resolve(h.application.getSnapshot());
}),
);
const result = h.client.application.authorize().then(
const result = h.client.application.signIn().then(
() => "resolved",
() => "rejected",
);
Expand Down
16 changes: 8 additions & 8 deletions apps/extension/src/sdk-rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { memoryBus } from "./testing/memory-bus.js";
import { applicationFixture } from "./testing/sdk-fixture.js";

import type { MdbaseApplicationSnapshot } from "@mdbase-reader/connect/native";
import type { ApplicationFixtureSnapshot } from "@mdbase-reader/connect/testing";

const owned: { close(): void }[] = [];
afterEach(() => {
Expand All @@ -38,12 +38,12 @@ function host(
function fixtureHost(
bus: ReturnType<typeof memoryBus>,
id: string,
initial: Partial<MdbaseApplicationSnapshot> = {},
initial: Partial<ApplicationFixtureSnapshot> = {},
): ReturnType<typeof applicationFixture> & { served: ReturnType<typeof host> } {
const sdk = applicationFixture(initial);
owned.push(sdk.controls);
const served = host(bus, id, {
application: sdk.entry.application(),
application: sdk.mdbase,
currentCollection: () => null,
});
return { ...sdk, served };
Expand All @@ -66,7 +66,7 @@ async function client(
return created;
}

const never = new Promise<MdbaseApplicationSnapshot>(() => undefined);
const never = new Promise<ApplicationFixtureSnapshot>(() => undefined);

describe("SDK RPC between extension pages and the offscreen host", () => {
it("serves only the public application commands, with the SDK's snapshot", async () => {
Expand Down Expand Up @@ -104,7 +104,7 @@ describe("SDK RPC between extension pages and the offscreen host", () => {
await client(bus, { openSignIn: bystander });
const opener = vi.fn();
const remote = await client(bus, { openSignIn: opener });
await remote.application.authorize();
await remote.application.signIn();
await vi.waitFor(() =>
expect(opener).toHaveBeenCalledWith("https://connect-lab.mdbase.dev/approve"),
);
Expand All @@ -122,7 +122,7 @@ describe("SDK RPC between extension pages and the offscreen host", () => {
hostGone: (id) =>
new Promise<void>((resolve) => (id === "h1" ? (gone = resolve) : undefined)),
});
const pending = remote.application.authorize();
const pending = remote.application.signIn();
await vi.waitFor(() =>
expect(first.controls.observedActions().some((call) => call.action === "authorize")).toBe(
true,
Expand Down Expand Up @@ -161,7 +161,7 @@ describe("SDK RPC between extension pages and the offscreen host", () => {
}),
);
const remote = await client(bus);
const pending = remote.application.authorize().then(
const pending = remote.application.signIn().then(
() => "resolved",
(reason: unknown) => (reason instanceof Error ? reason.message : "rejected"),
);
Expand Down Expand Up @@ -189,7 +189,7 @@ describe("the READY collection over the SDK RPC", () => {
const sdk = applicationFixture();
owned.push(sdk.controls);
host(bus, "h1", {
application: sdk.entry.application(),
application: sdk.mdbase,
currentCollection: () => ({ key: "h1:c:1", collection }),
});
const remote = await client(bus);
Expand Down
8 changes: 4 additions & 4 deletions apps/extension/src/sdk-rpc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MdbaseApplicationSnapshot } from "@mdbase-reader/connect/native";
import type { MdbaseSnapshot } from "@mdbase-reader/connect/native";

type MdbaseApplicationReadinessSnapshot = MdbaseApplicationSnapshot["readiness"];
type MdbaseApplicationReadinessSnapshot = MdbaseSnapshot["readiness"];

/**
* The extension's SDK channel. One offscreen document owns the SDK (sdk-host.ts); the side
Expand Down Expand Up @@ -34,7 +34,7 @@ export function broadcastLink(name = sdkChannelName): SdkLink & { close(): void
/** The application commands the extension sends; nothing else reaches the SDK. */
export const applicationCommands = [
"start",
"authorize",
"signIn",
"approve",
"select",
"chooseAnother",
Expand Down Expand Up @@ -354,7 +354,7 @@ export function isReadinessSnapshot(value: unknown): value is MdbaseApplicationR
}

/** The fields the client reads from a host snapshot; anything else is not one. */
export function isApplicationSnapshot(value: unknown): value is MdbaseApplicationSnapshot {
export function isApplicationSnapshot(value: unknown): value is MdbaseSnapshot {
if (!isObject(value)) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions apps/extension/src/sign-in-recovery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ async function renderAndApprove(
copy: ReturnType<typeof describeError>,
): Promise<void> {
owned.push(h.controls);
const application = h.entry.application();
const application = h.mdbase;
const scope = new AbortController();
const approve = async (): Promise<void> => {
await application.approve(undefined, { signal: scope.signal });
Expand Down Expand Up @@ -80,7 +80,7 @@ for (const status of ["blocked", "authorizing"] as const) {
for (const code of ["refused", "expired"] as const) {
it(`${status}/${code} keeps SDK copy and an enabled approval gesture`, async () => {
const h = applicationFixture({ status, problem: code });
const copy = describeError(h.entry.application().getSnapshot());
const copy = describeError(h.mdbase.getSnapshot());
if (!copy?.actionLabel) {
throw new Error("Missing public SDK sign-in description");
}
Expand Down
6 changes: 3 additions & 3 deletions apps/extension/src/testing/sdk-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { createApplicationFixture } from "@mdbase-reader/connect/testing";

import manifest from "../generated/mdbase-app.json";

import type { MdbaseApplicationSnapshot } from "@mdbase-reader/connect/native";
import type { ApplicationFixtureSnapshot } from "@mdbase-reader/connect/testing";

const facet = { checking: false, assessment: null, problem: null };

/** A complete signed-out public snapshot, for the SDK's own application fixture. */
export const signedOutSnapshot: MdbaseApplicationSnapshot = {
export const signedOutSnapshot: ApplicationFixtureSnapshot = {
status: "signed_out",
signIn: null,
collections: [],
Expand Down Expand Up @@ -35,7 +35,7 @@ export const signedOutSnapshot: MdbaseApplicationSnapshot = {

/** The SDK's public application fixture: test metadata only, never runtime evidence. */
export function applicationFixture(
initial: Partial<MdbaseApplicationSnapshot> = {},
initial: Partial<ApplicationFixtureSnapshot> = {},
): ReturnType<typeof createApplicationFixture> {
return createApplicationFixture({
declaration: {
Expand Down
Loading