@keyboard-hub/abyss-client
v0.0.1
Published
OAuth and API client for Keyboard Abyss browser and Node.js integrations.
Readme
@keyboard-hub/abyss-client
OAuth and API client for Keyboard Abyss browser and Node.js integrations.
Install
npm install @keyboard-hub/abyss-clientQuick Start
import { createAbyssClient } from "@keyboard-hub/abyss-client";
const abyss = createAbyssClient({
// Register a client in Keyboard Abyss Settings > Developer.
clientId: "CLIENT_ID_FROM_ABYSS_SETTINGS",
// Abyss redirects the user back here after consent. This exact URI must
// be registered on the OAuth client.
redirectUri: `${location.origin}/oauth/callback`,
// Request write scope only when the editor will save keymaps.
scopes: ["profile:read", "keymap:read", "keymap:write"],
});
if (abyss.hasAuthorizationCode()) {
// On the callback page, verify state + PKCE and store the returned tokens.
await abyss.handleRedirectCallback();
} else if (!abyss.getTokenSet()) {
// On first use, create a PKCE challenge and redirect to Abyss consent.
await abyss.startAuthorization();
}
// API helpers refresh the access token automatically when it is near expiry.
const profile = await abyss.userinfo();
const keymaps = await abyss.listMyKeymaps({ visibility: "all" });
const firstPage = await abyss.listMyKeymaps({
visibility: "all",
page: 1,
limit: 20,
});Load and Save Keymap to Abyss in Your Service
This example reads layout/keymap information from a connected keyboard, resolves that layout in Abyss, lets the user pick the first saved keymap for the same layout variation, and appends a new version when the user saves.
import { createAbyssClient } from "@keyboard-hub/abyss-client";
import type {
AbyssKeymapData,
AbyssKeymapSummary,
AbyssLayoutDefinition,
} from "@keyboard-hub/abyss-client";
type DeviceConnection = {
disconnect?: () => Promise<void> | void;
};
type ConnectedKeyboardState = {
keyboardName: string;
layout: AbyssLayoutDefinition;
keymap: AbyssKeymapData;
};
// Supply these functions from your editor or firmware integration.
declare function connectToKeyboard(): Promise<DeviceConnection>;
declare function readConnectedKeyboard(
connection: DeviceConnection,
): Promise<ConnectedKeyboardState>;
declare function editKeymapInYourAppAndSaveToDevice(
connection: DeviceConnection,
keymap: AbyssKeymapSummary,
): Promise<void>;
const abyss = createAbyssClient({
clientId: "CLIENT_ID_FROM_ABYSS_SETTINGS",
redirectUri: `${location.origin}/oauth/callback`,
scopes: ["profile:read", "keymap:read", "keymap:write", "layout:read"],
});
const connection = await connectToKeyboard();
try {
const device = await readConnectedKeyboard(connection);
const resolved = await abyss.resolveLayout({
keyboard: device.keyboardName,
layout: device.layout,
});
if (!resolved.layout) {
// Abyss must know this keyboard before your service can match saved keymaps.
throw new Error("Register this keyboard in Abyss before start.");
}
const keymaps = await abyss.listMyKeymaps({
visibility: "all",
keyboard: device.keyboardName,
layoutId: resolved.layout.id,
layoutVariationId: resolved.layout.variation.id,
});
const selected = keymaps[0];
if (!selected) {
throw new Error("No saved keymap exists for this connected layout.");
}
await editKeymapInYourAppAndSaveToDevice(connection, selected);
// Re-read after device writeback so Abyss stores the firmware state that
// actually survived adapter validation, not a stale in-memory draft.
const savedDevice = await readConnectedKeyboard(connection);
await abyss.updateKeymap(selected.id, {
data: savedDevice.keymap,
layoutVariationId: resolved.layout.variation.id,
layoutVersionId: resolved.layout.latestVersion.id,
layout: savedDevice.layout,
message: "Saved from connected keyboard",
});
} finally {
await connection.disconnect?.();
}Node.js
import { createAbyssClient } from "@keyboard-hub/abyss-client";
import { createNodeFileStorage } from "@keyboard-hub/abyss-client/node";
const abyss = createAbyssClient({
clientId: process.env.ABYSS_CLIENT_ID!,
redirectUri: "http://127.0.0.1:3000/oauth/callback",
storage: createNodeFileStorage(".keyboard-abyss/tokens.json"),
transactionStorage: createNodeFileStorage(".keyboard-abyss/oauth.json"),
});
const loginUrl = await abyss.buildAuthorizationUrl();
console.log(`Open ${loginUrl}`);
await abyss.handleRedirectCallback(callbackUrlFromYourServer);
const keymaps = await abyss.listMyKeymaps({ visibility: "all" });