@getpaseo/cli 0.3.0-beta.4 → 0.3.1

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.
Files changed (41) hide show
  1. package/dist/commands/hub/authority.d.ts +17 -0
  2. package/dist/commands/hub/authority.js +18 -0
  3. package/dist/commands/hub/client.d.ts +55 -3
  4. package/dist/commands/hub/client.js +158 -38
  5. package/dist/commands/hub/connect.d.ts +21 -0
  6. package/dist/commands/hub/connect.js +34 -0
  7. package/dist/commands/hub/credentials.d.ts +21 -0
  8. package/dist/commands/hub/credentials.js +143 -0
  9. package/dist/commands/hub/daemon-client.d.ts +27 -0
  10. package/dist/commands/hub/daemon-client.js +14 -0
  11. package/dist/commands/hub/deploy-input.js +28 -28
  12. package/dist/commands/hub/deploy.d.ts +23 -3
  13. package/dist/commands/hub/deploy.js +51 -42
  14. package/dist/commands/hub/disconnect.d.ts +16 -0
  15. package/dist/commands/hub/disconnect.js +24 -0
  16. package/dist/commands/hub/error.d.ts +1 -1
  17. package/dist/commands/hub/error.js +2 -2
  18. package/dist/commands/hub/help.d.ts +3 -0
  19. package/dist/commands/hub/help.js +5 -0
  20. package/dist/commands/hub/index.d.ts +15 -25
  21. package/dist/commands/hub/index.js +64 -74
  22. package/dist/commands/hub/{device-authorization.d.ts → login-flow.d.ts} +12 -15
  23. package/dist/commands/hub/login-flow.js +78 -0
  24. package/dist/commands/hub/login.d.ts +21 -0
  25. package/dist/commands/hub/login.js +34 -0
  26. package/dist/commands/hub/logout.d.ts +31 -0
  27. package/dist/commands/hub/logout.js +65 -0
  28. package/dist/commands/hub/origin.d.ts +2 -0
  29. package/dist/commands/hub/origin.js +27 -0
  30. package/dist/commands/hub/projects.d.ts +24 -0
  31. package/dist/commands/hub/projects.js +49 -0
  32. package/dist/commands/hub/reporter.d.ts +10 -0
  33. package/dist/commands/hub/reporter.js +11 -0
  34. package/dist/commands/hub/status-output.d.ts +13 -0
  35. package/dist/commands/hub/status-output.js +30 -0
  36. package/dist/commands/schedule/types.d.ts +1 -4
  37. package/dist/output/types.d.ts +1 -1
  38. package/package.json +4 -4
  39. package/dist/commands/hub/cloud-device-authorization.d.ts +0 -45
  40. package/dist/commands/hub/cloud-device-authorization.js +0 -92
  41. package/dist/commands/hub/device-authorization.js +0 -87
