@helloleo/plugins 0.1.14 → 0.1.15

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 (127) hide show
  1. package/dist/index.js +197 -469
  2. package/dist/templates/tanstack-router-2026-06-15/components.json +22 -0
  3. package/dist/templates/tanstack-router-2026-06-15/index.html +13 -0
  4. package/dist/templates/tanstack-router-2026-06-15/package.json +94 -0
  5. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/accordion.tsx +51 -0
  6. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/alert-dialog.tsx +115 -0
  7. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/alert.tsx +49 -0
  8. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/aspect-ratio.tsx +5 -0
  9. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/avatar.tsx +47 -0
  10. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/badge.tsx +32 -0
  11. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/breadcrumb.tsx +101 -0
  12. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/button.tsx +49 -0
  13. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/calendar.tsx +177 -0
  14. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/card.tsx +55 -0
  15. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/carousel.tsx +240 -0
  16. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/chart.tsx +331 -0
  17. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/checkbox.tsx +26 -0
  18. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/collapsible.tsx +11 -0
  19. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/command.tsx +143 -0
  20. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/context-menu.tsx +187 -0
  21. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/dialog.tsx +104 -0
  22. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/drawer.tsx +98 -0
  23. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/dropdown-menu.tsx +188 -0
  24. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/form.tsx +171 -0
  25. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/hover-card.tsx +27 -0
  26. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/input-otp.tsx +69 -0
  27. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/input.tsx +22 -0
  28. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/label.tsx +21 -0
  29. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/menubar.tsx +229 -0
  30. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/navigation-menu.tsx +120 -0
  31. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/pagination.tsx +98 -0
  32. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/popover.tsx +31 -0
  33. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/progress.tsx +25 -0
  34. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/radio-group.tsx +36 -0
  35. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/resizable.tsx +37 -0
  36. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/scroll-area.tsx +44 -0
  37. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/select.tsx +152 -0
  38. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/separator.tsx +24 -0
  39. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/sheet.tsx +122 -0
  40. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/sidebar.tsx +744 -0
  41. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/skeleton.tsx +7 -0
  42. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/slider.tsx +23 -0
  43. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/sonner.tsx +23 -0
  44. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/switch.tsx +27 -0
  45. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/table.tsx +94 -0
  46. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/tabs.tsx +53 -0
  47. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/textarea.tsx +21 -0
  48. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/toggle-group.tsx +57 -0
  49. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/toggle.tsx +42 -0
  50. package/dist/templates/tanstack-router-2026-06-15/src/components/ui/tooltip.tsx +32 -0
  51. package/dist/templates/tanstack-router-2026-06-15/src/hooks/use-mobile.tsx +19 -0
  52. package/dist/templates/tanstack-router-2026-06-15/src/lib/proxy.ts +83 -0
  53. package/dist/templates/tanstack-router-2026-06-15/src/lib/utils.ts +6 -0
  54. package/dist/templates/tanstack-router-2026-06-15/src/main.tsx +33 -0
  55. package/dist/templates/tanstack-router-2026-06-15/src/routeTree.gen.ts +59 -0
  56. package/dist/templates/tanstack-router-2026-06-15/src/router.tsx +23 -0
  57. package/dist/templates/tanstack-router-2026-06-15/src/routes/__root.tsx +16 -0
  58. package/dist/templates/tanstack-router-2026-06-15/src/routes/index.tsx +14 -0
  59. package/dist/templates/tanstack-router-2026-06-15/src/styles.css +214 -0
  60. package/dist/templates/tanstack-router-2026-06-15/tsconfig.json +28 -0
  61. package/dist/templates/tanstack-router-2026-06-15/tsr.config.json +3 -0
  62. package/dist/templates/tanstack-router-2026-06-15/vite.config.ts +21 -0
  63. package/package.json +3 -2
  64. package/src/template-render.ts +48 -0
  65. package/src/templates/tanstack-router-2026-06-15/components.json +22 -0
  66. package/src/templates/tanstack-router-2026-06-15/index.html +13 -0
  67. package/src/templates/tanstack-router-2026-06-15/package.json +94 -0
  68. package/src/templates/tanstack-router-2026-06-15/src/components/ui/accordion.tsx +51 -0
  69. package/src/templates/tanstack-router-2026-06-15/src/components/ui/alert-dialog.tsx +115 -0
  70. package/src/templates/tanstack-router-2026-06-15/src/components/ui/alert.tsx +49 -0
  71. package/src/templates/tanstack-router-2026-06-15/src/components/ui/aspect-ratio.tsx +5 -0
  72. package/src/templates/tanstack-router-2026-06-15/src/components/ui/avatar.tsx +47 -0
  73. package/src/templates/tanstack-router-2026-06-15/src/components/ui/badge.tsx +32 -0
  74. package/src/templates/tanstack-router-2026-06-15/src/components/ui/breadcrumb.tsx +101 -0
  75. package/src/templates/tanstack-router-2026-06-15/src/components/ui/button.tsx +49 -0
  76. package/src/templates/tanstack-router-2026-06-15/src/components/ui/calendar.tsx +177 -0
  77. package/src/templates/tanstack-router-2026-06-15/src/components/ui/card.tsx +55 -0
  78. package/src/templates/tanstack-router-2026-06-15/src/components/ui/carousel.tsx +240 -0
  79. package/src/templates/tanstack-router-2026-06-15/src/components/ui/chart.tsx +331 -0
  80. package/src/templates/tanstack-router-2026-06-15/src/components/ui/checkbox.tsx +26 -0
  81. package/src/templates/tanstack-router-2026-06-15/src/components/ui/collapsible.tsx +11 -0
  82. package/src/templates/tanstack-router-2026-06-15/src/components/ui/command.tsx +143 -0
  83. package/src/templates/tanstack-router-2026-06-15/src/components/ui/context-menu.tsx +187 -0
  84. package/src/templates/tanstack-router-2026-06-15/src/components/ui/dialog.tsx +104 -0
  85. package/src/templates/tanstack-router-2026-06-15/src/components/ui/drawer.tsx +98 -0
  86. package/src/templates/tanstack-router-2026-06-15/src/components/ui/dropdown-menu.tsx +188 -0
  87. package/src/templates/tanstack-router-2026-06-15/src/components/ui/form.tsx +171 -0
  88. package/src/templates/tanstack-router-2026-06-15/src/components/ui/hover-card.tsx +27 -0
  89. package/src/templates/tanstack-router-2026-06-15/src/components/ui/input-otp.tsx +69 -0
  90. package/src/templates/tanstack-router-2026-06-15/src/components/ui/input.tsx +22 -0
  91. package/src/templates/tanstack-router-2026-06-15/src/components/ui/label.tsx +21 -0
  92. package/src/templates/tanstack-router-2026-06-15/src/components/ui/menubar.tsx +229 -0
  93. package/src/templates/tanstack-router-2026-06-15/src/components/ui/navigation-menu.tsx +120 -0
  94. package/src/templates/tanstack-router-2026-06-15/src/components/ui/pagination.tsx +98 -0
  95. package/src/templates/tanstack-router-2026-06-15/src/components/ui/popover.tsx +31 -0
  96. package/src/templates/tanstack-router-2026-06-15/src/components/ui/progress.tsx +25 -0
  97. package/src/templates/tanstack-router-2026-06-15/src/components/ui/radio-group.tsx +36 -0
  98. package/src/templates/tanstack-router-2026-06-15/src/components/ui/resizable.tsx +37 -0
  99. package/src/templates/tanstack-router-2026-06-15/src/components/ui/scroll-area.tsx +44 -0
  100. package/src/templates/tanstack-router-2026-06-15/src/components/ui/select.tsx +152 -0
  101. package/src/templates/tanstack-router-2026-06-15/src/components/ui/separator.tsx +24 -0
  102. package/src/templates/tanstack-router-2026-06-15/src/components/ui/sheet.tsx +122 -0
  103. package/src/templates/tanstack-router-2026-06-15/src/components/ui/sidebar.tsx +744 -0
  104. package/src/templates/tanstack-router-2026-06-15/src/components/ui/skeleton.tsx +7 -0
  105. package/src/templates/tanstack-router-2026-06-15/src/components/ui/slider.tsx +23 -0
  106. package/src/templates/tanstack-router-2026-06-15/src/components/ui/sonner.tsx +23 -0
  107. package/src/templates/tanstack-router-2026-06-15/src/components/ui/switch.tsx +27 -0
  108. package/src/templates/tanstack-router-2026-06-15/src/components/ui/table.tsx +94 -0
  109. package/src/templates/tanstack-router-2026-06-15/src/components/ui/tabs.tsx +53 -0
  110. package/src/templates/tanstack-router-2026-06-15/src/components/ui/textarea.tsx +21 -0
  111. package/src/templates/tanstack-router-2026-06-15/src/components/ui/toggle-group.tsx +57 -0
  112. package/src/templates/tanstack-router-2026-06-15/src/components/ui/toggle.tsx +42 -0
  113. package/src/templates/tanstack-router-2026-06-15/src/components/ui/tooltip.tsx +32 -0
  114. package/src/templates/tanstack-router-2026-06-15/src/hooks/use-mobile.tsx +19 -0
  115. package/src/templates/tanstack-router-2026-06-15/src/lib/proxy.ts +83 -0
  116. package/src/templates/tanstack-router-2026-06-15/src/lib/utils.ts +6 -0
  117. package/src/templates/tanstack-router-2026-06-15/src/main.tsx +33 -0
  118. package/src/templates/tanstack-router-2026-06-15/src/routeTree.gen.ts +59 -0
  119. package/src/templates/tanstack-router-2026-06-15/src/router.tsx +23 -0
  120. package/src/templates/tanstack-router-2026-06-15/src/routes/__root.tsx +16 -0
  121. package/src/templates/tanstack-router-2026-06-15/src/routes/index.tsx +14 -0
  122. package/src/templates/tanstack-router-2026-06-15/src/styles.css +214 -0
  123. package/src/templates/tanstack-router-2026-06-15/tsconfig.json +28 -0
  124. package/src/templates/tanstack-router-2026-06-15/tsr.config.json +3 -0
  125. package/src/templates/tanstack-router-2026-06-15/vite.config.ts +21 -0
  126. package/src/tools/scaffold.ts +51 -444
  127. package/src/tools/setup-netsuite.ts +161 -80
