@getjack/jack 0.1.12 → 0.1.14
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.
- package/package.json +2 -5
- package/src/commands/down.ts +1 -4
- package/src/commands/login.ts +6 -199
- package/src/lib/auth/ensure-auth.test.ts +285 -0
- package/src/lib/auth/ensure-auth.ts +165 -0
- package/src/lib/auth/index.ts +10 -0
- package/src/lib/auth/login-flow.ts +287 -0
- package/src/lib/control-plane.ts +42 -0
- package/src/lib/deploy-mode.ts +23 -2
- package/src/lib/deploy-upload.ts +9 -0
- package/src/lib/hooks.ts +25 -9
- package/src/lib/json-edit.ts +1 -5
- package/src/lib/project-operations.ts +391 -310
- package/src/lib/project-resolver.ts +12 -0
- package/src/lib/telemetry.ts +1 -0
- package/templates/miniapp/.jack.json +5 -5
- package/templates/miniapp/public/.well-known/farcaster.json +15 -15
- package/templates/miniapp/src/lib/api.ts +71 -3
- package/templates/miniapp/src/worker.ts +45 -5
|
@@ -373,6 +373,18 @@ export async function listAllProjects(): Promise<ResolvedProject[]> {
|
|
|
373
373
|
projectMap.set(managed.id, resolved);
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
|
+
|
|
377
|
+
// Mark orphaned local managed projects (not found on control plane) as errors
|
|
378
|
+
for (const [, project] of projectMap) {
|
|
379
|
+
if (
|
|
380
|
+
project.deployMode === "managed" &&
|
|
381
|
+
project.status === "syncing" &&
|
|
382
|
+
!project.sources.controlPlane
|
|
383
|
+
) {
|
|
384
|
+
project.status = "error";
|
|
385
|
+
project.errorMessage = "Project not found in jack cloud. Run: jack unlink && jack ship";
|
|
386
|
+
}
|
|
387
|
+
}
|
|
376
388
|
} catch {
|
|
377
389
|
// Control plane unavailable, use local-only data
|
|
378
390
|
}
|
package/src/lib/telemetry.ts
CHANGED
|
@@ -12,6 +12,7 @@ const SESSION_ID = crypto.randomUUID();
|
|
|
12
12
|
// EVENT REGISTRY
|
|
13
13
|
// ============================================
|
|
14
14
|
export const Events = {
|
|
15
|
+
AUTH_GATE_RESOLVED: "auth_gate_resolved",
|
|
15
16
|
COMMAND_INVOKED: "command_invoked",
|
|
16
17
|
COMMAND_COMPLETED: "command_completed",
|
|
17
18
|
COMMAND_FAILED: "command_failed",
|
|
@@ -50,11 +50,11 @@
|
|
|
50
50
|
"path": "public/.well-known/farcaster.json",
|
|
51
51
|
"successMessage": "Updated manifest URLs to {{url}}",
|
|
52
52
|
"set": {
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
53
|
+
"frame.name": "{{name}}",
|
|
54
|
+
"frame.homeUrl": "{{url}}",
|
|
55
|
+
"frame.iconUrl": "{{url}}/icon.png",
|
|
56
|
+
"frame.imageUrl": "{{url}}/og.png",
|
|
57
|
+
"frame.splashImageUrl": "{{url}}/icon.png"
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
{
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
2
|
+
"accountAssociation": {
|
|
3
|
+
"header": "",
|
|
4
|
+
"payload": "",
|
|
5
|
+
"signature": ""
|
|
6
|
+
},
|
|
7
|
+
"frame": {
|
|
8
|
+
"version": "1",
|
|
9
|
+
"name": "jack-template",
|
|
10
|
+
"iconUrl": "https://example.com/icon.png",
|
|
11
|
+
"homeUrl": "https://example.com",
|
|
12
|
+
"imageUrl": "https://example.com/og.png",
|
|
13
|
+
"buttonTitle": "Open App",
|
|
14
|
+
"splashImageUrl": "https://example.com/icon.png",
|
|
15
|
+
"splashBackgroundColor": "#0a0a0a"
|
|
16
|
+
}
|
|
17
17
|
}
|
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
import { hc } from "hono/client";
|
|
2
2
|
import type { AppType } from "../worker";
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
// Create Hono RPC client
|
|
5
|
+
// Note: Type inference may show 'unknown' in IDE but works at runtime
|
|
6
|
+
// The explicit response types below ensure type safety for API consumers
|
|
7
|
+
const client = hc<AppType>("/");
|
|
8
|
+
|
|
9
|
+
// Export typed client - if AppType inference fails, these explicit types provide safety
|
|
10
|
+
export const api = client as {
|
|
11
|
+
api: {
|
|
12
|
+
guestbook: {
|
|
13
|
+
$get: () => Promise<
|
|
14
|
+
Response & {
|
|
15
|
+
json: () => Promise<{
|
|
16
|
+
entries: Array<{
|
|
17
|
+
id: number;
|
|
18
|
+
fid: number;
|
|
19
|
+
username: string;
|
|
20
|
+
display_name: string | null;
|
|
21
|
+
pfp_url: string | null;
|
|
22
|
+
message: string;
|
|
23
|
+
created_at: string;
|
|
24
|
+
}>;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
>;
|
|
28
|
+
$post: (options: {
|
|
29
|
+
json: {
|
|
30
|
+
fid: number;
|
|
31
|
+
username: string;
|
|
32
|
+
displayName?: string;
|
|
33
|
+
pfpUrl?: string;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
}) => Promise<
|
|
37
|
+
Response & {
|
|
38
|
+
json: () => Promise<{
|
|
39
|
+
entry?: {
|
|
40
|
+
id: number;
|
|
41
|
+
fid: number;
|
|
42
|
+
username: string;
|
|
43
|
+
display_name: string | null;
|
|
44
|
+
pfp_url: string | null;
|
|
45
|
+
message: string;
|
|
46
|
+
created_at: string;
|
|
47
|
+
};
|
|
48
|
+
error?: string;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
>;
|
|
52
|
+
};
|
|
53
|
+
ai: {
|
|
54
|
+
generate: {
|
|
55
|
+
$post: (options: {
|
|
56
|
+
json: { prompt: string; schema?: object };
|
|
57
|
+
}) => Promise<
|
|
58
|
+
Response & {
|
|
59
|
+
json: () => Promise<{
|
|
60
|
+
result?: string;
|
|
61
|
+
provider?: "openai" | "workers-ai";
|
|
62
|
+
error?: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
>;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
notifications: {
|
|
69
|
+
$get: (options?: {
|
|
70
|
+
query: { fid: string };
|
|
71
|
+
}) => Promise<Response & { json: () => Promise<unknown> }>;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Server-side Worker - handles API routes, keeps secrets secure
|
|
2
|
+
/// <reference types="@cloudflare/workers-types" />
|
|
2
3
|
|
|
3
4
|
import { Hono } from "hono";
|
|
4
5
|
import { cors } from "hono/cors";
|
|
@@ -53,11 +54,7 @@ function getBaseUrl(
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
// Reject localhost or IPs - embeds won't work in local dev or IP domains
|
|
56
|
-
if (
|
|
57
|
-
hostname === "localhost" ||
|
|
58
|
-
hostname === "127.0.0.1" ||
|
|
59
|
-
isIpAddress(hostname)
|
|
60
|
-
) {
|
|
57
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || isIpAddress(hostname)) {
|
|
61
58
|
return null; // Signal that we can't generate valid embed URLs
|
|
62
59
|
}
|
|
63
60
|
|
|
@@ -628,6 +625,49 @@ app.get("/share", (c) => {
|
|
|
628
625
|
});
|
|
629
626
|
});
|
|
630
627
|
|
|
628
|
+
// GET / - Inject fc:miniapp meta tags for Farcaster embeds on the main page
|
|
629
|
+
// Without this, sharing the app URL in a cast won't render an embed card
|
|
630
|
+
app.get("/", async (c) => {
|
|
631
|
+
// Fetch the static index.html from Vite build
|
|
632
|
+
const response = await c.env.ASSETS.fetch(c.req.raw);
|
|
633
|
+
const html = await response.text();
|
|
634
|
+
|
|
635
|
+
const baseUrl = getBaseUrl(c.env, c);
|
|
636
|
+
|
|
637
|
+
// Local dev - serve without meta tags (they require https URLs)
|
|
638
|
+
if (!baseUrl) {
|
|
639
|
+
return c.html(html);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Build embed JSON (same structure as /share route)
|
|
643
|
+
const embedJson = JSON.stringify({
|
|
644
|
+
version: "1",
|
|
645
|
+
imageUrl: `${baseUrl}/og.png`,
|
|
646
|
+
button: {
|
|
647
|
+
title: "Open App",
|
|
648
|
+
action: {
|
|
649
|
+
type: "launch_miniapp",
|
|
650
|
+
name: "jack-template",
|
|
651
|
+
url: baseUrl,
|
|
652
|
+
splashImageUrl: `${baseUrl}/icon.png`,
|
|
653
|
+
splashBackgroundColor: "#0a0a0a",
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
// Meta tags to inject
|
|
659
|
+
const metaTags = `
|
|
660
|
+
<meta property="og:title" content="jack-template" />
|
|
661
|
+
<meta property="og:image" content="${baseUrl}/og.png" />
|
|
662
|
+
<meta name="fc:miniapp" content='${embedJson}' />
|
|
663
|
+
<meta name="fc:frame" content='${embedJson}' />
|
|
664
|
+
`;
|
|
665
|
+
|
|
666
|
+
// Inject before </head>
|
|
667
|
+
const injectedHtml = html.replace("</head>", `${metaTags}</head>`);
|
|
668
|
+
return c.html(injectedHtml);
|
|
669
|
+
});
|
|
670
|
+
|
|
631
671
|
// Serve React app for all other routes
|
|
632
672
|
app.get("*", (c) => c.env.ASSETS.fetch(c.req.raw));
|
|
633
673
|
|