@@ -1,5 +1,5 @@
1
- import { type CloudDeviceAuthorization } from "./cloud-device-authorization.js";
2
- export interface AuthorizationWaiter {
1
+ import type { HubHttpClient } from "./client.js";
2
+ export interface LoginWaiter {
3
3
  wait(milliseconds: number): Promise<void>;
4
4
  now(): number;
5
5
  }
@@ -17,21 +17,18 @@ export declare class SystemBrowser implements BrowserOpener {
17
17
  constructor(options?: SystemBrowserOptions);
18
18
  open(url: string): Promise<void>;
19
19
  }
20
- export interface AuthorizationReporter {
21
- instructions(verificationUri: string, userCode: string): void;
22
- }
23
- interface DeviceAuthorizationWorkflowOptions {
24
- cloud: CloudDeviceAuthorization;
25
- waiter: AuthorizationWaiter;
20
+ interface CliLoginFlowOptions {
21
+ hub: Pick<HubHttpClient, "startCliAuthorization" | "pollCliAuthorization">;
22
+ waiter: LoginWaiter;
26
23
  browser: BrowserOpener;
27
- reporter: AuthorizationReporter;
28
- openBrowser?: boolean;
24
+ instructions(verificationUri: string, userCode: string): void;
25
+ openBrowser: boolean;
29
26
  }
30
- export declare class DeviceAuthorizationWorkflow {
27
+ export declare class CliLoginFlow {
31
28
  private readonly options;
32
- constructor(options: DeviceAuthorizationWorkflowOptions);
33
- authorize(hubUrl: string, displayName: string): Promise<string>;
29
+ constructor(options: CliLoginFlowOptions);
30
+ authorize(origin: string): Promise<string>;
34
31
  }
35
- export declare function createDeviceAuthorizationWorkflow(): DeviceAuthorizationWorkflow;
32
+ export declare function createCliLoginFlow(hub: HubHttpClient): CliLoginFlow;
36
33
  export {};
37
- //# sourceMappingURL=device-authorization.d.ts.map
34
+ //# sourceMappingURL=login-flow.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { spawn } from "node:child_process";
2
+ import { platform } from "node:os";
3
+ export class SystemBrowser {
4
+ constructor(options = {}) {
5
+ this.hostPlatform = options.hostPlatform ?? platform();
6
+ this.launch = options.launch ?? launchDetached;
7
+ }
8
+ async open(url) {
9
+ if (this.hostPlatform === "win32") {
10
+ await this.launch("rundll32.exe", ["url.dll,FileProtocolHandler", url]);
11
+ return;
12
+ }
13
+ await this.launch(this.hostPlatform === "darwin" ? "open" : "xdg-open", [url]);
14
+ }
15
+ }
16
+ export class CliLoginFlow {
17
+ constructor(options) {
18
+ this.options = options;
19
+ }
20
+ async authorize(origin) {
21
+ const authorization = await this.options.hub.startCliAuthorization(origin);
22
+ this.options.instructions(authorization.verificationUri, authorization.userCode);
23
+ if (this.options.openBrowser) {
24
+ await this.options.browser.open(authorization.verificationUriComplete).catch(() => undefined);
25
+ }
26
+ let interval = authorization.interval;
27
+ const expiresAt = Date.parse(authorization.expiresAt);
28
+ while (true) {
29
+ const remaining = expiresAt - this.options.waiter.now();
30
+ if (remaining <= 0)
31
+ throw new Error("Hub CLI login expired");
32
+ await this.options.waiter.wait(Math.min(interval * 1000, remaining));
33
+ const pollLifetime = expiresAt - this.options.waiter.now();
34
+ if (pollLifetime <= 0)
35
+ throw new Error("Hub CLI login expired");
36
+ const outcome = await this.options.hub.pollCliAuthorization(origin, authorization.deviceCode, pollLifetime);
37
+ const credential = approvedCredential(outcome);
38
+ if (credential !== null)
39
+ return credential;
40
+ if (outcome.status === "denied")
41
+ throw new Error("Hub CLI login was denied");
42
+ if (outcome.status === "expired")
43
+ throw new Error("Hub CLI login expired");
44
+ if (outcome.status === "disclosed")
45
+ throw new Error("Hub CLI login was already completed");
46
+ if (outcome.status !== "retry_later")
47
+ interval = outcome.interval;
48
+ }
49
+ }
50
+ }
51
+ export function createCliLoginFlow(hub) {
52
+ return new CliLoginFlow({
53
+ hub,
54
+ waiter: {
55
+ wait: (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)),
56
+ now: Date.now,
57
+ },
58
+ browser: new SystemBrowser(),
59
+ instructions(verificationUri, userCode) {
60
+ process.stderr.write(`Open ${verificationUri} and enter code ${userCode}\n`);
61
+ },
62
+ openBrowser: process.stderr.isTTY === true,
63
+ });
64
+ }
65
+ function approvedCredential(outcome) {
66
+ return outcome.status === "authorized" ? outcome.credential : null;
67
+ }
68
+ async function launchDetached(command, args) {
69
+ await new Promise((resolve, reject) => {
70
+ const child = spawn(command, args, { detached: true, shell: false, stdio: "ignore" });
71
+ child.once("spawn", () => {
72
+ child.unref();
73
+ resolve();
74
+ });
75
+ child.once("error", reject);
76
+ });
77
+ }
78
+ //# sourceMappingURL=login-flow.js.map
@@ -0,0 +1,21 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubCredentialStore } from "./credentials.js";
4
+ import type { CliLoginFlow } from "./login-flow.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubLoginResult {
7
+ origin: string;
8
+ status: "logged_in";
9
+ }
10
+ interface HubLoginDependencies {
11
+ env: Readonly<Record<string, string | undefined>>;
12
+ credentials: HubCredentialStore;
13
+ flow: Pick<CliLoginFlow, "authorize">;
14
+ reporter: HubReporter;
15
+ }
16
+ export declare function runHubLogin(originInput: string | undefined, options: {
17
+ json?: boolean;
18
+ }, dependencies: HubLoginDependencies): Promise<SingleResult<HubLoginResult>>;
19
+ export declare function addHubLoginCommand(parent: Command, dependencies: HubLoginDependencies): void;
20
+ export {};
21
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { withOutput } from "../../output/index.js";
2
+ import { addJsonOption } from "../../utils/command-options.js";
3
+ import { resolveHubOrigin } from "./authority.js";
4
+ import { reportHubProgress } from "./reporter.js";
5
+ import { addHubResolutionHelp } from "./help.js";
6
+ const schema = {
7
+ idField: "origin",
8
+ columns: [
9
+ { header: "HUB", field: "origin" },
10
+ { header: "STATUS", field: "status" },
11
+ ],
12
+ };
13
+ export async function runHubLogin(originInput, options, dependencies) {
14
+ const origin = resolveHubOrigin({
15
+ options: { origin: originInput },
16
+ env: dependencies.env,
17
+ credentials: dependencies.credentials,
18
+ });
19
+ reportHubProgress(dependencies.reporter, options, `Logging in to ${origin}`);
20
+ const credential = await dependencies.flow.authorize(origin);
21
+ dependencies.credentials.save({ origin, credential });
22
+ return { type: "single", data: { origin, status: "logged_in" }, schema };
23
+ }
24
+ export function addHubLoginCommand(parent, dependencies) {
25
+ addJsonOption(addHubResolutionHelp(parent
26
+ .command("login")
27
+ .description("Log in to a Paseo Hub for CLI access")
28
+ .argument("[origin]", "Paseo Hub origin"))).action(withOutput(async (...args) => {
29
+ const origin = args[0];
30
+ const options = args.at(-2);
31
+ return runHubLogin(origin, options, dependencies);
32
+ }));
33
+ }
34
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1,31 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubCredentialStore } from "./credentials.js";
4
+ import type { HubDaemonConnection } from "./daemon-client.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubLogoutResult {
7
+ origin: string | null;
8
+ status: "logged_out" | "not_logged_in";
9
+ daemonDisconnected: boolean;
10
+ }
11
+ interface HubLogoutOptions {
12
+ disconnectDaemon?: boolean;
13
+ force?: boolean;
14
+ host?: string;
15
+ json?: boolean;
16
+ }
17
+ interface HubLogoutDependencies {
18
+ credentials: HubCredentialStore;
19
+ daemon: HubDaemonConnection;
20
+ isInteractive(): boolean;
21
+ confirmDisconnect(origin: string): Promise<boolean>;
22
+ reporter: HubReporter;
23
+ }
24
+ export declare function runHubLogout(options: HubLogoutOptions, dependencies: HubLogoutDependencies): Promise<SingleResult<HubLogoutResult>>;
25
+ export declare function addHubLogoutCommand(parent: Command, dependencies: HubLogoutDependencies): void;
26
+ export declare const productionLogoutPrompt: {
27
+ isInteractive: () => boolean;
28
+ confirmDisconnect(origin: string): Promise<boolean>;
29
+ };
30
+ export {};
31
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { confirm, isCancel } from "@clack/prompts";
2
+ import { withOutput } from "../../output/index.js";
3
+ import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
4
+ import { withHubDaemon } from "./daemon-client.js";
5
+ import { reportHubProgress } from "./reporter.js";
6
+ const schema = {
7
+ idField: "status",
8
+ columns: [
9
+ { header: "HUB", field: "origin" },
10
+ { header: "STATUS", field: "status" },
11
+ { header: "DAEMON DISCONNECTED", field: "daemonDisconnected" },
12
+ ],
13
+ };
14
+ export async function runHubLogout(options, dependencies) {
15
+ const active = dependencies.credentials.active();
16
+ if (active === null) {
17
+ return logoutResult({ origin: null, status: "not_logged_in", daemonDisconnected: false });
18
+ }
19
+ reportHubProgress(dependencies.reporter, options, `Logging out of ${active.origin}`);
20
+ const mayPrompt = options.json !== true && dependencies.isInteractive();
21
+ let daemonStatus = null;
22
+ const shouldInspectDaemon = options.disconnectDaemon === true || mayPrompt;
23
+ if (shouldInspectDaemon) {
24
+ daemonStatus = await withHubDaemon(dependencies.daemon, options.host, async (daemon) => daemon.getHubStatus().then((response) => response.status));
25
+ }
26
+ const sameHub = daemonStatus?.hubOrigin === active.origin;
27
+ let shouldDisconnect = options.disconnectDaemon === true && sameHub;
28
+ if (options.disconnectDaemon !== true && mayPrompt && sameHub) {
29
+ shouldDisconnect = await dependencies.confirmDisconnect(active.origin);
30
+ }
31
+ if (!shouldDisconnect) {
32
+ dependencies.credentials.logoutActive();
33
+ return logoutResult({ origin: active.origin, status: "logged_out", daemonDisconnected: false });
34
+ }
35
+ reportHubProgress(dependencies.reporter, options, `Disconnecting this daemon from ${active.origin}`);
36
+ await withHubDaemon(dependencies.daemon, options.host, async (daemon) => {
37
+ await daemon.disconnectHub(options.force ?? false);
38
+ });
39
+ dependencies.credentials.logoutActive();
40
+ return logoutResult({ origin: active.origin, status: "logged_out", daemonDisconnected: true });
41
+ }
42
+ export function addHubLogoutCommand(parent, dependencies) {
43
+ addJsonAndDaemonHostOptions(parent
44
+ .command("logout")
45
+ .description("Remove the active stored Hub CLI login")
46
+ .option("--disconnect-daemon", "Also disconnect a daemon related to the same Hub")
47
+ .option("--force", "Remove daemon authority even if Hub is offline")).action(withOutput(async (...args) => {
48
+ const options = args.at(-2);
49
+ return runHubLogout(options, dependencies);
50
+ }));
51
+ }
52
+ export const productionLogoutPrompt = {
53
+ isInteractive: () => Boolean(process.stdin.isTTY && process.stdout.isTTY),
54
+ async confirmDisconnect(origin) {
55
+ const answer = await confirm({
56
+ message: `Disconnect this daemon from ${origin}?`,
57
+ initialValue: false,
58
+ });
59
+ return !isCancel(answer) && answer;
60
+ },
61
+ };
62
+ function logoutResult(data) {
63
+ return { type: "single", data, schema };
64
+ }
65
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1,2 @@
1
+ export declare function normalizeHubOrigin(value: string): string;
2
+ //# sourceMappingURL=origin.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { HubCommandError } from "./error.js";
2
+ export function normalizeHubOrigin(value) {
3
+ let url;
4
+ try {
5
+ url = new URL(value);
6
+ }
7
+ catch {
8
+ throw invalidHubOrigin();
9
+ }
10
+ if (!["http:", "https:"].includes(url.protocol) ||
11
+ (url.protocol === "http:" && !isLoopbackHostname(url.hostname)) ||
12
+ url.username ||
13
+ url.password ||
14
+ url.pathname !== "/" ||
15
+ url.search ||
16
+ url.hash) {
17
+ throw invalidHubOrigin();
18
+ }
19
+ return url.origin;
20
+ }
21
+ function isLoopbackHostname(hostname) {
22
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
23
+ }
24
+ function invalidHubOrigin() {
25
+ return new HubCommandError("HUB_INVALID_ORIGIN", "Hub URL must be an HTTPS origin without credentials, path, query, or hash. HTTP is allowed only for localhost, 127.0.0.1, or [::1].");
26
+ }
27
+ //# sourceMappingURL=origin.js.map
@@ -0,0 +1,24 @@
1
+ import type { Command } from "commander";
2
+ import { type SingleResult } from "../../output/index.js";
3
+ import type { HubHttpClient, HubProject } from "./client.js";
4
+ import type { HubCredentialStore } from "./credentials.js";
5
+ import { type HubReporter } from "./reporter.js";
6
+ interface HubProjectsResult {
7
+ origin: string;
8
+ projects: HubProject[];
9
+ }
10
+ export interface HubProjectsOptions {
11
+ hub?: string;
12
+ apiKey?: string;
13
+ json?: boolean;
14
+ }
15
+ interface HubProjectsDependencies {
16
+ env: Readonly<Record<string, string | undefined>>;
17
+ credentials: HubCredentialStore;
18
+ hub: Pick<HubHttpClient, "listProjects">;
19
+ reporter: HubReporter;
20
+ }
21
+ export declare function runHubProjects(options: HubProjectsOptions, dependencies: HubProjectsDependencies): Promise<SingleResult<HubProjectsResult>>;
22
+ export declare function addHubProjectsCommand(parent: Command, dependencies: HubProjectsDependencies): void;
23
+ export {};
24
+ //# sourceMappingURL=projects.d.ts.map
@@ -0,0 +1,49 @@
1
+ import { render, withOutput } from "../../output/index.js";
2
+ import { addJsonOption } from "../../utils/command-options.js";
3
+ import { resolveHubCredential, resolveHubOrigin } from "./authority.js";
4
+ import { reportHubProgress } from "./reporter.js";
5
+ import { addHubResolutionHelp } from "./help.js";
6
+ const projectSchema = {
7
+ idField: "id",
8
+ columns: [
9
+ { header: "SLUG", field: "slug" },
10
+ { header: "NAME", field: "name" },
11
+ { header: "ID", field: "id" },
12
+ { header: "HUB", field: "origin" },
13
+ ],
14
+ };
15
+ const schema = {
16
+ idField: "origin",
17
+ columns: [
18
+ { header: "HUB", field: "origin" },
19
+ { header: "PROJECTS", field: (result) => result.projects.length },
20
+ ],
21
+ renderHuman(result, options) {
22
+ const results = result.type === "single" ? [result.data] : result.data;
23
+ const data = results.flatMap((entry) => entry.projects.map((project) => ({ ...project, origin: entry.origin })));
24
+ return render({ type: "list", data, schema: projectSchema }, options);
25
+ },
26
+ };
27
+ export async function runHubProjects(options, dependencies) {
28
+ const resolution = {
29
+ options: { origin: options.hub, apiKey: options.apiKey },
30
+ env: dependencies.env,
31
+ credentials: dependencies.credentials,
32
+ };
33
+ const origin = resolveHubOrigin(resolution);
34
+ reportHubProgress(dependencies.reporter, options, `Listing projects from ${origin}`);
35
+ const credential = resolveHubCredential({ ...resolution, origin });
36
+ const projects = await dependencies.hub.listProjects(origin, credential);
37
+ return { type: "single", data: { origin, projects }, schema };
38
+ }
39
+ export function addHubProjectsCommand(parent, dependencies) {
40
+ addJsonOption(addHubResolutionHelp(parent
41
+ .command("projects")
42
+ .description("List projects for the authenticated Hub organization")
43
+ .option("--hub <origin>", "Paseo Hub origin")
44
+ .option("--api-key <secret>", "Organization API key"))).action(withOutput(async (...args) => {
45
+ const options = args.at(-2);
46
+ return runHubProjects(options, dependencies);
47
+ }));
48
+ }
49
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1,10 @@
1
+ export interface HubReporter {
2
+ progress(message: string): void;
3
+ }
4
+ export declare const processHubReporter: HubReporter;
5
+ interface HubReportOptions {
6
+ json?: boolean;
7
+ }
8
+ export declare function reportHubProgress(reporter: HubReporter, options: HubReportOptions, message: string): void;
9
+ export {};
10
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1,11 @@
1
+ export const processHubReporter = {
2
+ progress(message) {
3
+ process.stderr.write(`${message}\n`);
4
+ },
5
+ };
6
+ export function reportHubProgress(reporter, options, message) {
7
+ if (options.json === true)
8
+ return;
9
+ reporter.progress(message);
10
+ }
11
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1,13 @@
1
+ import type { ListResult } from "../../output/index.js";
2
+ import type { HubStatus } from "./daemon-client.js";
3
+ export interface HubRow {
4
+ state: string;
5
+ daemonId: string | null;
6
+ hub: string | null;
7
+ scopes: string;
8
+ connectedAt: string | null;
9
+ error: string | null;
10
+ warning?: string;
11
+ }
12
+ export declare function hubStatusResult(status: HubStatus, warning?: string, reportedHubOrigin?: string | null): ListResult<HubRow>;
13
+ //# sourceMappingURL=status-output.d.ts.map
@@ -0,0 +1,30 @@
1
+ const schema = {
2
+ idField: "state",
3
+ columns: [
4
+ { header: "STATE", field: "state" },
5
+ { header: "HUB", field: "hub" },
6
+ { header: "DAEMON", field: "daemonId" },
7
+ { header: "SCOPES", field: "scopes" },
8
+ { header: "CONNECTED", field: "connectedAt" },
9
+ { header: "ERROR", field: "error" },
10
+ { header: "WARNING", field: "warning" },
11
+ ],
12
+ };
13
+ export function hubStatusResult(status, warning, reportedHubOrigin = status.hubOrigin) {
14
+ return {
15
+ type: "list",
16
+ data: [
17
+ {
18
+ state: status.state,
19
+ daemonId: status.daemonId,
20
+ hub: reportedHubOrigin,
21
+ scopes: status.scopes.join(", "),
22
+ connectedAt: status.connectedAt,
23
+ error: status.lastError,
24
+ warning,
25
+ },
26
+ ],
27
+ schema,
28
+ };
29
+ }
30
+ //# sourceMappingURL=status-output.js.map
@@ -22,10 +22,7 @@ export type ScheduleTarget = {
22
22
  model?: string;
23
23
  thinkingOptionId?: string;
24
24
  title?: string | null;
25
- approvalPolicy?: string;
26
- sandboxMode?: string;
27
- networkAccess?: boolean;
28
- webSearch?: boolean;
25
+ providerOptions?: Record<string, unknown>;
29
26
  };
