@getpaseo/cli 0.3.0 → 0.4.0-beta.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 (93) hide show
  1. package/dist/cli.js +0 -5
  2. package/dist/commands/hub/authority.d.ts +17 -0
  3. package/dist/commands/hub/authority.js +18 -0
  4. package/dist/commands/hub/connect.d.ts +21 -0
  5. package/dist/commands/hub/connect.js +34 -0
  6. package/dist/commands/hub/credentials.d.ts +21 -0
  7. package/dist/commands/hub/credentials.js +143 -0
  8. package/dist/commands/hub/daemon-client.d.ts +27 -0
  9. package/dist/commands/hub/daemon-client.js +14 -0
  10. package/dist/commands/hub/deploy-bundle.d.ts +16 -0
  11. package/dist/commands/hub/deploy-bundle.js +248 -0
  12. package/dist/commands/hub/deploy.d.ts +25 -4
  13. package/dist/commands/hub/deploy.js +64 -48
  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/hub-client/index.d.ts +18 -0
  21. package/dist/commands/hub/hub-client/index.js +88 -0
  22. package/dist/commands/hub/hub-client/internal/contracts.d.ts +65 -0
  23. package/dist/commands/hub/hub-client/internal/contracts.js +47 -0
  24. package/dist/commands/hub/hub-client/internal/problem.d.ts +3 -0
  25. package/dist/commands/hub/hub-client/internal/problem.js +72 -0
  26. package/dist/commands/hub/hub-client/internal/transport.d.ts +15 -0
  27. package/dist/commands/hub/hub-client/internal/transport.js +30 -0
  28. package/dist/commands/hub/index.d.ts +15 -25
  29. package/dist/commands/hub/index.js +64 -74
  30. package/dist/commands/hub/{device-authorization.d.ts → login-flow.d.ts} +12 -15
  31. package/dist/commands/hub/login-flow.js +78 -0
  32. package/dist/commands/hub/login.d.ts +21 -0
  33. package/dist/commands/hub/login.js +34 -0
  34. package/dist/commands/hub/logout.d.ts +31 -0
  35. package/dist/commands/hub/logout.js +65 -0
  36. package/dist/commands/hub/origin.d.ts +2 -0
  37. package/dist/commands/hub/origin.js +27 -0
  38. package/dist/commands/hub/projects.d.ts +24 -0
  39. package/dist/commands/hub/projects.js +49 -0
  40. package/dist/commands/hub/reporter.d.ts +10 -0
  41. package/dist/commands/hub/reporter.js +11 -0
  42. package/dist/commands/hub/status-output.d.ts +13 -0
  43. package/dist/commands/hub/status-output.js +30 -0
  44. package/dist/commands/provider/diagnostic.d.ts +12 -0
  45. package/dist/commands/provider/diagnostic.js +31 -0
  46. package/dist/commands/provider/index.js +5 -0
  47. package/dist/commands/schedule/types.d.ts +1 -4
  48. package/dist/commands/workspace/index.js +10 -0
  49. package/dist/commands/workspace/rename.d.ts +22 -0
  50. package/dist/commands/workspace/rename.js +61 -0
  51. package/dist/output/types.d.ts +1 -1
  52. package/package.json +4 -4
  53. package/dist/commands/chat/create.d.ts +0 -9
  54. package/dist/commands/chat/create.js +0 -23
  55. package/dist/commands/chat/delete.d.ts +0 -6
  56. package/dist/commands/chat/delete.js +0 -20
  57. package/dist/commands/chat/index.d.ts +0 -3
  58. package/dist/commands/chat/index.js +0 -47
  59. package/dist/commands/chat/inspect.d.ts +0 -6
  60. package/dist/commands/chat/inspect.js +0 -20
  61. package/dist/commands/chat/ls.d.ts +0 -6
  62. package/dist/commands/chat/ls.js +0 -20
  63. package/dist/commands/chat/post.d.ts +0 -9
  64. package/dist/commands/chat/post.js +0 -28
  65. package/dist/commands/chat/read.d.ts +0 -11
  66. package/dist/commands/chat/read.js +0 -40
  67. package/dist/commands/chat/schema.d.ts +0 -36
  68. package/dist/commands/chat/schema.js +0 -81
  69. package/dist/commands/chat/shared.d.ts +0 -19
  70. package/dist/commands/chat/shared.js +0 -118
  71. package/dist/commands/chat/wait.d.ts +0 -9
  72. package/dist/commands/chat/wait.js +0 -45
  73. package/dist/commands/hub/client.d.ts +0 -19
  74. package/dist/commands/hub/client.js +0 -114
  75. package/dist/commands/hub/cloud-device-authorization.d.ts +0 -45
  76. package/dist/commands/hub/cloud-device-authorization.js +0 -92
  77. package/dist/commands/hub/deploy-input.d.ts +0 -17
  78. package/dist/commands/hub/deploy-input.js +0 -264
  79. package/dist/commands/hub/device-authorization.js +0 -87
  80. package/dist/commands/loop/index.d.ts +0 -3
  81. package/dist/commands/loop/index.js +0 -18
  82. package/dist/commands/loop/inspect.d.ts +0 -13
  83. package/dist/commands/loop/inspect.js +0 -100
  84. package/dist/commands/loop/logs.d.ts +0 -8
  85. package/dist/commands/loop/logs.js +0 -69
  86. package/dist/commands/loop/ls.d.ts +0 -18
  87. package/dist/commands/loop/ls.js +0 -62
  88. package/dist/commands/loop/run.d.ts +0 -30
  89. package/dist/commands/loop/run.js +0 -162
  90. package/dist/commands/loop/stop.d.ts +0 -15
  91. package/dist/commands/loop/stop.js +0 -56
  92. package/dist/commands/loop/types.d.ts +0 -138
  93. package/dist/commands/loop/types.js +0 -2
