@helloleo/plugins 0.2.0-beta.0 → 0.2.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.
- package/dist/index.js +8 -4
- package/dist/templates/tanstack-start-2026-06-18/src/routes/api/health.ts +81 -0
- package/package.json +1 -1
- package/src/templates/tanstack-start-2026-06-18/src/routes/api/health.ts +81 -0
- package/src/tools/scaffold.ts +1 -0
- package/src/tools/setup-netsuite.ts +7 -4
- package/dist/templates/tanstack-start-2026-06-18/src/api/health.ts +0 -66
- package/src/templates/tanstack-start-2026-06-18/src/api/health.ts +0 -66
package/dist/index.js
CHANGED
|
@@ -24918,6 +24918,7 @@ var scaffold = tool({
|
|
|
24918
24918
|
"Notes:",
|
|
24919
24919
|
"- This is a TanStack Start project. The server entry is src/server.ts. There is no index.html or client entrypoint.",
|
|
24920
24920
|
"- Add routes as files in src/routes/. Do not default export route components.",
|
|
24921
|
+
"- For JSON/CRUD APIs, add server routes under src/routes/api/. Read src/routes/api/health.ts first, add routes as needed.",
|
|
24921
24922
|
"- shadcn/ui components are already in src/components/ui.",
|
|
24922
24923
|
"- Design system: edit the tokens in src/styles.css (light and dark blocks).",
|
|
24923
24924
|
"- The database schema lives in src/db/schema.ts. Migrations run automatically.",
|
|
@@ -25004,17 +25005,20 @@ export function signInWithNetSuite(returnTo: string = window.location.href) {
|
|
|
25004
25005
|
// refuses to render -- looks like "nothing happens" to the user. Navigate
|
|
25005
25006
|
// the top frame instead so the OAuth flow runs at the top level and the
|
|
25006
25007
|
// callback redirect lands on the same top frame, which then reads the
|
|
25007
|
-
// #nssid= fragment.
|
|
25008
|
-
//
|
|
25008
|
+
// #nssid= fragment. Use \`location.href =\` (NOT \`location.assign()\`):
|
|
25009
|
+
// reading the \`.assign\` method off a cross-origin \`window.top.location\`
|
|
25010
|
+
// throws a SecurityError, which would drop us into the same-frame fallback
|
|
25011
|
+
// and load NetSuite inside the iframe (X-Frame-Options: DENY -> "refused to
|
|
25012
|
+
// connect"). Assigning \`.href\` is a navigation, allowed cross-origin.
|
|
25009
25013
|
try {
|
|
25010
25014
|
if (window.top && window.top !== window) {
|
|
25011
|
-
window.top.location.
|
|
25015
|
+
window.top.location.href = url.toString();
|
|
25012
25016
|
return;
|
|
25013
25017
|
}
|
|
25014
25018
|
} catch {
|
|
25015
25019
|
/* top window not accessible \u2014 fall through to same-frame navigation */
|
|
25016
25020
|
}
|
|
25017
|
-
window.location.
|
|
25021
|
+
window.location.href = url.toString();
|
|
25018
25022
|
}
|
|
25019
25023
|
|
|
25020
25024
|
export interface NetSuiteSession {
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { db } from '#/db'
|
|
3
|
+
import { entries } from '#/db/schema'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Server route example: GET /api/health. Use this file as the base for
|
|
7
|
+
* building JSON APIs (CRUD endpoints, webhooks) with TanStack Start
|
|
8
|
+
* server routes:
|
|
9
|
+
* https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
|
|
10
|
+
*
|
|
11
|
+
* How server routes work:
|
|
12
|
+
* - Files under src/routes/ can export server handlers. The URL matches
|
|
13
|
+
* the file path: src/routes/api/health.ts serves /api/health.
|
|
14
|
+
* - Add one handler per HTTP method under server.handlers (GET, POST,
|
|
15
|
+
* PUT, PATCH, DELETE). A handler receives ({ request, params }) and
|
|
16
|
+
* returns a Response, usually Response.json().
|
|
17
|
+
* - Dynamic segments use $: src/routes/api/todos/$id.ts serves
|
|
18
|
+
* /api/todos/:id and the handler reads params.id.
|
|
19
|
+
* - Read the request body with await request.json() and validate it
|
|
20
|
+
* before use. Return proper status codes (201 created, 404 not found).
|
|
21
|
+
* - Query the database with `import { db } from '#/db'` INSIDE the
|
|
22
|
+
* handler, never at module scope (the binding only exists per request).
|
|
23
|
+
*/
|
|
24
|
+
export const Route = createFileRoute('/api/health')({
|
|
25
|
+
server: {
|
|
26
|
+
handlers: {
|
|
27
|
+
GET: async () => {
|
|
28
|
+
const startedAt = Date.now()
|
|
29
|
+
|
|
30
|
+
const server = {
|
|
31
|
+
status: 'ok' as const,
|
|
32
|
+
uptimeSeconds: Math.round(
|
|
33
|
+
typeof process !== 'undefined' &&
|
|
34
|
+
typeof process.uptime === 'function'
|
|
35
|
+
? process.uptime()
|
|
36
|
+
: 0,
|
|
37
|
+
),
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
runtime: 'cloudflare-workers',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Database health: lightweight query against a known table
|
|
43
|
+
let database: {
|
|
44
|
+
status: 'ok' | 'error'
|
|
45
|
+
latencyMs: number
|
|
46
|
+
error: string | null
|
|
47
|
+
}
|
|
48
|
+
const dbStart = Date.now()
|
|
49
|
+
try {
|
|
50
|
+
await db.select({ id: entries.id }).from(entries).limit(1)
|
|
51
|
+
database = {
|
|
52
|
+
status: 'ok',
|
|
53
|
+
latencyMs: Date.now() - dbStart,
|
|
54
|
+
error: null,
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
database = {
|
|
58
|
+
status: 'error',
|
|
59
|
+
latencyMs: Date.now() - dbStart,
|
|
60
|
+
error: err instanceof Error ? err.message : String(err),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const overall =
|
|
65
|
+
server.status === 'ok' && database.status === 'ok'
|
|
66
|
+
? 'ok'
|
|
67
|
+
: 'degraded'
|
|
68
|
+
|
|
69
|
+
return Response.json(
|
|
70
|
+
{
|
|
71
|
+
status: overall,
|
|
72
|
+
server,
|
|
73
|
+
database,
|
|
74
|
+
checkedInMs: Date.now() - startedAt,
|
|
75
|
+
},
|
|
76
|
+
{ status: overall === 'ok' ? 200 : 503 },
|
|
77
|
+
)
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
})
|
package/package.json
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { db } from '#/db'
|
|
3
|
+
import { entries } from '#/db/schema'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Server route example: GET /api/health. Use this file as the base for
|
|
7
|
+
* building JSON APIs (CRUD endpoints, webhooks) with TanStack Start
|
|
8
|
+
* server routes:
|
|
9
|
+
* https://tanstack.com/start/latest/docs/framework/react/guide/server-routes
|
|
10
|
+
*
|
|
11
|
+
* How server routes work:
|
|
12
|
+
* - Files under src/routes/ can export server handlers. The URL matches
|
|
13
|
+
* the file path: src/routes/api/health.ts serves /api/health.
|
|
14
|
+
* - Add one handler per HTTP method under server.handlers (GET, POST,
|
|
15
|
+
* PUT, PATCH, DELETE). A handler receives ({ request, params }) and
|
|
16
|
+
* returns a Response, usually Response.json().
|
|
17
|
+
* - Dynamic segments use $: src/routes/api/todos/$id.ts serves
|
|
18
|
+
* /api/todos/:id and the handler reads params.id.
|
|
19
|
+
* - Read the request body with await request.json() and validate it
|
|
20
|
+
* before use. Return proper status codes (201 created, 404 not found).
|
|
21
|
+
* - Query the database with `import { db } from '#/db'` INSIDE the
|
|
22
|
+
* handler, never at module scope (the binding only exists per request).
|
|
23
|
+
*/
|
|
24
|
+
export const Route = createFileRoute('/api/health')({
|
|
25
|
+
server: {
|
|
26
|
+
handlers: {
|
|
27
|
+
GET: async () => {
|
|
28
|
+
const startedAt = Date.now()
|
|
29
|
+
|
|
30
|
+
const server = {
|
|
31
|
+
status: 'ok' as const,
|
|
32
|
+
uptimeSeconds: Math.round(
|
|
33
|
+
typeof process !== 'undefined' &&
|
|
34
|
+
typeof process.uptime === 'function'
|
|
35
|
+
? process.uptime()
|
|
36
|
+
: 0,
|
|
37
|
+
),
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
runtime: 'cloudflare-workers',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Database health: lightweight query against a known table
|
|
43
|
+
let database: {
|
|
44
|
+
status: 'ok' | 'error'
|
|
45
|
+
latencyMs: number
|
|
46
|
+
error: string | null
|
|
47
|
+
}
|
|
48
|
+
const dbStart = Date.now()
|
|
49
|
+
try {
|
|
50
|
+
await db.select({ id: entries.id }).from(entries).limit(1)
|
|
51
|
+
database = {
|
|
52
|
+
status: 'ok',
|
|
53
|
+
latencyMs: Date.now() - dbStart,
|
|
54
|
+
error: null,
|
|
55
|
+
}
|
|
56
|
+
} catch (err) {
|
|
57
|
+
database = {
|
|
58
|
+
status: 'error',
|
|
59
|
+
latencyMs: Date.now() - dbStart,
|
|
60
|
+
error: err instanceof Error ? err.message : String(err),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const overall =
|
|
65
|
+
server.status === 'ok' && database.status === 'ok'
|
|
66
|
+
? 'ok'
|
|
67
|
+
: 'degraded'
|
|
68
|
+
|
|
69
|
+
return Response.json(
|
|
70
|
+
{
|
|
71
|
+
status: overall,
|
|
72
|
+
server,
|
|
73
|
+
database,
|
|
74
|
+
checkedInMs: Date.now() - startedAt,
|
|
75
|
+
},
|
|
76
|
+
{ status: overall === 'ok' ? 200 : 503 },
|
|
77
|
+
)
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
})
|
package/src/tools/scaffold.ts
CHANGED
|
@@ -88,6 +88,7 @@ export const scaffold = tool({
|
|
|
88
88
|
"Notes:",
|
|
89
89
|
"- This is a TanStack Start project. The server entry is src/server.ts. There is no index.html or client entrypoint.",
|
|
90
90
|
"- Add routes as files in src/routes/. Do not default export route components.",
|
|
91
|
+
"- For JSON/CRUD APIs, add server routes under src/routes/api/. Read src/routes/api/health.ts first, add routes as needed.",
|
|
91
92
|
"- shadcn/ui components are already in src/components/ui.",
|
|
92
93
|
"- Design system: edit the tokens in src/styles.css (light and dark blocks).",
|
|
93
94
|
"- The database schema lives in src/db/schema.ts. Migrations run automatically.",
|
|
@@ -82,17 +82,20 @@ export function signInWithNetSuite(returnTo: string = window.location.href) {
|
|
|
82
82
|
// refuses to render -- looks like "nothing happens" to the user. Navigate
|
|
83
83
|
// the top frame instead so the OAuth flow runs at the top level and the
|
|
84
84
|
// callback redirect lands on the same top frame, which then reads the
|
|
85
|
-
// #nssid= fragment.
|
|
86
|
-
//
|
|
85
|
+
// #nssid= fragment. Use \`location.href =\` (NOT \`location.assign()\`):
|
|
86
|
+
// reading the \`.assign\` method off a cross-origin \`window.top.location\`
|
|
87
|
+
// throws a SecurityError, which would drop us into the same-frame fallback
|
|
88
|
+
// and load NetSuite inside the iframe (X-Frame-Options: DENY -> "refused to
|
|
89
|
+
// connect"). Assigning \`.href\` is a navigation, allowed cross-origin.
|
|
87
90
|
try {
|
|
88
91
|
if (window.top && window.top !== window) {
|
|
89
|
-
window.top.location.
|
|
92
|
+
window.top.location.href = url.toString();
|
|
90
93
|
return;
|
|
91
94
|
}
|
|
92
95
|
} catch {
|
|
93
96
|
/* top window not accessible — fall through to same-frame navigation */
|
|
94
97
|
}
|
|
95
|
-
window.location.
|
|
98
|
+
window.location.href = url.toString();
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
export interface NetSuiteSession {
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { supabaseAdmin } from "@/integrations/supabase/client.server";
|
|
3
|
-
|
|
4
|
-
export const Route = createFileRoute("/api/health")({
|
|
5
|
-
server: {
|
|
6
|
-
handlers: {
|
|
7
|
-
GET: async () => {
|
|
8
|
-
const startedAt = Date.now();
|
|
9
|
-
|
|
10
|
-
// Server health
|
|
11
|
-
const server = {
|
|
12
|
-
status: "ok" as const,
|
|
13
|
-
uptimeSeconds: Math.round(
|
|
14
|
-
typeof process !== "undefined" &&
|
|
15
|
-
typeof process.uptime === "function"
|
|
16
|
-
? process.uptime()
|
|
17
|
-
: 0,
|
|
18
|
-
),
|
|
19
|
-
timestamp: new Date().toISOString(),
|
|
20
|
-
runtime: "cloudflare-workers",
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Database health — lightweight query against a known table
|
|
24
|
-
let database: {
|
|
25
|
-
status: "ok" | "error";
|
|
26
|
-
latencyMs: number;
|
|
27
|
-
error: string | null;
|
|
28
|
-
};
|
|
29
|
-
const dbStart = Date.now();
|
|
30
|
-
try {
|
|
31
|
-
const { error } = await supabaseAdmin
|
|
32
|
-
.from("notes")
|
|
33
|
-
.select("id", { count: "exact", head: true })
|
|
34
|
-
.limit(1);
|
|
35
|
-
if (error) throw error;
|
|
36
|
-
database = {
|
|
37
|
-
status: "ok",
|
|
38
|
-
latencyMs: Date.now() - dbStart,
|
|
39
|
-
error: null,
|
|
40
|
-
};
|
|
41
|
-
} catch (err) {
|
|
42
|
-
database = {
|
|
43
|
-
status: "error",
|
|
44
|
-
latencyMs: Date.now() - dbStart,
|
|
45
|
-
error: err instanceof Error ? err.message : String(err),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const overall =
|
|
50
|
-
server.status === "ok" && database.status === "ok"
|
|
51
|
-
? "ok"
|
|
52
|
-
: "degraded";
|
|
53
|
-
|
|
54
|
-
return Response.json(
|
|
55
|
-
{
|
|
56
|
-
status: overall,
|
|
57
|
-
server,
|
|
58
|
-
database,
|
|
59
|
-
checkedInMs: Date.now() - startedAt,
|
|
60
|
-
},
|
|
61
|
-
{ status: overall === "ok" ? 200 : 503 },
|
|
62
|
-
);
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { supabaseAdmin } from "@/integrations/supabase/client.server";
|
|
3
|
-
|
|
4
|
-
export const Route = createFileRoute("/api/health")({
|
|
5
|
-
server: {
|
|
6
|
-
handlers: {
|
|
7
|
-
GET: async () => {
|
|
8
|
-
const startedAt = Date.now();
|
|
9
|
-
|
|
10
|
-
// Server health
|
|
11
|
-
const server = {
|
|
12
|
-
status: "ok" as const,
|
|
13
|
-
uptimeSeconds: Math.round(
|
|
14
|
-
typeof process !== "undefined" &&
|
|
15
|
-
typeof process.uptime === "function"
|
|
16
|
-
? process.uptime()
|
|
17
|
-
: 0,
|
|
18
|
-
),
|
|
19
|
-
timestamp: new Date().toISOString(),
|
|
20
|
-
runtime: "cloudflare-workers",
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Database health — lightweight query against a known table
|
|
24
|
-
let database: {
|
|
25
|
-
status: "ok" | "error";
|
|
26
|
-
latencyMs: number;
|
|
27
|
-
error: string | null;
|
|
28
|
-
};
|
|
29
|
-
const dbStart = Date.now();
|
|
30
|
-
try {
|
|
31
|
-
const { error } = await supabaseAdmin
|
|
32
|
-
.from("notes")
|
|
33
|
-
.select("id", { count: "exact", head: true })
|
|
34
|
-
.limit(1);
|
|
35
|
-
if (error) throw error;
|
|
36
|
-
database = {
|
|
37
|
-
status: "ok",
|
|
38
|
-
latencyMs: Date.now() - dbStart,
|
|
39
|
-
error: null,
|
|
40
|
-
};
|
|
41
|
-
} catch (err) {
|
|
42
|
-
database = {
|
|
43
|
-
status: "error",
|
|
44
|
-
latencyMs: Date.now() - dbStart,
|
|
45
|
-
error: err instanceof Error ? err.message : String(err),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const overall =
|
|
50
|
-
server.status === "ok" && database.status === "ok"
|
|
51
|
-
? "ok"
|
|
52
|
-
: "degraded";
|
|
53
|
-
|
|
54
|
-
return Response.json(
|
|
55
|
-
{
|
|
56
|
-
status: overall,
|
|
57
|
-
server,
|
|
58
|
-
database,
|
|
59
|
-
checkedInMs: Date.now() - startedAt,
|
|
60
|
-
},
|
|
61
|
-
{ status: overall === "ok" ? 200 : 503 },
|
|
62
|
-
);
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
});
|