@@ -6,10 +6,13 @@ import { writeBaseScaffold } from "./scaffold.ts";
6
6
 
7
7
  /**
8
8
  * One-shot bootstrap for a NetSuite project. Writes the base HelloLeo
9
- * scaffold (via writeBaseScaffold) plus the NetSuite OAuth wiring
10
- * (AuthGate, LoginPage, sign-in button, netsuite client, auth-gated
11
- * App.tsx). All NetSuite-specific templates live in this file -- one
12
- * place to read or change anything NetSuite-related.
9
+ * scaffold (via writeBaseScaffold) plus ADDITIVE NetSuite OAuth wiring:
10
+ * the netsuite OAuth client, a NetSuite auth context (auth.tsx), and the
11
+ * AuthLayout / LoginPage / SignInWithNetSuite components. It never
12
+ * overwrites a scaffold file -- the one manual step is wrapping the root
13
+ * route's <Outlet /> with <AuthLayout> (the tool's output shows the
14
+ * snippet). All NetSuite-specific templates live in this file -- one place
15
+ * to read or change anything NetSuite-related.
13
16
  *
14
17
  * Use INSTEAD of `scaffold` when the project needs NetSuite. The tool
15
18
  * name carries the intent so the LLM can't accidentally ship a project
@@ -209,34 +212,120 @@ export function LoginPage() {
209
212
  `;
210
213
  }
211
214
 
212
- function netsuiteAuthGateTsx(): string {
213
- return `import { useEffect, useState } from 'react';
215
+ function authTsx(): string {
216
+ return `import * as React from 'react';
217
+ import {
218
+ getNetSuiteSession,
219
+ signInWithNetSuite,
220
+ signOutNetSuite,
221
+ type NetSuiteSession,
222
+ } from './netsuite';
223
+
224
+ /**
225
+ * NetSuite auth context. Holds the current session (resolved from the Worker's
226
+ * /api/me via getNetSuiteSession) and exposes sign-in / sign-out. The only
227
+ * authoritative auth check is /api/me -- never trust sessionStorage directly.
228
+ */
229
+ export interface NetSuiteAuthContextValue {
230
+ pending: boolean;
231
+ isAuthenticated: boolean;
232
+ session: NetSuiteSession | null;
233
+ signIn: () => void;
234
+ signOut: () => Promise<void>;
235
+ refresh: () => Promise<void>;
236
+ }
237
+
238
+ const NetSuiteAuthContext =
239
+ React.createContext<NetSuiteAuthContextValue | null>(null);
240
+
241
+ export function NetSuiteAuthProvider({
242
+ children,
243
+ }: {
244
+ children: React.ReactNode;
245
+ }) {
246
+ const [session, setSession] = React.useState<NetSuiteSession | null>(null);
247
+ const [pending, setPending] = React.useState(true);
248
+
249
+ const refresh = React.useCallback(async () => {
250
+ setPending(true);
251
+ try {
252
+ setSession(await getNetSuiteSession());
253
+ } finally {
254
+ setPending(false);
255
+ }
256
+ }, []);
257
+
258
+ React.useEffect(() => {
259
+ refresh();
260
+ }, [refresh]);
261
+
262
+ const value: NetSuiteAuthContextValue = {
263
+ pending,
264
+ isAuthenticated: Boolean(session?.authenticated),
265
+ session,
266
+ signIn: () => signInWithNetSuite(),
267
+ signOut: signOutNetSuite,
268
+ refresh,
269
+ };
270
+
271
+ return (
272
+ <NetSuiteAuthContext.Provider value={value}>
273
+ {children}
274
+ </NetSuiteAuthContext.Provider>
275
+ );
276
+ }
277
+
278
+ export function useNetSuiteAuth(): NetSuiteAuthContextValue {
279
+ const ctx = React.useContext(NetSuiteAuthContext);
280
+ if (!ctx) {
281
+ throw new Error('useNetSuiteAuth must be used within <NetSuiteAuthProvider>');
282
+ }
283
+ return ctx;
284
+ }
285
+ `;
286
+ }
287
+
288
+ function authLayoutTsx(): string {
289
+ return `import type { ReactNode } from 'react';
290
+ import { NetSuiteAuthProvider, useNetSuiteAuth } from '../../lib/auth';
214
291
  import { LoginPage } from './LoginPage';