30
27
  };
31
28
  export interface ScheduleRunRecord {
@@ -58,7 +58,7 @@ export interface ListResult<T> {
58
58
  schema: OutputSchema<T>;
59
59
  }
60
60
  /** Union type for all command results */
61
- export type AnyCommandResult<T> = SingleResult<T> | ListResult<T>;
61
+ export type AnyCommandResult<T> = T extends unknown ? SingleResult<T> | ListResult<T> : never;
62
62
  /** Base interface for command results (deprecated, use SingleResult or ListResult) */
63
63
  export type CommandResult<T> = SingleResult<T> | ListResult<T>;
64
64
  /** Structured error for command failures */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpaseo/cli",
3
- "version": "0.3.0-beta.4",
3
+ "version": "0.3.1",
4
4
  "description": "Paseo CLI - control your AI coding agents from the command line",
5
5
  "bin": {
6
6
  "paseo": "bin/paseo"
@@ -28,9 +28,9 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@clack/prompts": "^1.0.0",
31
- "@getpaseo/client": "0.3.0-beta.4",
32
- "@getpaseo/protocol": "0.3.0-beta.4",
33
- "@getpaseo/server": "0.3.0-beta.4",
31
+ "@getpaseo/client": "0.3.1",
32
+ "@getpaseo/protocol": "0.3.1",
33
+ "@getpaseo/server": "0.3.1",
34
34
  "chalk": "^5.3.0",
35
35
  "commander": "^12.0.0",
36
36
  "mime-types": "^2.1.35",
@@ -1,45 +0,0 @@
1
- import { z } from "zod";
2
- declare const authorizationSchema: z.ZodObject<{
3
- deviceCode: z.ZodString;
4
- userCode: z.ZodString;
5
- verificationUri: z.ZodURL;
6
- verificationUriComplete: z.ZodURL;
7
- expiresAt: z.ZodString;
8
- interval: z.ZodNumber;
9
- }, z.core.$strip>;
10
- declare const pollSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
11
- status: z.ZodLiteral<"pending">;
12
- interval: z.ZodNumber;
13
- }, z.core.$strip>, z.ZodObject<{
14
- status: z.ZodLiteral<"slow_down">;
15
- interval: z.ZodNumber;
16
- }, z.core.$strip>, z.ZodObject<{
17
- status: z.ZodLiteral<"approved">;
18
- interval: z.ZodNumber;
19
- enrollmentToken: z.ZodString;
20
- }, z.core.$strip>, z.ZodObject<{
21
- status: z.ZodLiteral<"denied">;
22
- interval: z.ZodNumber;
23
- }, z.core.$strip>, z.ZodObject<{
24
- status: z.ZodLiteral<"expired">;
25
- interval: z.ZodNumber;
26
- }, z.core.$strip>, z.ZodObject<{
27
- status: z.ZodLiteral<"enrolled">;
28
- interval: z.ZodNumber;
29
- }, z.core.$strip>, z.ZodObject<{
30
- status: z.ZodLiteral<"retry_later">;
31
- }, z.core.$strip>], "status">;
32
- export type DeviceAuthorization = z.infer<typeof authorizationSchema>;
33
- export type DeviceAuthorizationPoll = z.infer<typeof pollSchema>;
34
- export interface CloudDeviceAuthorization {
35
- start(hubUrl: string, displayName: string): Promise<DeviceAuthorization>;
36
- poll(hubUrl: string, deviceCode: string, timeoutMilliseconds: number): Promise<DeviceAuthorizationPoll>;
37
- }
38
- export declare class CloudDeviceAuthorizationClient implements CloudDeviceAuthorization {
39
- private readonly startTimeoutMilliseconds;
40
- constructor(startTimeoutMilliseconds?: number);
41
- start(hubUrl: string, displayName: string): Promise<DeviceAuthorization>;
42
- poll(hubUrl: string, deviceCode: string, timeoutMilliseconds: number): Promise<DeviceAuthorizationPoll>;
43
- }
44
- export {};
45
- //# sourceMappingURL=cloud-device-authorization.d.ts.map
@@ -1,92 +0,0 @@
1
- import { z } from "zod";
2
- const START_TIMEOUT_MS = 15000;
3
- const activationUrlSchema = z.url({ protocol: /^https?$/u });
4
- const authorizationSchema = z.object({
5
- deviceCode: z.string().min(32),
6
- userCode: z.string().min(1),
7
- verificationUri: activationUrlSchema,
8
- verificationUriComplete: activationUrlSchema,
9
- expiresAt: z.string().datetime(),
10
- interval: z.number().int().min(5),
11
- });
12
- const pollSchema = z.discriminatedUnion("status", [
13
- z.object({ status: z.literal("pending"), interval: z.number().int().min(5) }),
14
- z.object({ status: z.literal("slow_down"), interval: z.number().int().min(5) }),
15
- z.object({
16
- status: z.literal("approved"),
17
- interval: z.number().int().min(5),
18
- enrollmentToken: z.string().min(32),
19
- }),
20
- z.object({ status: z.literal("denied"), interval: z.number().int().min(5) }),
21
- z.object({ status: z.literal("expired"), interval: z.number().int().min(5) }),
22
- z.object({ status: z.literal("enrolled"), interval: z.number().int().min(5) }),
23
- z.object({ status: z.literal("retry_later") }),
24
- ]);
25
- export class CloudDeviceAuthorizationClient {
26
- constructor(startTimeoutMilliseconds = START_TIMEOUT_MS) {
27
- this.startTimeoutMilliseconds = startTimeoutMilliseconds;
28
- }
29
- async start(hubUrl, displayName) {
30
- const signal = AbortSignal.timeout(this.startTimeoutMilliseconds);
31
- try {
32
- const response = await fetch(endpoint(hubUrl, "/api/device-authorizations/"), {
33
- method: "POST",
34
- headers: { "content-type": "application/json" },
35
- body: JSON.stringify({ displayName }),
36
- signal,
37
- });
38
- if (!response.ok)
39
- throw new Error(`Cloud registration failed (${response.status})`);
40
- return authorizationSchema.parse(await response.json());
41
- }
42
- catch (error) {
43
- if (signal.aborted) {
44
- throw new Error("Cloud registration start timed out", { cause: error });
45
- }
46
- throw error;
47
- }
48
- }
49
- async poll(hubUrl, deviceCode, timeoutMilliseconds) {
50
- const signal = AbortSignal.timeout(timeoutMilliseconds);
51
- let response;
52
- try {
53
- response = await fetch(endpoint(hubUrl, "/api/device-authorizations/poll"), {
54
- method: "POST",
55
- headers: { "content-type": "application/json" },
56
- body: JSON.stringify({ deviceCode }),
57
- signal,
58
- });
59
- }
60
- catch {
61
- return { status: "retry_later" };
62
- }
63
- if ([408, 425, 429].includes(response.status) || response.status >= 500) {
64
- return { status: "retry_later" };
65
- }
66
- if (!response.ok)
67
- throw new Error(`Cloud registration poll failed (${response.status})`);
68
- let body;
69
- try {
70
- body = await response.json();
71
- }
72
- catch (error) {
73
- if (signal.aborted || error instanceof TypeError)
74
- return { status: "retry_later" };
75
- throw error;
76
- }
77
- return pollSchema.parse(body);
78
- }
79
- }
80
- function endpoint(hubUrl, pathname) {
81
- const url = new URL(hubUrl);
82
- if (!["http:", "https:"].includes(url.protocol) ||
83
- url.username ||
84
- url.password ||
85
- url.search ||
86
- url.hash) {
87
- throw new Error("Hub URL must be an HTTP or HTTPS origin without credentials or a query");
88
- }
89
- url.pathname = `${url.pathname.replace(/\/$/u, "")}${pathname}`;
90
- return url.toString();
91
- }
92
- //# sourceMappingURL=cloud-device-authorization.js.map