dazzer-connect 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,79 +0,0 @@
1
- function writeOut(message) {
2
- process.stdout.write(`${message}\n`);
3
- }
4
- function writeErr(message) {
5
- process.stderr.write(`${message}\n`);
6
- }
7
- /** Prints device-flow instructions for the user to complete in a browser. */
8
- export function printDeviceInstructions(deviceAuth) {
9
- writeOut("");
10
- if (deviceAuth.verification_uri_complete) {
11
- writeOut("To finish signing in, open this link in your browser:");
12
- writeOut(` ${deviceAuth.verification_uri_complete}`);
13
- }
14
- else {
15
- writeOut("To finish signing in, open this page in your browser:");
16
- writeOut(` ${deviceAuth.verification_uri}`);
17
- writeOut("");
18
- writeOut("Then enter this code:");
19
- writeOut(` ${deviceAuth.user_code}`);
20
- }
21
- writeOut("");
22
- writeOut("Waiting for you to approve in the browser...");
23
- }
24
- /** Tells the user their browser is opening for the loopback sign-in, with a manual fallback. */
25
- export function printBrowserOpening(url) {
26
- writeOut("");
27
- writeOut("Opening your browser to sign in…");
28
- writeOut("If it doesn't open automatically, paste this into your browser:");
29
- writeOut(` ${url}`);
30
- writeOut("");
31
- }
32
- /** Prints success message after login completes. */
33
- export function printLoginSuccess(keychainOk) {
34
- writeOut("");
35
- writeOut("Signed in successfully.");
36
- if (!keychainOk) {
37
- writeErr("Warning: could not save tokens to the OS keychain. Use the config below.");
38
- }
39
- }
40
- /** Prints copy-paste-ready MCP client config with Bearer authorization. */
41
- export function printMcpClientConfig(accessToken, mcpServerUrl) {
42
- writeOut("");
43
- writeOut("Copy this into your MCP client configuration:");
44
- writeOut("");
45
- writeOut("{");
46
- writeOut(' "mcpServers": {');
47
- writeOut(' "dazzer": {');
48
- writeOut(` "url": "${mcpServerUrl.replace(/\/$/, "")}",`);
49
- writeOut(' "headers": {');
50
- writeOut(` "Authorization": "Bearer ${accessToken}"`);
51
- writeOut(" }");
52
- writeOut(" }");
53
- writeOut(" }");
54
- writeOut("}");
55
- writeOut("");
56
- }
57
- /** Prints auth status for the status command. */
58
- export function printAuthStatus(params) {
59
- if (!params.signedIn) {
60
- writeOut("Not signed in. Run: dazzer auth login");
61
- return;
62
- }
63
- writeOut("Signed in.");
64
- if (params.issuer) {
65
- writeOut(` Issuer: ${params.issuer}`);
66
- }
67
- if (params.expiresAt) {
68
- writeOut(` Token expires: ${new Date(params.expiresAt).toISOString()}`);
69
- }
70
- }
71
- /** Prints logout confirmation. */
72
- export function printLogoutSuccess() {
73
- writeOut("Signed out.");
74
- }
75
- /** Prints a user-facing error and exits. */
76
- export function fail(message) {
77
- writeErr(`Error: ${message}`);
78
- process.exit(1);
79
- }
@@ -1,60 +0,0 @@
1
- /** Exchanges a refresh token for a new access token (and rotated refresh token). */
2
- export async function refreshAccessToken(options) {
3
- const fetchFn = options.fetchFn ?? fetch;
4
- const params = new URLSearchParams({
5
- grant_type: "refresh_token",
6
- client_id: options.clientId,
7
- refresh_token: options.refreshToken,
8
- });
9
- if (options.resource) {
10
- params.set("resource", options.resource);
11
- }
12
- const res = await fetchFn(options.discovery.tokenEndpoint, {
13
- method: "POST",
14
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
15
- body: params.toString(),
16
- });
17
- const body = (await res.json());
18
- if (!res.ok) {
19
- const error = typeof body.error === "string" ? body.error : "refresh_failed";
20
- throw new Error(`Could not refresh token: ${error}`);
21
- }
22
- const accessToken = body.access_token;
23
- const refreshToken = body.refresh_token;
24
- if (typeof accessToken !== "string") {
25
- throw new Error("The authorization server returned an unexpected refresh response.");
26
- }
27
- const newRefresh = typeof refreshToken === "string" ? refreshToken : options.refreshToken;
28
- const expiresIn = typeof body.expires_in === "number" ? body.expires_in : null;
29
- await options.tokenStore.save({ accessToken, refreshToken: newRefresh });
30
- return { accessToken, refreshToken: newRefresh, expiresIn };
31
- }
32
- /** Returns a valid access token, refreshing when possible. */
33
- export async function getValidAccessToken(options) {
34
- const stored = await options.tokenStore.load();
35
- if (!stored) {
36
- return null;
37
- }
38
- try {
39
- return await refreshAccessToken({ ...options, refreshToken: stored.refreshToken });
40
- }
41
- catch {
42
- return {
43
- accessToken: stored.accessToken,
44
- refreshToken: stored.refreshToken,
45
- expiresIn: null,
46
- };
47
- }
48
- }
49
- /** Saves freshly issued tokens after login. */
50
- export async function persistLoginTokens(tokenStore, tokens) {
51
- if (!tokens.refresh_token) {
52
- throw new Error("The authorization server did not return a refresh token.");
53
- }
54
- const stored = {
55
- accessToken: tokens.access_token,
56
- refreshToken: tokens.refresh_token,
57
- };
58
- await tokenStore.save(stored);
59
- return stored;
60
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * @purpose Defines the token storage contract and provides keychain-backed and
3
- * in-memory implementations so secrets stay out of disk while tests stay hermetic.
4
- */
5
- import { Entry } from "@napi-rs/keyring";
6
- const SERVICE = "dazzer-oauth-cli";
7
- const ACCESS_ACCOUNT = "access-token";
8
- const REFRESH_ACCOUNT = "refresh-token";
9
- function accessEntry() {
10
- return new Entry(SERVICE, ACCESS_ACCOUNT);
11
- }
12
- function refreshEntry() {
13
- return new Entry(SERVICE, REFRESH_ACCOUNT);
14
- }
15
- /** Persists tokens in the OS keychain via @napi-rs/keyring. */
16
- export class KeychainTokenStore {
17
- async save(tokens) {
18
- accessEntry().setPassword(tokens.accessToken);
19
- refreshEntry().setPassword(tokens.refreshToken);
20
- }
21
- async load() {
22
- const accessToken = accessEntry().getPassword();
23
- const refreshToken = refreshEntry().getPassword();
24
- if (!accessToken || !refreshToken) {
25
- return null;
26
- }
27
- return { accessToken, refreshToken };
28
- }
29
- async clear() {
30
- try {
31
- accessEntry().deletePassword();
32
- }
33
- catch {
34
- // ignore missing entry
35
- }
36
- try {
37
- refreshEntry().deletePassword();
38
- }
39
- catch {
40
- // ignore missing entry
41
- }
42
- }
43
- }
44
- /** In-memory store for unit tests. */
45
- export class MemoryTokenStore {
46
- tokens = null;
47
- async save(tokens) {
48
- this.tokens = { ...tokens };
49
- }
50
- async load() {
51
- return this.tokens ? { ...this.tokens } : null;
52
- }
53
- async clear() {
54
- this.tokens = null;
55
- }
56
- }
57
- /** Default production token store. */
58
- export function createTokenStore() {
59
- return new KeychainTokenStore();
60
- }