215
- import { getNetSuiteSession, type NetSuiteSession } from '../../lib/netsuite';
216
292
 
217
293
  /**
218
- * Mandatory auth gate for NetSuite projects. Wrap your real App content with
219
- * <AuthGate>...</AuthGate>. Never render NetSuite data without this gate -- it
220
- * is the ONLY supported authentication for a NetSuite project (no password
221
- * gates, no sessionStorage flags, no shared credential).
222
- *
223
- * Pattern in src/App.tsx:
294
+ * NetSuite auth layout. This is the ONLY wiring you need to add by hand --
295
+ * wrap the root route's <Outlet /> with it:
224
296
  *
225
- * import { AuthGate } from './components/auth/AuthGate';
226
- * export default function App() {
297
+ * // src/routes/__root.tsx
298
+ * import { AuthLayout } from '../components/auth/AuthLayout';
299
+ * ...
300
+ * function RootComponent() {
227
301
  * return (
228
- * <AuthGate>
229
- * <Dashboard /> // your authenticated content
230
- * </AuthGate>
302
+ * <>
303
+ * <AuthLayout>
304
+ * <Outlet />
305
+ * </AuthLayout>
306
+ * { ...devtools... }
307
+ * </>
231
308
  * );
232
309
  * }
310
+ *
311
+ * It provides NetSuite auth context to the whole tree and gates rendering:
312
+ * while the session resolves it shows a spinner, unauthenticated users see
313
+ * <LoginPage />, authenticated users see your routes. Use useNetSuiteAuth()
314
+ * anywhere below it to read the session or sign out. NEVER swap this for a
315
+ * password gate -- real OAuth is the only supported login.
233
316
  */
