Skip to content

Commit 0242f44

Browse files
committed
Fix CLI device approve origin
1 parent 9d5d64f commit 0242f44

14 files changed

Lines changed: 605 additions & 218 deletions

File tree

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,24 @@
22

33
Bun + Turborepo monorepo.
44

5+
Landing page: [claws.supply](https://claws.supply)
6+
57
## Workspace Layout
68

79
- `apps/web`: Next.js App Router application (`@claws-supply/web`)
8-
- `packages/cli`: claws.supply creator CLI (`@claws-supply/cli`)
10+
- `packages/cli`: claws.supply creator CLI (`claws-supply`)
11+
12+
## CLI Usage
13+
14+
Run without installing globally:
15+
16+
```bash
17+
npx claws-supply auth
18+
npx claws-supply build
19+
npx claws-supply publish
20+
```
21+
22+
`build` uses your current folder by default. Use `--source <path>` only when the target project is in a different folder.
923

1024
## Requirements
1125

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { jsonError, jsonSuccess } from "@/lib/api/response";
22
import { enforceCliDeviceDecisionRateLimit } from "@/lib/api/rate-limit";
3-
import { handleRouteError, requireSessionOrThrow } from "@/lib/api/route-helpers";
3+
import { requireSessionOrThrow } from "@/lib/api/route-helpers";
44
import { parseJsonBodyWithSchema } from "@/lib/api/validation";
5-
import { postToDeviceAuthEndpoint, parseDeviceAuthError } from "@/lib/cli/device-auth";
5+
import { auth } from "@/lib/auth-server";
6+
import {
7+
parseDeviceAuthApiError,
8+
resolveDeviceAuthApiErrorStatus,
9+
} from "@/lib/cli/device-auth";
610
import { cliDeviceDecisionSchema } from "@/lib/cli/schemas";
711

812
export async function POST(request: Request) {
@@ -17,30 +21,18 @@ export async function POST(request: Request) {
1721
}
1822

1923
const input = await parseJsonBodyWithSchema(request, cliDeviceDecisionSchema);
20-
const response = await postToDeviceAuthEndpoint({
21-
request,
22-
path: "/device/approve",
24+
const response = await auth.api.deviceApprove({
25+
headers: request.headers,
2326
body: {
2427
userCode: input.userCode,
2528
},
2629
});
2730

28-
if (response.status >= 400) {
29-
return jsonError(
30-
parseDeviceAuthError(response.payload, "Unable to approve device code."),
31-
{
32-
code: "CLI_DEVICE_AUTH_APPROVE_ERROR",
33-
status: response.status,
34-
},
35-
);
36-
}
37-
38-
return jsonSuccess(response.payload);
31+
return jsonSuccess(response);
3932
} catch (error) {
40-
return handleRouteError(error, {
41-
message: "Unable to approve device code.",
33+
return jsonError(parseDeviceAuthApiError(error, "Unable to approve device code."), {
4234
code: "CLI_DEVICE_AUTH_APPROVE_ERROR",
43-
status: 400,
35+
status: resolveDeviceAuthApiErrorStatus(error, 400),
4436
});
4537
}
4638
}
Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { jsonError, jsonSuccess } from "@/lib/api/response";
22
import { enforceCliDeviceDecisionRateLimit } from "@/lib/api/rate-limit";
3-
import { handleRouteError, requireSessionOrThrow } from "@/lib/api/route-helpers";
3+
import { requireSessionOrThrow } from "@/lib/api/route-helpers";
44
import { parseJsonBodyWithSchema } from "@/lib/api/validation";
5-
import { postToDeviceAuthEndpoint, parseDeviceAuthError } from "@/lib/cli/device-auth";
5+
import { auth } from "@/lib/auth-server";
6+
import {
7+
parseDeviceAuthApiError,
8+
resolveDeviceAuthApiErrorStatus,
9+
} from "@/lib/cli/device-auth";
610
import { cliDeviceDecisionSchema } from "@/lib/cli/schemas";
711

812
export async function POST(request: Request) {
@@ -17,27 +21,18 @@ export async function POST(request: Request) {
1721
}
1822

1923
const input = await parseJsonBodyWithSchema(request, cliDeviceDecisionSchema);
20-
const response = await postToDeviceAuthEndpoint({
21-
request,
22-
path: "/device/deny",
24+
const response = await auth.api.deviceDeny({
25+
headers: request.headers,
2326
body: {
2427
userCode: input.userCode,
2528
},
2629
});
2730

28-
if (response.status >= 400) {
29-
return jsonError(parseDeviceAuthError(response.payload, "Unable to deny device code."), {
30-
code: "CLI_DEVICE_AUTH_DENY_ERROR",
31-
status: response.status,
32-
});
33-
}
34-
35-
return jsonSuccess(response.payload);
31+
return jsonSuccess(response);
3632
} catch (error) {
37-
return handleRouteError(error, {
38-
message: "Unable to deny device code.",
33+
return jsonError(parseDeviceAuthApiError(error, "Unable to deny device code."), {
3934
code: "CLI_DEVICE_AUTH_DENY_ERROR",
40-
status: 400,
35+
status: resolveDeviceAuthApiErrorStatus(error, 400),
4136
});
4237
}
4338
}

apps/web/components/docs/docs-right-sidebar.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SidebarAdStack } from "@/components/ads/sidebar-ad-stack";
1+
// import { SidebarAdStack } from "@/components/ads/sidebar-ad-stack";
22
import { Button } from "@/components/ui/button";
33
import Link from "next/link";
44

@@ -50,7 +50,8 @@ export async function DocsRightSidebar() {
5050
</div>
5151
</section>
5252

53-
<SidebarAdStack />
53+
{/* Temporarily hidden until ad release is ready. */}
54+
{/* <SidebarAdStack /> */}
5455
</div>
5556
</div>
5657
);

apps/web/components/docs/docs-section-menu.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ export function DocsSectionMenu() {
3737
created by anthony riera{" "}
3838
<Link
3939
className="underline underline-offset-2"
40-
href="https://x.com/_anthonyriera"
40+
href="https://x.com/anthonyriera"
4141
rel="noreferrer"
4242
target="_blank"
4343
>
44-
@_anthonyriera on X
44+
@anthonyriera on X
4545
</Link>
4646
</p>
4747
<p>
48-
team:{" "}
48+
and{" "}
4949
<Link
5050
className="underline underline-offset-2"
5151
href="https://cossistant.com"

apps/web/components/extra-sidebar.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import Link from "next/link";
22
import { MemberAvatar } from "@/components/members/member-avatar";
3-
import { SidebarAdStack } from "@/components/ads/sidebar-ad-stack";
3+
// import { SidebarAdStack } from "@/components/ads/sidebar-ad-stack";
44
import { getCommunitySidebarSnapshotCached } from "@/lib/members/read-service";
55
import { memberPath } from "@/lib/routes";
66

7-
const SIDEBAR_SLOT_COUNT = 5;
7+
// const SIDEBAR_SLOT_COUNT = 5;
88
const COMMUNITY_MEMBER_LIMIT = 10;
99

1010
export async function ExtraSidebar() {
@@ -37,7 +37,8 @@ export async function ExtraSidebar() {
3737
))}
3838
</div>
3939
</section>
40-
<SidebarAdStack slotCount={SIDEBAR_SLOT_COUNT} />
40+
{/* Temporarily hidden until ad release is ready. */}
41+
{/* <SidebarAdStack slotCount={SIDEBAR_SLOT_COUNT} /> */}
4142
</div>
4243
);
4344
}

apps/web/components/navbar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ export function Navbar({ user }: NavbarProps) {
7979
>
8080
MEMBERS
8181
</Link>
82+
{/* Temporarily hidden until ad release is ready.
8283
<Link
8384
className="text-xs tracking-wider hover:opacity-80 transition-opacity"
8485
href="/advertise"
8586
>
8687
ADVERTISE
8788
</Link>
89+
*/}
8890
<Link
8991
className="text-xs tracking-wider hover:opacity-80 transition-opacity"
9092
href="/docs"

apps/web/lib/cli/device-auth.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ type DeviceAuthPostResult = {
55
payload: unknown;
66
};
77

8+
type DeviceAuthErrorPayload = {
9+
error?: unknown;
10+
error_description?: unknown;
11+
message?: unknown;
12+
};
13+
14+
type DeviceAuthApiError = {
15+
body?: unknown;
16+
message?: unknown;
17+
status?: unknown;
18+
statusCode?: unknown;
19+
};
20+
821
export async function postToDeviceAuthEndpoint(options: {
922
request: Request;
1023
path: "/device/code" | "/device/token" | "/device/approve" | "/device/deny";
@@ -48,11 +61,7 @@ export function parseDeviceAuthError(payload: unknown, fallbackMessage: string):
4861
return fallbackMessage;
4962
}
5063

51-
const body = payload as {
52-
error?: unknown;
53-
error_description?: unknown;
54-
message?: unknown;
55-
};
64+
const body = payload as DeviceAuthErrorPayload;
5665

5766
if (typeof body.error_description === "string" && body.error_description.length > 0) {
5867
return body.error_description;
@@ -68,3 +77,42 @@ export function parseDeviceAuthError(payload: unknown, fallbackMessage: string):
6877

6978
return fallbackMessage;
7079
}
80+
81+
export function parseDeviceAuthApiError(error: unknown, fallbackMessage: string): string {
82+
if (!error || typeof error !== "object") {
83+
return fallbackMessage;
84+
}
85+
86+
const candidate = error as DeviceAuthApiError;
87+
const messageFromBody = parseDeviceAuthError(candidate.body, "");
88+
if (messageFromBody.length > 0) {
89+
return messageFromBody;
90+
}
91+
92+
if (typeof candidate.message === "string" && candidate.message.trim().length > 0) {
93+
return candidate.message;
94+
}
95+
96+
return fallbackMessage;
97+
}
98+
99+
export function resolveDeviceAuthApiErrorStatus(
100+
error: unknown,
101+
fallbackStatus: number,
102+
): number {
103+
if (!error || typeof error !== "object") {
104+
return fallbackStatus;
105+
}
106+
107+
const candidate = error as DeviceAuthApiError;
108+
109+
if (typeof candidate.statusCode === "number" && Number.isFinite(candidate.statusCode)) {
110+
return candidate.statusCode;
111+
}
112+
113+
if (typeof candidate.status === "number" && Number.isFinite(candidate.status)) {
114+
return candidate.status;
115+
}
116+
117+
return fallbackStatus;
118+
}

0 commit comments

Comments
 (0)