@@ -1,8 +1,11 @@
1
1
  import { withOutput } from "../../output/index.js";
2
2
  import { addJsonOption } from "../../utils/command-options.js";
3
- import { installHubConfiguration } from "./client.js";
4
- import { resolveHubDeployInput } from "./deploy-input.js";
5
- import { HubDeployError } from "./error.js";
3
+ import { resolveHubCredential, resolveHubOrigin } from "./authority.js";
4
+ import { HubHttpClient, } from "./hub-client/index.js";
5
+ import { PrivateHubCredentialStore } from "./credentials.js";
6
+ import { discoverHubBundle } from "./deploy-bundle.js";
7
+ import { processHubReporter, reportHubProgress } from "./reporter.js";
8
+ import { addHubResolutionHelp } from "./help.js";
6
9
  const resultSchema = {
7
10
  idField: "versionId",
8
11
  columns: [
@@ -10,62 +13,75 @@ const resultSchema = {
10
13
  { header: "VERSION", field: "version" },
11
14
  { header: "VERSION ID", field: "versionId" },
12
15
  { header: "ACTIVE", field: "active" },
16
+ { header: "WORKFLOWS", field: "workflows" },
17
+ { header: "HUB", field: "origin" },
13
18
  ],
14
19
  };
15
- export async function runHubDeploy(options, environment = { cwd: process.cwd(), env: process.env }) {
16
- const origin = options.hub ?? environment.env.PASEO_HUB_URL;
17
- const apiKey = options.apiKey ?? environment.env.PASEO_HUB_API_KEY;
18
- if (!origin) {
19
- throw new HubDeployError("HUB_ORIGIN_REQUIRED", "Hub origin is required. Pass --hub <origin> or set PASEO_HUB_URL.");
20
- }
21
- if (!apiKey) {
22
- throw new HubDeployError("HUB_API_KEY_REQUIRED", "Hub API key is required. Pass --api-key <secret> or set PASEO_HUB_API_KEY.");
23
- }
24
- const normalizedOrigin = parseHubOrigin(origin);
25
- const deployInput = await resolveHubDeployInput({
20
+ const validationSchema = {
21
+ idField: "projectSlug",
22
+ columns: [
23
+ { header: "PROJECT", field: "projectSlug" },
24
+ { header: "VALID", field: "valid" },
25
+ { header: "WORKFLOWS", field: "workflows" },
26
+ { header: "HUB", field: "origin" },
27
+ ],
28
+ };
29
+ export async function runHubDeploy(options, environment = {
30
+ cwd: process.cwd(),
31
+ env: process.env,
32
+ credentials: new PrivateHubCredentialStore(),
33
+ hub: new HubHttpClient(),
34
+ }) {
35
+ const credentials = environment.credentials ?? new PrivateHubCredentialStore(environment.env);
36
+ const resolution = {
37
+ options: { origin: options.hub, apiKey: options.apiKey },
38
+ env: environment.env,
39
+ credentials,
40
+ };
41
+ const origin = resolveHubOrigin(resolution);
42
+ const deployInput = await discoverHubBundle({
26
43
  cwd: environment.cwd,
27
- ...(options.file === undefined ? {} : { file: options.file }),
28
44
  ...(options.project === undefined ? {} : { project: options.project }),
29
45
  });
30
- const deployed = await installHubConfiguration({
31
- origin: normalizedOrigin,
32
- apiKey,
46
+ const action = options.dryRun === true ? "Validating" : "Deploying";
47
+ reportHubProgress(environment.reporter ?? processHubReporter, options, `${action} ${deployInput.projectSlug} ${options.dryRun === true ? "against" : "to"} ${origin}`);
48
+ const credential = resolveHubCredential({ ...resolution, origin });
49
+ const request = {
50
+ origin,
51
+ apiKey: credential,
33
52
  ...deployInput,
34
- });
35
- return { type: "single", data: deployed, schema: resultSchema };
53
+ };
54
+ if (options.dryRun === true) {
55
+ const validated = await (environment.hub ?? new HubHttpClient()).validateConfiguration(request);
56
+ return {
57
+ type: "single",
58
+ data: { ...validated, workflows: deployInput.workflowCount, origin },
59
+ schema: validationSchema,
60
+ };
61
+ }
62
+ const deployed = await (environment.hub ?? new HubHttpClient()).installConfiguration(request);
63
+ return {
64
+ type: "single",
65
+ data: { ...deployed, workflows: deployInput.workflowCount, origin },
66
+ schema: resultSchema,
67
+ };
36
68
  }
37
- export function addHubDeployCommand(hub) {
38
- addJsonOption(hub
69
+ export function addHubDeployCommand(hub, dependencies) {
70
+ addJsonOption(addHubResolutionHelp(hub
39
71
  .command("deploy")
40
- .description("Install and activate a Hub configuration")
41
- .argument("[file]", "Hub configuration YAML", ".paseo/hub.yml")
72
+ .description("Discover, validate, and activate the canonical .paseo Hub bundle")
42
73
  .option("-p, --project <slug>", "Target project slug")
43
74
  .option("--hub <origin>", "Paseo Hub origin")
44
- .option("--api-key <secret>", "Organization API key")).action(withOutput(async (...args) => {
45
- const file = args[0];
75
+ .option("--api-key <secret>", "Organization API key")
76
+ .option("--dry-run", "Validate without installing or activating"))).action(withOutput(async (...args) => {
46
77
  const options = args.at(-2);
47
- return runHubDeploy({ ...options, file });
78
+ return runHubDeploy(options, {
79
+ cwd: dependencies.cwd(),
80
+ env: dependencies.env,
81
+ credentials: dependencies.credentials,
82
+ hub: dependencies.hub,
83
+ reporter: dependencies.reporter,
84
+ });
48
85
  }));
49
86
  }
50
- function parseHubOrigin(value) {
51
- let url;
52
- try {
53
- url = new URL(value);
54
- }
55
- catch {
56
- throw invalidHubOrigin();
57
- }
58
- if (!["http:", "https:"].includes(url.protocol) ||
59
- url.username ||
60
- url.password ||
61
- url.pathname !== "/" ||
62
- url.search ||
63
- url.hash) {
64
- throw invalidHubOrigin();
65
- }
66
- return url.origin;
67
- }
68
- function invalidHubOrigin() {
69
- return new HubDeployError("HUB_INVALID_ORIGIN", "Hub URL must be an HTTP or HTTPS origin without credentials, path, query, or hash.");
70
- }
71
87
  //# sourceMappingURL=deploy.js.map
@@ -0,0 +1,16 @@
1
+ import type { Command } from "commander";
2
+ import type { HubDaemonConnection } from "./daemon-client.js";
3
+ import { type HubReporter } from "./reporter.js";
4
+ interface HubDisconnectOptions {
5
+ force?: boolean;
6
+ host?: string;
7
+ json?: boolean;
8
+ }
9
+ interface HubDisconnectDependencies {
10
+ daemon: HubDaemonConnection;
11
+ reporter: HubReporter;
12
+ }
13
+ export declare function runHubDisconnect(options: HubDisconnectOptions, dependencies: HubDisconnectDependencies): Promise<import("../../output/types.js").ListResult<import("./status-output.js").HubRow>>;
14
+ export declare function addHubDisconnectCommand(parent: Command, dependencies: HubDisconnectDependencies): void;
15
+ export {};
16
+ //# sourceMappingURL=disconnect.d.ts.map
@@ -0,0 +1,24 @@
1
+ import { withOutput } from "../../output/index.js";
2
+ import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
3
+ import { withHubDaemon } from "./daemon-client.js";
4
+ import { reportHubProgress } from "./reporter.js";
5
+ import { hubStatusResult } from "./status-output.js";
6
+ export function runHubDisconnect(options, dependencies) {
7
+ return withHubDaemon(dependencies.daemon, options.host, async (client) => {
8
+ const current = (await client.getHubStatus()).status;
9
+ if (current.hubOrigin !== null) {
10
+ reportHubProgress(dependencies.reporter, options, `Disconnecting this daemon from ${current.hubOrigin}`);
11
+ }
12
+ const response = await client.disconnectHub(options.force ?? false);
13
+ return hubStatusResult(response.status, response.warning, current.hubOrigin);
14
+ });
15
+ }
16
+ export function addHubDisconnectCommand(parent, dependencies) {
17
+ addJsonAndDaemonHostOptions(parent
18
+ .command("disconnect")
19
+ .option("--force", "Remove local authority even if the Hub is offline")).action(withOutput(async (...args) => {
20
+ const options = args.at(-2);
21
+ return runHubDisconnect(options, dependencies);
22
+ }));
23
+ }
24
+ //# sourceMappingURL=disconnect.js.map
@@ -1,4 +1,4 @@
1
- export declare class HubDeployError extends Error {
1
+ export declare class HubCommandError extends Error {
2
2
  readonly code: string;
3
3
  readonly details?: string | undefined;
4
4
  constructor(code: string, message: string, details?: string | undefined);
@@ -1,9 +1,9 @@
1
- export class HubDeployError extends Error {
1
+ export class HubCommandError extends Error {
2
2
  constructor(code, message, details) {
3
3
  super(message);
4
4
  this.code = code;
5
5
  this.details = details;
6
- this.name = "HubDeployError";
6
+ this.name = "HubCommandError";
7
7
  }
8
8
  }
9
9
  //# sourceMappingURL=error.js.map
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function addHubResolutionHelp(command: Command): Command;
3
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1,5 @@
1
+ const resolutionHelp = "\nHub origin precedence: command origin/--hub, PASEO_HUB_URL, active stored login, then https://hub.paseo.sh.\nCredential precedence: --api-key, PASEO_HUB_API_KEY, then a stored login for the exact resolved origin.\n";
2
+ export function addHubResolutionHelp(command) {
3
+ return command.addHelpText("after", resolutionHelp);
4
+ }
5
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1,18 @@
1
+ import type { HubBundleFile } from "../deploy-bundle.js";
2
+ import { type CliAuthorization, type CliAuthorizationPoll, type HubInstallResult, type HubProject, type HubValidationResult } from "./internal/contracts.js";
3
+ export type { CliAuthorization, CliAuthorizationPoll, HubInstallResult, HubProject, HubValidationResult, } from "./internal/contracts.js";
4
+ interface HubConfigurationInput {
5
+ origin: string;
6
+ apiKey: string;
7
+ projectSlug: string;
8
+ files: readonly HubBundleFile[];
9
+ }
10
+ export declare class HubHttpClient {
11
+ startCliAuthorization(origin: string): Promise<CliAuthorization>;
12
+ pollCliAuthorization(origin: string, deviceCode: string, timeoutMilliseconds: number): Promise<CliAuthorizationPoll>;
13
+ listProjects(origin: string, apiKey: string): Promise<HubProject[]>;
14
+ installConfiguration(input: HubConfigurationInput): Promise<HubInstallResult>;
15
+ validateConfiguration(input: HubConfigurationInput): Promise<HubValidationResult>;
16
+ issueEnrollmentToken(origin: string, apiKey: string): Promise<string>;
17
+ }
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,88 @@
1
+ import { HubCommandError } from "../error.js";
2
+ import { authorizationPollSchema, authorizationSchema, enrollmentTokenSchema, installResponseSchema, projectsResponseSchema, validationResponseSchema, } from "./internal/contracts.js";
3
+ import { requestHub } from "./internal/transport.js";
4
+ export class HubHttpClient {
5
+ startCliAuthorization(origin) {
6
+ return requestHub({
7
+ origin,
8
+ path: "/api/v1/cli-authorizations",
9
+ method: "POST",
10
+ body: {},
11
+ successStatus: 201,
12
+ schema: authorizationSchema,
13
+ failureMessage: "Hub CLI login could not be started",
14
+ });
15
+ }
16
+ async pollCliAuthorization(origin, deviceCode, timeoutMilliseconds) {
17
+ try {
18
+ return await requestHub({
19
+ origin,
20
+ path: "/api/v1/cli-authorizations/poll",
21
+ method: "POST",
22
+ body: { deviceCode },
23
+ successStatus: 200,
24
+ schema: authorizationPollSchema,
25
+ timeoutMilliseconds,
26
+ failureMessage: "Hub CLI login polling failed",
27
+ });
28
+ }
29
+ catch (error) {
30
+ if (error instanceof HubCommandError && error.code === "HUB_NETWORK_ERROR") {
31
+ return { status: "retry_later" };
32
+ }
33
+ throw error;
34
+ }
35
+ }
36
+ async listProjects(origin, apiKey) {
37
+ const response = await requestHub({
38
+ origin,
39
+ path: "/api/v1/projects",
40
+ method: "GET",
41
+ apiKey,
42
+ successStatus: 200,
43
+ schema: projectsResponseSchema,
44
+ failureMessage: "Hub project listing failed",
45
+ });
46
+ return response.projects;
47
+ }
48
+ installConfiguration(input) {
49
+ return requestHub({
50
+ origin: input.origin,
51
+ path: "/api/v1/configurations/install",
52
+ method: "POST",
53
+ apiKey: input.apiKey,
54
+ body: configurationBody(input),
55
+ successStatus: 201,
56
+ schema: installResponseSchema,
57
+ failureMessage: "Hub deployment failed",
58
+ });
59
+ }
60
+ validateConfiguration(input) {
61
+ return requestHub({
62
+ origin: input.origin,
63
+ path: "/api/v1/configurations/validate",
64
+ method: "POST",
65
+ apiKey: input.apiKey,
66
+ body: configurationBody(input),
67
+ successStatus: 200,
68
+ schema: validationResponseSchema,
69
+ failureMessage: "Hub configuration validation failed",
70
+ });
71
+ }
72
+ async issueEnrollmentToken(origin, apiKey) {
73
+ const response = await requestHub({
74
+ origin,
75
+ path: "/api/v1/daemons/enrollment-tokens",
76
+ method: "POST",
77
+ apiKey,
78
+ successStatus: 201,
79
+ schema: enrollmentTokenSchema,
80
+ failureMessage: "Hub daemon enrollment authorization failed",
81
+ });
82
+ return response.token;
83
+ }
84
+ }
85
+ function configurationBody(input) {
86
+ return { projectSlug: input.projectSlug, files: input.files };
87
+ }
88
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,65 @@
1
+ import { z } from "zod";
2
+ export 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.$strict>;
10
+ export declare const authorizationPollSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
11
+ status: z.ZodLiteral<"pending">;
12
+ interval: z.ZodNumber;
13
+ }, z.core.$strict>, z.ZodObject<{
14
+ status: z.ZodLiteral<"slow_down">;
15
+ interval: z.ZodNumber;
16
+ }, z.core.$strict>, z.ZodObject<{
17
+ status: z.ZodLiteral<"authorized">;
18
+ interval: z.ZodNumber;
19
+ credential: z.ZodString;
20
+ organizationId: z.ZodString;
21
+ }, z.core.$strict>, z.ZodObject<{
22
+ status: z.ZodLiteral<"denied">;
23
+ interval: z.ZodNumber;
24
+ }, z.core.$strict>, z.ZodObject<{
25
+ status: z.ZodLiteral<"expired">;
26
+ interval: z.ZodNumber;
27
+ }, z.core.$strict>, z.ZodObject<{
28
+ status: z.ZodLiteral<"disclosed">;
29
+ interval: z.ZodNumber;
30
+ }, z.core.$strict>, z.ZodObject<{
31
+ status: z.ZodLiteral<"retry_later">;
32
+ }, z.core.$strict>], "status">;
33
+ declare const projectSchema: z.ZodObject<{
34
+ id: z.ZodString;
35
+ slug: z.ZodString;
36
+ name: z.ZodString;
37
+ }, z.core.$strict>;
38
+ export declare const projectsResponseSchema: z.ZodObject<{
39
+ projects: z.ZodArray<z.ZodObject<{
40
+ id: z.ZodString;
41
+ slug: z.ZodString;
42
+ name: z.ZodString;
43
+ }, z.core.$strict>>;
44
+ }, z.core.$strict>;
45
+ export declare const installResponseSchema: z.ZodObject<{
46
+ projectSlug: z.ZodString;
47
+ version: z.ZodNumber;
48
+ versionId: z.ZodString;
49
+ active: z.ZodLiteral<true>;
50
+ }, z.core.$strict>;
51
+ export declare const validationResponseSchema: z.ZodObject<{
52
+ projectSlug: z.ZodString;
53
+ valid: z.ZodLiteral<true>;
54
+ }, z.core.$strict>;
55
+ export declare const enrollmentTokenSchema: z.ZodObject<{
56
+ token: z.ZodString;
57
+ expiresAt: z.ZodString;
58
+ }, z.core.$strict>;
59
+ export type CliAuthorization = z.infer<typeof authorizationSchema>;
60
+ export type CliAuthorizationPoll = z.infer<typeof authorizationPollSchema>;
61
+ export type HubProject = z.infer<typeof projectSchema>;
62
+ export type HubInstallResult = z.infer<typeof installResponseSchema>;
63
+ export type HubValidationResult = z.infer<typeof validationResponseSchema>;
64
+ export {};
65
+ //# sourceMappingURL=contracts.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { z } from "zod";
2
+ const activationUrlSchema = z.url({ protocol: /^https?$/u });
3
+ export const authorizationSchema = z
4
+ .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(1),
11
+ })
12
+ .strict();
13
+ export const authorizationPollSchema = z.discriminatedUnion("status", [
14
+ z.object({ status: z.literal("pending"), interval: z.number().int().min(1) }).strict(),
15
+ z.object({ status: z.literal("slow_down"), interval: z.number().int().min(1) }).strict(),
16
+ z
17
+ .object({
18
+ status: z.literal("authorized"),
19
+ interval: z.number().int().min(1),
20
+ credential: z.string().min(32),
21
+ organizationId: z.string().min(1),
22
+ })
23
+ .strict(),
24
+ z.object({ status: z.literal("denied"), interval: z.number().int().min(1) }).strict(),
25
+ z.object({ status: z.literal("expired"), interval: z.number().int().min(1) }).strict(),
26
+ z.object({ status: z.literal("disclosed"), interval: z.number().int().min(1) }).strict(),
27
+ z.object({ status: z.literal("retry_later") }).strict(),
28
+ ]);
29
+ const projectSchema = z
30
+ .object({ id: z.string().uuid(), slug: z.string().min(1), name: z.string().min(1) })
31
+ .strict();
32
+ export const projectsResponseSchema = z.object({ projects: z.array(projectSchema) }).strict();
33
+ export const installResponseSchema = z
34
+ .object({
35
+ projectSlug: z.string().min(1),
36
+ version: z.number().int().positive(),
37
+ versionId: z.string().uuid(),
38
+ active: z.literal(true),
39
+ })
40
+ .strict();
41
+ export const validationResponseSchema = z
42
+ .object({ projectSlug: z.string().min(1), valid: z.literal(true) })
43
+ .strict();
44
+ export const enrollmentTokenSchema = z
45
+ .object({ token: z.string().min(32), expiresAt: z.string().datetime() })
46
+ .strict();
47
+ //# sourceMappingURL=contracts.js.map
@@ -0,0 +1,3 @@
1
+ import { HubCommandError } from "../../error.js";
2
+ export declare function hubRequestFailure(response: Response, failureMessage: string, apiKey: string | undefined): Promise<HubCommandError>;
3
+ //# sourceMappingURL=problem.d.ts.map
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ import { HubCommandError } from "../../error.js";
3
+ const issuePathSchema = z.union([z.string(), z.array(z.union([z.string(), z.number()]))]);
4
+ const fieldIssueSchema = z.object({
5
+ field: z.string().optional(),
6
+ path: issuePathSchema.optional(),
7
+ message: z.string(),
8
+ });
9
+ const problemSchema = z.object({
10
+ type: z.string().optional(),
11
+ title: z.string().optional(),
12
+ status: z.number().int().optional(),
13
+ detail: z.string().optional(),
14
+ instance: z.string().optional(),
15
+ errors: z
16
+ .union([z.array(fieldIssueSchema), z.record(z.string(), z.array(z.string()))])
17
+ .optional(),
18
+ issues: z.array(fieldIssueSchema).optional(),
19
+ });
20
+ export async function hubRequestFailure(response, failureMessage, apiKey) {
21
+ const contentType = response.headers.get("content-type") ?? "";
22
+ if (!contentType.toLowerCase().includes("application/problem+json")) {
23
+ return new HubCommandError("HUB_REQUEST_FAILED", `${failureMessage} with HTTP ${response.status}.`);
24
+ }
25
+ let body;
26
+ try {
27
+ body = await response.json();
28
+ }
29
+ catch {
30
+ return new HubCommandError("HUB_INVALID_RESPONSE", `Hub returned malformed problem details for HTTP ${response.status}.`);
31
+ }
32
+ const parsed = problemSchema.safeParse(body);
33
+ if (!parsed.success ||
34
+ (parsed.data.status !== undefined && parsed.data.status !== response.status)) {
35
+ return new HubCommandError("HUB_INVALID_RESPONSE", `Hub returned nonconforming problem details for HTTP ${response.status}.`);
36
+ }
37
+ const title = parsed.data.title ?? `${failureMessage} with HTTP ${response.status}`;
38
+ const message = parsed.data.detail === undefined ? title : `${title}: ${parsed.data.detail}`;
39
+ const details = formatFieldIssues(parsed.data.errors, parsed.data.issues);
40
+ const code = response.status === 422 ? "HUB_VALIDATION_FAILED" : "HUB_REQUEST_FAILED";
41
+ return new HubCommandError(code, redactSecret(message, apiKey), details === undefined ? undefined : redactSecret(details, apiKey));
42
+ }
43
+ function formatFieldIssues(errors, issues) {
44
+ const fieldIssues = Array.isArray(errors) ? errors : issues;
45
+ if (fieldIssues !== undefined) {
46
+ const lines = fieldIssues.map((issue) => {
47
+ const field = issue.field ?? formatIssuePath(issue.path);
48
+ return field === undefined ? issue.message : `${field}: ${issue.message}`;
49
+ });
50
+ return lines.length === 0 ? undefined : lines.join("\n");
51
+ }
52
+ if (errors === undefined)
53
+ return undefined;
54
+ const lines = Object.entries(errors).flatMap(([field, messages]) => messages.map((message) => `${field}: ${message}`));
55
+ return lines.length === 0 ? undefined : lines.join("\n");
56
+ }
57
+ function formatIssuePath(path) {
58
+ if (path === undefined || typeof path === "string")
59
+ return path;
60
+ let formatted = "";
61
+ for (const segment of path) {
62
+ if (typeof segment === "number")
63
+ formatted += `[${segment}]`;
64
+ else
65
+ formatted += formatted.length === 0 ? segment : `.${segment}`;
66
+ }
67
+ return formatted || undefined;
68
+ }
69
+ function redactSecret(value, secret) {
70
+ return secret === undefined ? value : value.split(secret).join("[redacted]");
71
+ }
72
+ //# sourceMappingURL=problem.js.map
@@ -0,0 +1,15 @@
1
+ import type { z } from "zod";
2
+ interface HubRequest<T> {
3
+ origin: string;
4
+ path: string;
5
+ method: "GET" | "POST";
6
+ apiKey?: string;
7
+ body?: unknown;
8
+ successStatus: number;
9
+ schema: z.ZodType<T>;
10
+ timeoutMilliseconds?: number;
11
+ failureMessage: string;
12
+ }
13
+ export declare function requestHub<T>(input: HubRequest<T>): Promise<T>;
14
+ export {};
15
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { HubCommandError } from "../../error.js";
2
+ import { hubRequestFailure } from "./problem.js";
3
+ export async function requestHub(input) {
4
+ const signal = AbortSignal.timeout(input.timeoutMilliseconds ?? 15000);
5
+ let response;
6
+ try {
7
+ response = await fetch(`${input.origin}${input.path}`, {
8
+ method: input.method,
9
+ headers: {
10
+ ...(input.apiKey === undefined ? {} : { authorization: `Bearer ${input.apiKey}` }),
11
+ ...(input.body === undefined ? {} : { "content-type": "application/json" }),
12
+ },
13
+ ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }),
14
+ signal,
15
+ });
16
+ }
17
+ catch {
18
+ throw new HubCommandError("HUB_NETWORK_ERROR", `Could not reach Paseo Hub at ${input.origin}. Check the Hub URL and network connection.`);
19
+ }
20
+ if (response.status !== input.successStatus) {
21
+ throw await hubRequestFailure(response, input.failureMessage, input.apiKey);
22
+ }
23
+ try {
24
+ return input.schema.parse(await response.json());
25
+ }
26
+ catch {
27
+ throw new HubCommandError("HUB_INVALID_RESPONSE", "Hub returned a malformed response.");
28
+ }
29
+ }
30
+ //# sourceMappingURL=transport.js.map
@@ -1,30 +1,20 @@
1
1
  import { Command } from "commander";
2
- interface HubCommandClient {
3
- connectHub(url: string, token: string): Promise<{
4
- status: HubStatus;
5
- }>;
6
- getHubStatus(): Promise<{
7
- status: HubStatus;
8
- }>;
9
- disconnectHub(force: boolean): Promise<{
10
- status: HubStatus;
11
- warning?: string;
12
- }>;
13
- close(): Promise<void>;
14
- }
15
- interface HubStatus {
16
- state: string;
17
- daemonId: string | null;
18
- hubOrigin: string | null;
19
- scopes: string[];
20
- connectedAt: string | null;
21
- lastError: string | null;
22
- }
2
+ import { HubHttpClient } from "./hub-client/index.js";
3
+ import { type HubCredentialStore } from "./credentials.js";
4
+ import { type HubDaemonConnection } from "./daemon-client.js";
5
+ import { type CliLoginFlow } from "./login-flow.js";
6
+ import { type HubReporter } from "./reporter.js";
23
7
  interface HubCommandEnvironment {
24
- connect(host: string | undefined): Promise<HubCommandClient>;
25
- authorize(url: string, displayName: string): Promise<string>;
26
- displayName(): string;
8
+ env: Readonly<Record<string, string | undefined>>;
9
+ credentials: HubCredentialStore;
10
+ hub: HubHttpClient;
11
+ login: Pick<CliLoginFlow, "authorize">;
12
+ daemon: HubDaemonConnection;
13
+ isInteractive(): boolean;
14
+ confirmDisconnect(origin: string): Promise<boolean>;
15
+ reporter: HubReporter;
16
+ cwd(): string;
27
17
  }
28
- export declare function createHubCommand(environment?: HubCommandEnvironment): Command;
18
+ export declare function createHubCommand(overrides?: Partial<HubCommandEnvironment>): Command;
29
19
  export {};
30
20
  //# sourceMappingURL=index.d.ts.map