234
- export function AuthGate({ children }: { children: React.ReactNode }) {
235
- const [session, setSession] = useState<NetSuiteSession | null>(null);
317
+ export function AuthLayout({ children }: { children: ReactNode }) {
318
+ return (
319
+ <NetSuiteAuthProvider>
320
+ <Gate>{children}</Gate>
321
+ </NetSuiteAuthProvider>
322
+ );
323
+ }
236
324
 
237
- useEffect(() => { getNetSuiteSession().then(setSession); }, []);
325
+ function Gate({ children }: { children: ReactNode }) {
326
+ const { pending, isAuthenticated } = useNetSuiteAuth();
238
327
 
239
- if (session === null) {
328
+ if (pending) {
240
329
  return (
241
330
  <div className="min-h-screen flex items-center justify-center bg-background">
242
331
  <div className="h-8 w-8 rounded-full border-2 border-primary border-t-transparent animate-spin" />
@@ -244,46 +333,26 @@ export function AuthGate({ children }: { children: React.ReactNode }) {
244
333
  );
245
334
  }
246
335
 
247
- if (!session.authenticated) return <LoginPage />;
336
+ if (!isAuthenticated) return <LoginPage />;
248
337
 
249
338
  return <>{children}</>;
250
339
  }
251
340
  `;
252
341
  }
253
342
 
254
- function netsuiteAppTsx(): string {
255
- return `import { AuthGate } from './components/auth/AuthGate';
256
-
257
- /**
258
- * NetSuite project entry point. KEEP <AuthGate> as the outermost element --
259
- * removing it disables real OAuth and exposes NetSuite data to anonymous
260
- * users. Build your dashboard / pages inside the gate.
261
- */
262
- export default function App() {
263
- return (
264
- <AuthGate>
265
- <div className="min-h-screen bg-background text-foreground p-8">
266
- <h1 className="text-2xl font-bold">You are signed in to NetSuite.</h1>
267
- <p className="text-muted-foreground mt-2">
268
- Replace this placeholder with your dashboard.
269
- </p>
270
- </div>
271
- </AuthGate>
272
- );
273
- }
274
- `;
275
- }
276
-
277
343
  export const setupNetsuite = tool({
278
344
  description:
279
- "Bootstrap a NetSuite-backed React + Vite + Tailwind project in one call. " +
280
- "Writes the full HelloLeo base scaffold AND the NetSuite OAuth wiring " +
281
- "(src/lib/netsuite.ts, src/components/auth/{SignInWithNetSuite,LoginPage,AuthGate}.tsx, " +
282
- "src/App.tsx wrapped in <AuthGate>). " +
345
+ "Bootstrap a NetSuite-backed React + Vite + Tailwind v4 + TanStack Router " +
346
+ "project in one call. Writes the full HelloLeo base scaffold PLUS the " +
347
+ "NetSuite OAuth wiring, all ADDITIVE -- it never overwrites a scaffold " +
348
+ "file. Adds src/lib/netsuite.ts (OAuth client), src/lib/auth.tsx " +
349
+ "(NetSuiteAuthProvider + useNetSuiteAuth), and " +
350
+ "src/components/auth/{AuthLayout,LoginPage,SignInWithNetSuite}.tsx. " +
283
351
  "Use this INSTEAD of `scaffold` for any project that needs NetSuite. " +
284
- "Uses default theme (Inter font, blue primary, 0.5rem radius) -- edit " +
285
- "src/index.css afterwards to customise. Real OAuth is wired from day " +
286
- "one -- never replace the gate with a password placeholder.",
352
+ "After it runs there is exactly ONE manual step: wrap the root route's " +
353
+ "<Outlet /> with <AuthLayout> in src/routes/__root.tsx (the tool's output " +
354
+ "shows the snippet). Real OAuth is wired from day one -- never replace " +
355
+ "<AuthLayout> with a password placeholder.",
287
356
  args: {},
288
357
  async execute(_args, context) {
289
358
  const dir = context.directory;
@@ -293,55 +362,67 @@ export const setupNetsuite = tool({
293
362
  recursive: true,
294
363
  });
295
364
 
365
+ // All additive -- nothing the base scaffold wrote is touched.
296
366
  const nsFiles: [string, string][] = [
297
367
  [path.join("src", "lib", "netsuite.ts"), netsuiteTs()],
368
+ [path.join("src", "lib", "auth.tsx"), authTsx()],
298
369
  [
299
- path.join("src", "components", "auth", "SignInWithNetSuite.tsx"),
300
- signInButtonTsx(),
370
+ path.join("src", "components", "auth", "AuthLayout.tsx"),
371
+ authLayoutTsx(),
301
372
  ],
302
373
  [
303
374
  path.join("src", "components", "auth", "LoginPage.tsx"),
304
375
  netsuiteLoginPageTsx(),
305
376
  ],
306
377
  [
307
- path.join("src", "components", "auth", "AuthGate.tsx"),
308
- netsuiteAuthGateTsx(),
378
+ path.join("src", "components", "auth", "SignInWithNetSuite.tsx"),
379
+ signInButtonTsx(),
309
380
  ],
310
- [path.join("src", "App.tsx"), netsuiteAppTsx()],
311
381
  ];
312
382
 
313
- const nsCreated: string[] = [];
314
383
  for (const [filePath, content] of nsFiles) {
315
384
  await Bun.write(path.join(dir, filePath), content);
316
- nsCreated.push(filePath);
317
385
  }
318
386
 
319
- const all = [...base, ...nsCreated];
387
+ const all = [...base, ...nsFiles.map(([f]) => f)];
320
388
  return [
321
- `Scaffolded ${all.length} files (base + NetSuite OAuth):`,
322
- ...all.map((f) => ` - ${f}`),
389
+ `Generated ${all.length} files (base scaffold + NetSuite OAuth, all additive -- nothing overwritten).`,
390
+ "",
391
+ "All you need to do is wrap the root layout with the auth layout.",
392
+ "In src/routes/__root.tsx, import AuthLayout and wrap <Outlet />:",
393
+ "",
394
+ " import { AuthLayout } from '../components/auth/AuthLayout'",
395
+ "",
396
+ " function RootComponent() {",
397
+ " return (",
398
+ " <>",
399
+ " <AuthLayout>",
400
+ " <Outlet />",
401
+ " </AuthLayout>",
402
+ " {/* keep the existing <TanStackDevtools ... /> here */}",
403
+ " </>",
404
+ " )",
405
+ " }",
406
+ "",
407
+ "That single wrap gates every route: <LoginPage /> until the user signs",
408
+ "in with NetSuite, your routes after. Read the session anywhere below it",
409
+ "with useNetSuiteAuth() from src/lib/auth.tsx. NEVER swap <AuthLayout>",
410
+ "for a password gate -- real OAuth is the only supported login.",
323
411
  "",
324
- "Next: build your dashboard INSIDE <AuthGate> in src/App.tsx.",
325
- "Design system reference: read the header comment in src/index.css",
326
- " before adding tokens or styling primitives.",
412
+ "NetSuite OAuth files written:",
413
+ " - src/lib/netsuite.ts OAuth client (signIn / session / workerFetch)",
414
+ " - src/lib/auth.tsx NetSuiteAuthProvider + useNetSuiteAuth",
415
+ " - src/components/auth/AuthLayout.tsx provider + gate (wrap root with this)",
416
+ " - src/components/auth/LoginPage.tsx unauthenticated view",
417
+ " - src/components/auth/SignInWithNetSuite.tsx sign-in button",
327
418
  "",
328
- "NetSuite auth -- already wired:",
329
- " - App.tsx wraps everything in <AuthGate>. NEVER remove the gate",
330
- " or build a password placeholder -- real OAuth is the only login.",
331
- " - LoginPage.tsx + SignInWithNetSuite.tsx are the unauthenticated",
332
- " view. Customise the copy / imagery, keep <SignInWithNetSuite/>",
333
- " as the call-to-action.",
334
- " - signInWithNetSuite() in src/lib/netsuite.ts hits the Worker at",
335
- " /auth/netsuite/start. Deploy the Worker via cloudflare-backend",
336
- " MCP with routes:",
419
+ "Worker (deploy via cloudflare-backend MCP) must serve:",
337
420
  " GET /auth/netsuite/start -- redirect to NetSuite OAuth",
338
421
  " GET /auth/netsuite/callback -- code -> token exchange",
339
- " GET /api/me -- current session",
422
+ " GET /api/me -- current session",
340
423
  " POST /auth/netsuite/logout -- clear session",
341
- " Worker reads env.NETSUITE_ACCOUNT_ID, env.NETSUITE_CLIENT_ID,",
342
- " env.NETSUITE_CLIENT_SECRET (set by the runtime-setup wizard).",
343
- " - VITE_WORKER_URL must be set so the frontend knows where to",
344
- " send users. The HelloLeo Cloud provisioner seeds this.",
424
+ " Reads env.NETSUITE_ACCOUNT_ID / _CLIENT_ID / _CLIENT_SECRET.",
425
+ " VITE_WORKER_URL must be set (HelloLeo Cloud provisioner seeds it).",
345
426
  ].join("\n");
346
427
  },
347
428
  });