@xanots/sdk 0.0.3-beta.0 → 0.0.4
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/CHANGELOG.md +80 -0
- package/README.md +35 -2
- package/dist/agent-file-refresh-IJ7GN2FJ.js +17 -0
- package/dist/bin.js +12 -153
- package/dist/{capture-HUV5BNTC.js → capture-7PO6SGB4.js} +2 -2
- package/dist/{chunk-WRYT2PAX.js → chunk-7SISR3CS.js} +24 -36
- package/dist/{chunk-7DKX2SPN.js → chunk-ACQCK4DT.js} +4 -4
- package/dist/{chunk-XQ22GLYS.js → chunk-AJ7JQ4OU.js} +5 -5
- package/dist/{chunk-EWFHDJY5.js → chunk-ALNQCWAW.js} +2 -2
- package/dist/{chunk-55VHDNW5.js → chunk-BPEEGJJA.js} +108 -3
- package/dist/{chunk-U3G2UW65.js → chunk-CYJ7R3AD.js} +3 -3
- package/dist/{agent-file-refresh-J3KY54E5.js → chunk-D6OGU2AI.js} +5 -6
- package/dist/{chunk-VVXPK6SE.js → chunk-DUC3PXDG.js} +150 -45
- package/dist/{chunk-4HKZH6YK.js → chunk-EAIR6VUL.js} +235 -10
- package/dist/chunk-ERQZFWIW.js +22 -0
- package/dist/{chunk-TQUO2OXY.js → chunk-FN4OQT2J.js} +4 -4
- package/dist/{chunk-FY6LXRR6.js → chunk-KGNJM4LN.js} +2 -2
- package/dist/{chunk-HJPTWBLH.js → chunk-MFIHIS6B.js} +2 -2
- package/dist/{chunk-F6JCFRKO.js → chunk-PXXLBXOP.js} +2 -2
- package/dist/{chunk-YZ4GU6F5.js → chunk-QUUB7HYK.js} +5 -838
- package/dist/{chunk-HKAX756N.js → chunk-SWIXWJIY.js} +3 -3
- package/dist/{chunk-76QBEIGO.js → chunk-T4XPCJRF.js} +3 -2
- package/dist/chunk-T6N3VMMO.js +173 -0
- package/dist/{chunk-CBL57QBQ.js → chunk-VKD3EBKG.js} +112 -21
- package/dist/{chunk-MWLNBSTY.js → chunk-VWGJQTNA.js} +3 -3
- package/dist/chunk-WGDAOOXG.js +845 -0
- package/dist/{chunk-4YMD2OOZ.js → chunk-XHEXOES3.js} +1 -1
- package/dist/{chunk-4HT3BNZ7.js → chunk-YUBJLB6G.js} +10 -2
- package/dist/{chunk-5L4X5LS6.js → chunk-YUPQOLFX.js} +77 -2
- package/dist/{chunk-QO4I5OYF.js → chunk-YYSJAAJM.js} +36 -3
- package/dist/{chunk-P3TTMWUP.js → chunk-ZOYMZZ3S.js} +8 -1
- package/dist/chunk-ZSYZTGJH.js +81 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +8 -8
- package/dist/{codegen-command-EXLKZ2ZI.js → codegen-command-Z7WQMOJ7.js} +21 -20
- package/dist/{completion-2PVZK6YX.js → completion-4GYN752B.js} +2 -2
- package/dist/{deploy-command-SXX6RJWM.js → deploy-command-M2S4HHLC.js} +26 -26
- package/dist/{env-target-3EGIPR4D.js → env-target-GSFCYHKZ.js} +6 -6
- package/dist/{ephemeral-command-OGOYP7D6.js → ephemeral-command-6WJW7LP6.js} +24 -24
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -7
- package/dist/init-command-GJUPWTKA.js +30 -0
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +53 -7
- package/dist/{io-AMIKRLPC.js → io-7VIA5SON.js} +3 -3
- package/dist/{live-diff-RXSJCVJ7.js → live-diff-FP4SFNT4.js} +2 -2
- package/dist/{lock-3CVKALKT.js → lock-KXOJIGCG.js} +2 -2
- package/dist/{lock-commands-R22J54XV.js → lock-commands-7IH7RSSP.js} +9 -9
- package/dist/{login-command-ACJF6KWQ.js → login-command-QM5SBBI2.js} +2 -2
- package/dist/{logout-command-MX3MJS5U.js → logout-command-THPASOHM.js} +2 -2
- package/dist/{loop-SAWAOUFO.js → loop-7SAIGRCZ.js} +3 -3
- package/dist/{marketplace-command-XJIWL4YP.js → marketplace-command-463DT7O7.js} +11 -25
- package/dist/meta-client-OW5WKWW7.js +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.js +18 -12
- package/dist/onboard-command-EHOHKQQU.js +36 -0
- package/dist/{profile-command-SWJ3SPKR.js → profile-command-EUWPVWED.js} +6 -6
- package/dist/{release-command-6PLMLGDK.js → release-command-M4CVNTWL.js} +25 -25
- package/dist/{sandbox-details-command-HJE5SPVG.js → sandbox-details-command-BRII3QHG.js} +5 -5
- package/dist/{sandbox-export-command-QCJY4GMV.js → sandbox-export-command-PCZ5FL4U.js} +8 -8
- package/dist/scaffold.js +4 -2
- package/dist/{store-g45zwB33.d.ts → store-BJONDJoZ.d.ts} +171 -2
- package/dist/{test-command-LLPXKT35.js → test-command-U4G5Y3UM.js} +10 -10
- package/dist/upgrade-command-CKJ4BS2P.js +177 -0
- package/dist/{validate-command-WAT3ZJT3.js → validate-command-S5N37JRP.js} +12 -12
- package/dist/{workspace-command-JKMI7RZ4.js → workspace-command-RALSEJSW.js} +28 -27
- package/dist/workspace-export-AJMGN3CQ.js +1 -1
- package/guides/README.md +30 -0
- package/guides/authoring.md +642 -0
- package/guides/cli.md +191 -0
- package/guides/codegen.md +83 -0
- package/guides/coverage.md +67 -0
- package/guides/deploying.md +340 -0
- package/guides/environment.md +132 -0
- package/guides/object-kinds.md +376 -0
- package/guides/project-structure.md +43 -0
- package/guides/scaffold.md +198 -0
- package/guides/typed-frontend.md +201 -0
- package/llms/kinds-agent-mcp.md +2 -1
- package/llms/kinds-knowledge.md +20 -0
- package/llms/object-kinds.md +1 -0
- package/llms-full.txt +27 -3
- package/llms.txt +3 -2
- package/manifest.json +30 -3
- package/package.json +5 -2
- package/dist/.build-fingerprint +0 -1
- package/dist/chunk-47WDWMBJ.js +0 -14
- package/dist/init-command-6DGXEVZD.js +0 -29
|
@@ -4,9 +4,7 @@ import {
|
|
|
4
4
|
fontDependencies,
|
|
5
5
|
fontImports,
|
|
6
6
|
fontThemeVars,
|
|
7
|
-
|
|
8
|
-
orderedTokens,
|
|
9
|
-
reactPreset
|
|
7
|
+
orderedTokens
|
|
10
8
|
} from "./chunk-6DHJVLYP.js";
|
|
11
9
|
|
|
12
10
|
// src/emit/init-templates.ts
|
|
@@ -867,835 +865,8 @@ export const XANO_HOST: string =
|
|
|
867
865
|
`;
|
|
868
866
|
}
|
|
869
867
|
|
|
870
|
-
// src/emit/frontend-svelte.ts
|
|
871
|
-
var CODE_CLASS = "bg-muted rounded px-1.5 py-0.5 font-mono text-sm";
|
|
872
|
-
function htmlText(s) {
|
|
873
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
874
|
-
}
|
|
875
|
-
function svelteText(s) {
|
|
876
|
-
return htmlText(s).replace(/\{/g, "{").replace(/\}/g, "}");
|
|
877
|
-
}
|
|
878
|
-
function renderNode(node) {
|
|
879
|
-
return "code" in node ? `<code class="${CODE_CLASS}">${svelteText(node.code)}</code>` : svelteText(node.text);
|
|
880
|
-
}
|
|
881
|
-
function renderNodes(nodes) {
|
|
882
|
-
return nodes.map(renderNode).join("");
|
|
883
|
-
}
|
|
884
|
-
function renderApp(landing, choice) {
|
|
885
|
-
const steps = landing.steps.map((step) => ` <li>${renderNodes(step)}</li>`).join("\n");
|
|
886
|
-
const toggle = choice.dark === "toggle";
|
|
887
|
-
const icons = iconLibraryOf(choice.icons).svelte;
|
|
888
|
-
return `<script lang="ts">
|
|
889
|
-
${icons.arrowImport}
|
|
890
|
-
|
|
891
|
-
import { Button } from "$lib/components/ui/button/index.js";
|
|
892
|
-
import * as Card from "$lib/components/ui/card/index.js";${toggle ? `
|
|
893
|
-
import ModeToggle from "$lib/components/mode-toggle.svelte";` : ""}
|
|
894
|
-
</script>
|
|
895
|
-
|
|
896
|
-
<main class="mx-auto flex min-h-screen max-w-2xl flex-col justify-center p-8">${toggle ? `
|
|
897
|
-
<div class="mb-4 flex justify-end">
|
|
898
|
-
<ModeToggle />
|
|
899
|
-
</div>` : ""}
|
|
900
|
-
<Card.Root>
|
|
901
|
-
<Card.Header>
|
|
902
|
-
<Card.Title class="text-3xl tracking-tight">${svelteText(landing.title)}</Card.Title>
|
|
903
|
-
<Card.Description class="text-base">
|
|
904
|
-
${renderNodes(landing.lead)}
|
|
905
|
-
</Card.Description>
|
|
906
|
-
</Card.Header>
|
|
907
|
-
<Card.Content>
|
|
908
|
-
<ol class="text-muted-foreground list-inside list-decimal space-y-2">
|
|
909
|
-
${steps}
|
|
910
|
-
</ol>
|
|
911
|
-
</Card.Content>
|
|
912
|
-
<Card.Footer>
|
|
913
|
-
<!-- Components come from shadcn-svelte \u2014 add more with
|
|
914
|
-
\`npx shadcn-svelte@latest add <name>\`. -->
|
|
915
|
-
<Button href="${landing.cta.href}" target="_blank" rel="noreferrer">
|
|
916
|
-
${svelteText(landing.cta.label)}
|
|
917
|
-
<${icons.arrowComponent} />
|
|
918
|
-
</Button>
|
|
919
|
-
</Card.Footer>
|
|
920
|
-
</Card.Root>
|
|
921
|
-
</main>
|
|
922
|
-
`;
|
|
923
|
-
}
|
|
924
|
-
function renderSvelteKitPlugin() {
|
|
925
|
-
return `sveltekit({
|
|
926
|
-
// RUNES MODE, FORCED \u2014 not left to Svelte 5's per-component detection.
|
|
927
|
-
//
|
|
928
|
-
// By default a component that uses \`export let\` and \`<slot>\` simply
|
|
929
|
-
// compiles in legacy mode and works, so the Svelte 4 API an assistant
|
|
930
|
-
// reaches for from older training data produces no error at all. Pinning
|
|
931
|
-
// runes here turns that into a compile failure naming the file, which is
|
|
932
|
-
// the same guidance the agent brief gives, enforced instead of stated.
|
|
933
|
-
//
|
|
934
|
-
// \`node_modules\` is exempted (returning undefined restores detection):
|
|
935
|
-
// an installed library compiles under whatever mode ITS author wrote for,
|
|
936
|
-
// and forcing ours onto it would break dependencies this project does not
|
|
937
|
-
// own. Removable in Svelte 6, where runes stop being opt-in.
|
|
938
|
-
compilerOptions: {
|
|
939
|
-
runes: ({ filename }) =>
|
|
940
|
-
filename.split(/[/\\\\]/).includes("node_modules") ? undefined : true,
|
|
941
|
-
},
|
|
942
|
-
// No \`preprocess\`. vite-plugin-svelte 7 compiles \`<script lang="ts">\`
|
|
943
|
-
// itself, so \`vitePreprocess()\` is the no-op it looks like \u2014 \`sv create\`
|
|
944
|
-
// emits none either. Verified against a real build: components typecheck
|
|
945
|
-
// and compile without it.
|
|
946
|
-
//
|
|
947
|
-
// The deploy target is a static host with NO server runtime \u2014 Xano is the
|
|
948
|
-
// backend. Routes are PRERENDERED (see frontend/src/routes/+layout.ts):
|
|
949
|
-
// each becomes its own HTML file at build time, and the host resolves a URL
|
|
950
|
-
// to it by trying the exact key, then \`{path}.html\`, then
|
|
951
|
-
// \`{path}/index.html\`. That is why no \`trailingSlash\` is configured \u2014 both
|
|
952
|
-
// output shapes resolve, so this stays on SvelteKit's default.
|
|
953
|
-
//
|
|
954
|
-
// NO \`fallback\`. It looks harmless \u2014 it used to be how every URL got served
|
|
955
|
-
// \u2014 but adapter-static writes the fallback shell AT index.html, overwriting
|
|
956
|
-
// the prerendered home page with an empty document. Measured on a real
|
|
957
|
-
// build: 1936 bytes of empty shell instead of 4920 bytes of rendered page,
|
|
958
|
-
// on the most-visited route in the app.
|
|
959
|
-
//
|
|
960
|
-
// Dropping it also gets the better failure. With no fallback, adapter-static
|
|
961
|
-
// is \`strict\` by default, so a route it cannot prerender (a dynamic \`[id]\`
|
|
962
|
-
// with no \`entries\`) FAILS THE BUILD with a message naming the route \u2014
|
|
963
|
-
// instead of shipping and 404ing for real users.
|
|
964
|
-
//
|
|
965
|
-
// \`xanots deploy --static-env\` still finds its anchor: every prerendered
|
|
966
|
-
// route renders from app.html, so each document has a <head> and each one
|
|
967
|
-
// gets the injected globals.
|
|
968
|
-
adapter: adapter({
|
|
969
|
-
pages: "frontend/dist",
|
|
970
|
-
assets: "frontend/dist",
|
|
971
|
-
precompress: false,
|
|
972
|
-
}),
|
|
973
|
-
// Absolute asset URLs, pinned rather than left to the default. Prerendered
|
|
974
|
-
// pages live at varying URL depths, and a relative \`../_app/\u2026\` computed for
|
|
975
|
-
// one depth 404s at another.
|
|
976
|
-
paths: { relative: false },
|
|
977
|
-
prerender: {
|
|
978
|
-
// A hash link in the shared layout \u2014 \`<a href="#services">\`, the default
|
|
979
|
-
// shape of a one-page site's nav \u2014 renders into EVERY prerendered route,
|
|
980
|
-
// including the scaffold's own /404. There it resolves to /404#services,
|
|
981
|
-
// an anchor that by definition is not on that page, and SvelteKit's
|
|
982
|
-
// default handler THROWS: the vite build succeeds and the prerender pass
|
|
983
|
-
// after it kills the build, with a stack trace naming only files inside
|
|
984
|
-
// node_modules and a route the author never wrote.
|
|
985
|
-
//
|
|
986
|
-
// So ignore a missing id on /404 specifically, rather than reaching for a
|
|
987
|
-
// blanket \`handleMissingId: "warn"\`. A hash link that is genuinely broken
|
|
988
|
-
// on a real route still fails the build, which is the check worth keeping.
|
|
989
|
-
handleMissingId: ({ path, message }) => {
|
|
990
|
-
if (path === "/404") return;
|
|
991
|
-
throw new Error(message);
|
|
992
|
-
},
|
|
993
|
-
},
|
|
994
|
-
// SvelteKit's project layout, redirected under frontend/ so this stays a
|
|
995
|
-
// single-root project: one package.json, one tsconfig.json, and xano/
|
|
996
|
-
// sitting alongside as the backend half. NOTE these are what make
|
|
997
|
-
// frontend/src/routes the routes directory \u2014 a file added under a
|
|
998
|
-
// top-level src/routes/ is not a route and will not be served.
|
|
999
|
-
files: {
|
|
1000
|
-
routes: "frontend/src/routes",
|
|
1001
|
-
lib: "frontend/src/lib",
|
|
1002
|
-
appTemplate: "frontend/src/app.html",
|
|
1003
|
-
assets: "frontend/static",
|
|
1004
|
-
},
|
|
1005
|
-
})`;
|
|
1006
|
-
}
|
|
1007
|
-
function renderAppHtml({ appName }, choice) {
|
|
1008
|
-
return `<!doctype html>
|
|
1009
|
-
<html lang="en">
|
|
1010
|
-
<head>
|
|
1011
|
-
<meta charset="utf-8" />
|
|
1012
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1013
|
-
<title>${htmlText(appName)}</title>
|
|
1014
|
-
${renderThemeScript(choice.dark)}
|
|
1015
|
-
<!-- Drop a favicon.png into frontend/static/ and link it here:
|
|
1016
|
-
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
|
1017
|
-
Everything in that directory is copied to the site root verbatim. -->
|
|
1018
|
-
<!-- Keep this inside <head>: \`xanots deploy --static-env\` injects the
|
|
1019
|
-
backend URL here as a window global that frontend/src/lib/api.ts reads. -->
|
|
1020
|
-
%sveltekit.head%
|
|
1021
|
-
</head>
|
|
1022
|
-
<body data-sveltekit-preload-data="hover">
|
|
1023
|
-
<div style="display: contents">%sveltekit.body%</div>
|
|
1024
|
-
</body>
|
|
1025
|
-
</html>
|
|
1026
|
-
`;
|
|
1027
|
-
}
|
|
1028
|
-
function renderModeToggleSvelte(icons) {
|
|
1029
|
-
return `<script lang="ts">
|
|
1030
|
-
${icons.modeImports.join("\n ")}
|
|
1031
|
-
|
|
1032
|
-
import { Button } from "$lib/components/ui/button/index.js";
|
|
1033
|
-
import { getMode, setMode, watchMode, type Mode } from "$lib/theme.js";
|
|
1034
|
-
|
|
1035
|
-
/** system \u2192 light \u2192 dark \u2192 system. */
|
|
1036
|
-
const next: Record<Mode, Mode> = { system: "light", light: "dark", dark: "system" };
|
|
1037
|
-
|
|
1038
|
-
const icons = {
|
|
1039
|
-
system: ${icons.modeComponents.system},
|
|
1040
|
-
light: ${icons.modeComponents.light},
|
|
1041
|
-
dark: ${icons.modeComponents.dark},
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
// Starts at "system" so the prerendered HTML is deterministic; the effect
|
|
1045
|
-
// corrects it in the browser, after the inline script has already applied
|
|
1046
|
-
// the right class.
|
|
1047
|
-
let mode = $state<Mode>("system");
|
|
1048
|
-
|
|
1049
|
-
$effect(() => {
|
|
1050
|
-
mode = getMode();
|
|
1051
|
-
return watchMode((m) => (mode = m));
|
|
1052
|
-
});
|
|
1053
|
-
|
|
1054
|
-
function change() {
|
|
1055
|
-
const target = next[mode];
|
|
1056
|
-
setMode(target);
|
|
1057
|
-
mode = target;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
const Icon = $derived(icons[mode]);
|
|
1061
|
-
</script>
|
|
1062
|
-
|
|
1063
|
-
<Button variant="ghost" size="icon" onclick={change} aria-label="Switch to {next[mode]} theme">
|
|
1064
|
-
<Icon />
|
|
1065
|
-
</Button>
|
|
1066
|
-
`;
|
|
1067
|
-
}
|
|
1068
|
-
function renderAppDts() {
|
|
1069
|
-
return `// See https://svelte.dev/docs/kit/types#app.d.ts
|
|
1070
|
-
declare global {
|
|
1071
|
-
namespace App {
|
|
1072
|
-
// interface Error {}
|
|
1073
|
-
// interface Locals {}
|
|
1074
|
-
// interface PageData {}
|
|
1075
|
-
// interface PageState {}
|
|
1076
|
-
// interface Platform {}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
export {};
|
|
1081
|
-
`;
|
|
1082
|
-
}
|
|
1083
|
-
function renderLayoutTs() {
|
|
1084
|
-
return `// There is no server. The backend is Xano, reached through $lib/api.ts,
|
|
1085
|
-
// and \`npm run xano:deploy\` ships this app to a static host with no runtime.
|
|
1086
|
-
//
|
|
1087
|
-
// prerender: true \u2014 every route is rendered to its own HTML file AT BUILD TIME
|
|
1088
|
-
// and served as a real document. That is what makes each page load as itself
|
|
1089
|
-
// rather than as an empty shell that fills in afterwards.
|
|
1090
|
-
//
|
|
1091
|
-
// Prerendering IS server-rendering, just at build time rather than per request.
|
|
1092
|
-
// So module-scope \`window\`/\`document\` access now fails the BUILD instead of the
|
|
1093
|
-
// browser \u2014 which is the better place to find out. Reach for browser globals
|
|
1094
|
-
// inside onMount, or guard with \`import { browser } from "$app/environment"\`.
|
|
1095
|
-
//
|
|
1096
|
-
// A route with dynamic segments (e.g. /posts/[id]) cannot be prerendered unless
|
|
1097
|
-
// the build knows which ones exist, so THE BUILD FAILS and names the route.
|
|
1098
|
-
// That is deliberate \u2014 better than shipping a page that 404s for real users.
|
|
1099
|
-
// Give it entries, in that route's +page.ts:
|
|
1100
|
-
//
|
|
1101
|
-
// export const entries = () => [{ id: "1" }, { id: "2" }];
|
|
1102
|
-
//
|
|
1103
|
-
// Inherited by every route below this one.
|
|
1104
|
-
export const prerender = true;
|
|
1105
|
-
`;
|
|
1106
|
-
}
|
|
1107
|
-
function renderErrorState() {
|
|
1108
|
-
return `<script lang="ts">
|
|
1109
|
-
// Shared by the prerendered /404 route and +error.svelte.
|
|
1110
|
-
let { status = 404, message = "" }: { status?: number; message?: string } = $props();
|
|
1111
|
-
</script>
|
|
1112
|
-
|
|
1113
|
-
<main class="grid min-h-screen place-items-center p-8">
|
|
1114
|
-
<div class="max-w-md space-y-4 text-center">
|
|
1115
|
-
<p class="text-6xl font-semibold tracking-tight">{status}</p>
|
|
1116
|
-
<h1 class="text-xl font-medium">
|
|
1117
|
-
{status === 404 ? "We can't find that page." : "Something went wrong."}
|
|
1118
|
-
</h1>
|
|
1119
|
-
<p class="text-muted-foreground text-sm">
|
|
1120
|
-
{message !== "" ? message : "The link may be broken, or the page may have moved."}
|
|
1121
|
-
</p>
|
|
1122
|
-
<a
|
|
1123
|
-
href="/"
|
|
1124
|
-
class="bg-primary text-primary-foreground ring-offset-background focus-visible:ring-ring inline-flex h-10 items-center rounded-md px-5 text-sm font-medium transition-opacity hover:opacity-90 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
|
|
1125
|
-
>
|
|
1126
|
-
Back to safety
|
|
1127
|
-
</a>
|
|
1128
|
-
</div>
|
|
1129
|
-
</main>
|
|
1130
|
-
`;
|
|
1131
|
-
}
|
|
1132
|
-
function renderNotFoundRoute() {
|
|
1133
|
-
return `<script lang="ts">
|
|
1134
|
-
// Prerendered to 404.html, which is what tells the static host to answer an
|
|
1135
|
-
// unmatched path with a real 404 instead of quietly serving the app shell
|
|
1136
|
-
// with a 200 (a missing asset would then reach the browser as HTML, which it
|
|
1137
|
-
// reports as "Unexpected token '<'").
|
|
1138
|
-
//
|
|
1139
|
-
// It must be a route, not +error.svelte: SvelteKit never prerenders the error
|
|
1140
|
-
// component to a file, so relying on it would ship no 404.html at all.
|
|
1141
|
-
//
|
|
1142
|
-
// Delete this directory and an unmatched path serves the home page with a 200
|
|
1143
|
-
// instead \u2014 which is worse, not better, so keep it unless you have a reason.
|
|
1144
|
-
import ErrorState from "$lib/components/error-state.svelte";
|
|
1145
|
-
</script>
|
|
1146
|
-
|
|
1147
|
-
<svelte:head>
|
|
1148
|
-
<title>Page not found</title>
|
|
1149
|
-
</svelte:head>
|
|
1150
|
-
|
|
1151
|
-
<ErrorState status={404} />
|
|
1152
|
-
`;
|
|
1153
|
-
}
|
|
1154
|
-
function renderErrorSvelte() {
|
|
1155
|
-
return `<script lang="ts">
|
|
1156
|
-
// Rendered when a client-side navigation or load fails inside the running
|
|
1157
|
-
// app. The static host never sees these \u2014 for a path that matched no
|
|
1158
|
-
// document at all, it serves the prerendered routes/404 page instead.
|
|
1159
|
-
import { page } from "$app/state";
|
|
1160
|
-
import ErrorState from "$lib/components/error-state.svelte";
|
|
1161
|
-
</script>
|
|
1162
|
-
|
|
1163
|
-
<svelte:head>
|
|
1164
|
-
<title>{page.status === 404 ? "Page not found" : "Something went wrong"}</title>
|
|
1165
|
-
</svelte:head>
|
|
1166
|
-
|
|
1167
|
-
<ErrorState status={page.status} message={page.error?.message ?? ""} />
|
|
1168
|
-
`;
|
|
1169
|
-
}
|
|
1170
|
-
function renderLayoutSvelte() {
|
|
1171
|
-
return `<script lang="ts">
|
|
1172
|
-
// The shared token stylesheet \u2014 semantic colors (bg-primary,
|
|
1173
|
-
// text-muted-foreground) plus the Tailwind v4 theme. Imported once here so
|
|
1174
|
-
// every route gets it.
|
|
1175
|
-
import "../index.css";
|
|
1176
|
-
|
|
1177
|
-
let { children } = $props();
|
|
1178
|
-
</script>
|
|
1179
|
-
|
|
1180
|
-
{@render children()}
|
|
1181
|
-
`;
|
|
1182
|
-
}
|
|
1183
|
-
function renderComponentsJson(choice) {
|
|
1184
|
-
const config = {
|
|
1185
|
-
$schema: "https://shadcn-svelte.com/schema.json",
|
|
1186
|
-
tailwind: {
|
|
1187
|
-
// v4 has no config file; the theme lives in the stylesheet — the same
|
|
1188
|
-
// shared one the React preset points at.
|
|
1189
|
-
css: "frontend/src/index.css",
|
|
1190
|
-
// Tracks the theme the stylesheet was rendered from — see the React
|
|
1191
|
-
// preset's note; the shadcn-svelte CLI reads it the same way.
|
|
1192
|
-
baseColor: choice.theme.baseColor ?? "neutral"
|
|
1193
|
-
},
|
|
1194
|
-
aliases: {
|
|
1195
|
-
components: "$lib/components",
|
|
1196
|
-
utils: "$lib/utils",
|
|
1197
|
-
ui: "$lib/components/ui",
|
|
1198
|
-
hooks: "$lib/hooks",
|
|
1199
|
-
lib: "$lib"
|
|
1200
|
-
},
|
|
1201
|
-
typescript: true,
|
|
1202
|
-
registry: "https://shadcn-svelte.com/registry"
|
|
1203
|
-
};
|
|
1204
|
-
return JSON.stringify(config, null, 2) + "\n";
|
|
1205
|
-
}
|
|
1206
|
-
function renderButtonSvelte() {
|
|
1207
|
-
return `<script lang="ts" module>
|
|
1208
|
-
import { type VariantProps, tv } from "tailwind-variants";
|
|
1209
|
-
|
|
1210
|
-
export const buttonVariants = tv({
|
|
1211
|
-
base: "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1212
|
-
variants: {
|
|
1213
|
-
variant: {
|
|
1214
|
-
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1215
|
-
destructive:
|
|
1216
|
-
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
|
1217
|
-
outline:
|
|
1218
|
-
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
1219
|
-
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1220
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
1221
|
-
link: "text-primary underline-offset-4 hover:underline",
|
|
1222
|
-
},
|
|
1223
|
-
size: {
|
|
1224
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
1225
|
-
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
|
1226
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
1227
|
-
icon: "size-9",
|
|
1228
|
-
},
|
|
1229
|
-
},
|
|
1230
|
-
defaultVariants: {
|
|
1231
|
-
variant: "default",
|
|
1232
|
-
size: "default",
|
|
1233
|
-
},
|
|
1234
|
-
});
|
|
1235
|
-
|
|
1236
|
-
export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
|
|
1237
|
-
export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
|
|
1238
|
-
|
|
1239
|
-
export type ButtonProps = WithElementRef<HTMLButtonAttributes> &
|
|
1240
|
-
WithElementRef<HTMLAnchorAttributes> & {
|
|
1241
|
-
variant?: ButtonVariant;
|
|
1242
|
-
size?: ButtonSize;
|
|
1243
|
-
};
|
|
1244
|
-
</script>
|
|
1245
|
-
|
|
1246
|
-
<script lang="ts">
|
|
1247
|
-
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from "svelte/elements";
|
|
1248
|
-
import type { WithElementRef } from "bits-ui";
|
|
1249
|
-
import { cn } from "$lib/utils.js";
|
|
1250
|
-
|
|
1251
|
-
let {
|
|
1252
|
-
class: className,
|
|
1253
|
-
variant = "default",
|
|
1254
|
-
size = "default",
|
|
1255
|
-
ref = $bindable(null),
|
|
1256
|
-
href = undefined,
|
|
1257
|
-
type = "button",
|
|
1258
|
-
children,
|
|
1259
|
-
...restProps
|
|
1260
|
-
}: ButtonProps = $props();
|
|
1261
|
-
</script>
|
|
1262
|
-
|
|
1263
|
-
{#if href}
|
|
1264
|
-
<a
|
|
1265
|
-
bind:this={ref}
|
|
1266
|
-
data-slot="button"
|
|
1267
|
-
class={cn(buttonVariants({ variant, size }), className)}
|
|
1268
|
-
{href}
|
|
1269
|
-
{...restProps}
|
|
1270
|
-
>
|
|
1271
|
-
{@render children?.()}
|
|
1272
|
-
</a>
|
|
1273
|
-
{:else}
|
|
1274
|
-
<button
|
|
1275
|
-
bind:this={ref}
|
|
1276
|
-
data-slot="button"
|
|
1277
|
-
class={cn(buttonVariants({ variant, size }), className)}
|
|
1278
|
-
{type}
|
|
1279
|
-
{...restProps}
|
|
1280
|
-
>
|
|
1281
|
-
{@render children?.()}
|
|
1282
|
-
</button>
|
|
1283
|
-
{/if}
|
|
1284
|
-
`;
|
|
1285
|
-
}
|
|
1286
|
-
function renderButtonIndex() {
|
|
1287
|
-
return `export {
|
|
1288
|
-
default as Button,
|
|
1289
|
-
buttonVariants,
|
|
1290
|
-
type ButtonProps,
|
|
1291
|
-
type ButtonSize,
|
|
1292
|
-
type ButtonVariant,
|
|
1293
|
-
} from "./button.svelte";
|
|
1294
|
-
`;
|
|
1295
|
-
}
|
|
1296
|
-
function cardPart(slot, tag, classes) {
|
|
1297
|
-
return `<script lang="ts">
|
|
1298
|
-
import type { HTMLAttributes } from "svelte/elements";
|
|
1299
|
-
import type { WithElementRef } from "bits-ui";
|
|
1300
|
-
import { cn } from "$lib/utils.js";
|
|
1301
|
-
|
|
1302
|
-
let {
|
|
1303
|
-
class: className,
|
|
1304
|
-
ref = $bindable(null),
|
|
1305
|
-
children,
|
|
1306
|
-
...restProps
|
|
1307
|
-
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
|
1308
|
-
</script>
|
|
1309
|
-
|
|
1310
|
-
<${tag}
|
|
1311
|
-
bind:this={ref}
|
|
1312
|
-
data-slot="${slot}"
|
|
1313
|
-
class={cn("${classes}", className)}
|
|
1314
|
-
{...restProps}
|
|
1315
|
-
>
|
|
1316
|
-
{@render children?.()}
|
|
1317
|
-
</${tag}>
|
|
1318
|
-
`;
|
|
1319
|
-
}
|
|
1320
|
-
function renderCardIndex() {
|
|
1321
|
-
return `import Root from "./card.svelte";
|
|
1322
|
-
import Content from "./card-content.svelte";
|
|
1323
|
-
import Description from "./card-description.svelte";
|
|
1324
|
-
import Footer from "./card-footer.svelte";
|
|
1325
|
-
import Header from "./card-header.svelte";
|
|
1326
|
-
import Title from "./card-title.svelte";
|
|
1327
|
-
|
|
1328
|
-
export {
|
|
1329
|
-
Root,
|
|
1330
|
-
Content,
|
|
1331
|
-
Description,
|
|
1332
|
-
Footer,
|
|
1333
|
-
Header,
|
|
1334
|
-
Title,
|
|
1335
|
-
//
|
|
1336
|
-
Root as Card,
|
|
1337
|
-
Content as CardContent,
|
|
1338
|
-
Description as CardDescription,
|
|
1339
|
-
Footer as CardFooter,
|
|
1340
|
-
Header as CardHeader,
|
|
1341
|
-
Title as CardTitle,
|
|
1342
|
-
};
|
|
1343
|
-
`;
|
|
1344
|
-
}
|
|
1345
|
-
var sveltePreset = {
|
|
1346
|
-
id: "svelte",
|
|
1347
|
-
label: "SvelteKit",
|
|
1348
|
-
dependencies: {
|
|
1349
|
-
// shadcn-svelte's runtime surface. `bits-ui` is the headless primitive
|
|
1350
|
-
// library its components are built on (the Radix equivalent), and
|
|
1351
|
-
// `tailwind-variants` types the variants (the cva equivalent). clsx +
|
|
1352
|
-
// tailwind-merge back `cn()` exactly as in the React preset. Pre-installed
|
|
1353
|
-
// so `npx shadcn-svelte@latest add <component>` works without a separate
|
|
1354
|
-
// npm i.
|
|
1355
|
-
//
|
|
1356
|
-
// The icon package is `--icons`, merged in by renderPackageJson from
|
|
1357
|
-
// `iconBinding` below — see the React preset's note.
|
|
1358
|
-
"bits-ui": "^2.18.1",
|
|
1359
|
-
clsx: "^2.1.1",
|
|
1360
|
-
"tailwind-merge": "^3.0.1",
|
|
1361
|
-
"tailwind-variants": "^3.3.1"
|
|
1362
|
-
},
|
|
1363
|
-
devDependencies: {
|
|
1364
|
-
// Writes the static bundle `deploy --static` ships. Peer-depends on kit ^2.
|
|
1365
|
-
"@sveltejs/adapter-static": "^3.0.10",
|
|
1366
|
-
// 2.70 peer-accepts vite ^8 and vite-plugin-svelte ^7 — the versions
|
|
1367
|
-
// pinned below. Bump this line and those two together.
|
|
1368
|
-
"@sveltejs/kit": "^2.70.2",
|
|
1369
|
-
// 7.x, matching what `sv create` installs. It peer-requires vite ^8, so
|
|
1370
|
-
// this line and the `vite` pin move together or not at all — and the React
|
|
1371
|
-
// preset's plugin has the same constraint, which is why the two presets
|
|
1372
|
-
// share one Vite major rather than each choosing.
|
|
1373
|
-
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
1374
|
-
"@tailwindcss/vite": "^4.1.5",
|
|
1375
|
-
"@types/node": "^20.19.43",
|
|
1376
|
-
svelte: "^5.56.9",
|
|
1377
|
-
"svelte-check": "^4.7.6",
|
|
1378
|
-
tailwindcss: "^4.1.5",
|
|
1379
|
-
"tw-animate-css": "^1.2.4",
|
|
1380
|
-
tsx: "^4.19.2",
|
|
1381
|
-
// 6.x, the major `sv create` pins. svelte-check peer-accepts `^5 || ^6`;
|
|
1382
|
-
// 7 is out but not yet in that range, so this tracks the canonical
|
|
1383
|
-
// scaffold rather than latest.
|
|
1384
|
-
typescript: "^6.0.3",
|
|
1385
|
-
vite: "^8.0.16"
|
|
1386
|
-
},
|
|
1387
|
-
// svelte-check REPLACES `tsc --noEmit` here rather than joining it.
|
|
1388
|
-
//
|
|
1389
|
-
// It is a superset: reading the same tsconfig, it checks `xano/`'s TypeScript
|
|
1390
|
-
// exactly as `tsc` would AND the components `tsc` cannot parse at all. Running
|
|
1391
|
-
// both is not merely redundant — `tsc` fails outright on the UI kit's barrels,
|
|
1392
|
-
// which re-export types from `.svelte` modules it only knows as default
|
|
1393
|
-
// exports. Verified against a real scaffold: a type error planted in
|
|
1394
|
-
// `xano/index.ts` and one planted in `App.svelte` are each caught by this
|
|
1395
|
-
// command alone.
|
|
1396
|
-
//
|
|
1397
|
-
// `svelte-kit sync` runs first, and is not optional: it generates
|
|
1398
|
-
// `.svelte-kit/tsconfig.json` (which the project's tsconfig extends) and the
|
|
1399
|
-
// route types. Without it svelte-check fails on a missing extends target
|
|
1400
|
-
// rather than on anything the user wrote.
|
|
1401
|
-
checkCmd: "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
1402
|
-
// SvelteKit supplies `$lib` on both sides — the Vite alias from its plugin
|
|
1403
|
-
// and the tsconfig path from the config it generates. Declaring either by
|
|
1404
|
-
// hand would be a second source of truth that can silently disagree.
|
|
1405
|
-
aliasName: null,
|
|
1406
|
-
aliasTarget: "frontend/src/lib",
|
|
1407
|
-
tsconfigPaths: {},
|
|
1408
|
-
tsconfigExtends: "./.svelte-kit/tsconfig.json",
|
|
1409
|
-
// What `svelte-kit sync` generates and the extended config lists — re-added
|
|
1410
|
-
// because our `include` replaces that config's rather than merging with it.
|
|
1411
|
-
// These are the declarations behind `$app/*`, `$env/*`, and `./$types`.
|
|
1412
|
-
tsconfigInclude: [
|
|
1413
|
-
".svelte-kit/ambient.d.ts",
|
|
1414
|
-
".svelte-kit/env.d.ts",
|
|
1415
|
-
".svelte-kit/non-ambient.d.ts",
|
|
1416
|
-
".svelte-kit/types/**/$types.d.ts"
|
|
1417
|
-
],
|
|
1418
|
-
// `prepare` runs on `npm install`, so a fresh clone has `.svelte-kit/`
|
|
1419
|
-
// before anything reads tsconfig.json.
|
|
1420
|
-
extraScripts: { prepare: "svelte-kit sync" },
|
|
1421
|
-
// shadcn-svelte's generated components import these from `$lib/utils.js`
|
|
1422
|
-
// alongside `cn()`. Without them the scaffold type-checks until the first
|
|
1423
|
-
// `npx shadcn-svelte@latest add <name>` — which the agent guidance tells
|
|
1424
|
-
// assistants to run — and then fails inside components the user never wrote,
|
|
1425
|
-
// with an error naming a file they have no reason to suspect.
|
|
1426
|
-
//
|
|
1427
|
-
// Verbatim from shadcn-svelte's own utils.ts, so a component the CLI writes
|
|
1428
|
-
// resolves against exactly what upstream expects.
|
|
1429
|
-
libUtilsExtra: `
|
|
1430
|
-
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
|
|
1431
|
-
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
|
|
1432
|
-
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
|
|
1433
|
-
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
|
|
1434
|
-
`,
|
|
1435
|
-
gitignoreEntries: [".svelte-kit/"],
|
|
1436
|
-
// No `jsx`. `verbatimModuleSyntax` is what svelte-check expects so that
|
|
1437
|
-
// type-only imports in components are erased rather than emitted.
|
|
1438
|
-
tsconfigOptions: { verbatimModuleSyntax: true },
|
|
1439
|
-
viteImports: [
|
|
1440
|
-
`import { sveltekit } from "@sveltejs/kit/vite";`,
|
|
1441
|
-
`import adapter from "@sveltejs/adapter-static";`,
|
|
1442
|
-
`import tailwindcss from "@tailwindcss/vite";`
|
|
1443
|
-
],
|
|
1444
|
-
// tailwindcss() before sveltekit() — the order Tailwind v4 documents for
|
|
1445
|
-
// SvelteKit, so the stylesheet is processed before Kit consumes the graph.
|
|
1446
|
-
//
|
|
1447
|
-
// The whole SvelteKit config rides in the sveltekit() call. There is no
|
|
1448
|
-
// svelte.config.js by design — see renderSvelteKitPlugin().
|
|
1449
|
-
vitePlugins: ["tailwindcss()", renderSvelteKitPlugin()],
|
|
1450
|
-
// SvelteKit resolves its own paths from this file's directory and redirects
|
|
1451
|
-
// them into frontend/ via `files`; moving Vite's root under it puts the two
|
|
1452
|
-
// into disagreement. Output is the adapter's job, not `build.outDir`.
|
|
1453
|
-
viteRoot: null,
|
|
1454
|
-
viteBuild: null,
|
|
1455
|
-
// SvelteKit owns the page template — frontend/src/app.html. No `entryScript`
|
|
1456
|
-
// follows: there is no shared index.html for it to point at.
|
|
1457
|
-
ownsHtmlEntry: true,
|
|
1458
|
-
files(vars, landing, choice = defaultThemeChoice()) {
|
|
1459
|
-
const ui = "frontend/src/lib/components/ui";
|
|
1460
|
-
return [
|
|
1461
|
-
{ path: "components.json", content: renderComponentsJson(choice) },
|
|
1462
|
-
{ path: "frontend/src/app.html", content: renderAppHtml(vars, choice) },
|
|
1463
|
-
// Only for `--dark toggle` — see the React preset's note.
|
|
1464
|
-
...choice.dark === "toggle" ? [
|
|
1465
|
-
{
|
|
1466
|
-
path: "frontend/src/lib/components/mode-toggle.svelte",
|
|
1467
|
-
content: renderModeToggleSvelte(iconLibraryOf(choice.icons).svelte)
|
|
1468
|
-
}
|
|
1469
|
-
] : [],
|
|
1470
|
-
{ path: "frontend/src/app.d.ts", content: renderAppDts() },
|
|
1471
|
-
{ path: "frontend/src/routes/+layout.ts", content: renderLayoutTs() },
|
|
1472
|
-
{ path: "frontend/src/routes/+layout.svelte", content: renderLayoutSvelte() },
|
|
1473
|
-
{ path: "frontend/src/routes/+page.svelte", content: renderApp(landing, choice) },
|
|
1474
|
-
{ path: "frontend/src/routes/+error.svelte", content: renderErrorSvelte() },
|
|
1475
|
-
{ path: "frontend/src/routes/404/+page.svelte", content: renderNotFoundRoute() },
|
|
1476
|
-
{ path: "frontend/src/lib/components/error-state.svelte", content: renderErrorState() },
|
|
1477
|
-
// `kit.files.assets` points here: static files copied to the site root
|
|
1478
|
-
// verbatim. A README rather than a .gitkeep because this one gets
|
|
1479
|
-
// PUBLISHED — everything here lands in frontend/dist, so the placeholder
|
|
1480
|
-
// that keeps the directory in git is a file real users will see deployed.
|
|
1481
|
-
{
|
|
1482
|
-
path: "frontend/static/README.md",
|
|
1483
|
-
content: `Files here are copied to the site root as-is \u2014 \`favicon.png\` is served
|
|
1484
|
-
at \`/favicon.png\`. Reference them from a component with a root-relative
|
|
1485
|
-
path, or from \`app.html\` via \`%sveltekit.assets%\`.
|
|
1486
|
-
|
|
1487
|
-
Delete this file once you add something real.
|
|
1488
|
-
`
|
|
1489
|
-
},
|
|
1490
|
-
{ path: `${ui}/button/button.svelte`, content: renderButtonSvelte() },
|
|
1491
|
-
{ path: `${ui}/button/index.ts`, content: renderButtonIndex() },
|
|
1492
|
-
{
|
|
1493
|
-
path: `${ui}/card/card.svelte`,
|
|
1494
|
-
content: cardPart(
|
|
1495
|
-
"card",
|
|
1496
|
-
"div",
|
|
1497
|
-
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm"
|
|
1498
|
-
)
|
|
1499
|
-
},
|
|
1500
|
-
{
|
|
1501
|
-
path: `${ui}/card/card-header.svelte`,
|
|
1502
|
-
content: cardPart(
|
|
1503
|
-
"card-header",
|
|
1504
|
-
"div",
|
|
1505
|
-
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6"
|
|
1506
|
-
)
|
|
1507
|
-
},
|
|
1508
|
-
{
|
|
1509
|
-
path: `${ui}/card/card-title.svelte`,
|
|
1510
|
-
content: cardPart("card-title", "div", "leading-none font-semibold")
|
|
1511
|
-
},
|
|
1512
|
-
{
|
|
1513
|
-
path: `${ui}/card/card-description.svelte`,
|
|
1514
|
-
content: cardPart("card-description", "div", "text-sm text-muted-foreground")
|
|
1515
|
-
},
|
|
1516
|
-
{
|
|
1517
|
-
path: `${ui}/card/card-content.svelte`,
|
|
1518
|
-
content: cardPart("card-content", "div", "px-6")
|
|
1519
|
-
},
|
|
1520
|
-
{
|
|
1521
|
-
path: `${ui}/card/card-footer.svelte`,
|
|
1522
|
-
content: cardPart("card-footer", "div", "flex items-center px-6 [.border-t]:pt-6")
|
|
1523
|
-
},
|
|
1524
|
-
{ path: `${ui}/card/index.ts`, content: renderCardIndex() }
|
|
1525
|
-
];
|
|
1526
|
-
},
|
|
1527
|
-
iconBinding(id) {
|
|
1528
|
-
return iconLibraryOf(id).svelte;
|
|
1529
|
-
},
|
|
1530
|
-
readmeFrontendSection(icons) {
|
|
1531
|
-
return `[SvelteKit](https://svelte.dev/docs/kit) with Svelte 5, styled with
|
|
1532
|
-
[Tailwind CSS](https://tailwindcss.com) v4 and
|
|
1533
|
-
[shadcn-svelte](https://shadcn-svelte.com).
|
|
1534
|
-
|
|
1535
|
-
Pages live in [\`frontend/src/routes/\`](frontend/src/routes/) \u2014 \`+page.svelte\`
|
|
1536
|
-
is a page, a subdirectory is a nested route. Routes are **prerendered**: each
|
|
1537
|
-
becomes its own HTML document at build time, so a page loads as itself rather
|
|
1538
|
-
than as a shell that fills in afterwards, and an unmatched path returns a real
|
|
1539
|
-
404 from [\`+error.svelte\`](frontend/src/routes/+error.svelte).
|
|
1540
|
-
|
|
1541
|
-
> **There is no server.** \`npm run xano:deploy\` ships this app to a static host
|
|
1542
|
-
> with no runtime of its own; Xano is the backend, reached through
|
|
1543
|
-
> [\`frontend/src/lib/api.ts\`](frontend/src/lib/api.ts). So \`+page.server.ts\`,
|
|
1544
|
-
> form actions, and server \`load\` have nothing to run on \u2014 and **nothing warns
|
|
1545
|
-
> you**: a project using them builds and deploys green, then fails in the
|
|
1546
|
-
> browser. Treat them as unavailable. That is the trade \u2014 the backend is
|
|
1547
|
-
> authored in [\`xano/\`](xano/) as TypeScript and deployed alongside the
|
|
1548
|
-
> frontend, so it is a real backend, just not this one.
|
|
1549
|
-
>
|
|
1550
|
-
> \`frontend/src/routes/+layout.ts\` sets \`prerender = true\` for the whole app.
|
|
1551
|
-
> Because prerendering renders at build time, module-scope \`window\`/\`document\`
|
|
1552
|
-
> access now fails the **build** rather than the browser \u2014 use \`onMount\`, or
|
|
1553
|
-
> guard with \`import { browser } from "$app/environment"\`.
|
|
1554
|
-
|
|
1555
|
-
**A dynamic route needs \`entries\`, or the build fails.** A route like
|
|
1556
|
-
\`/posts/[id]\` cannot be prerendered unless the build knows which ids exist, so
|
|
1557
|
-
the build stops and names it \u2014 deliberately, rather than shipping a page that
|
|
1558
|
-
404s for real users:
|
|
1559
|
-
|
|
1560
|
-
\`\`\`ts
|
|
1561
|
-
// frontend/src/routes/posts/[id]/+page.ts
|
|
1562
|
-
export const entries = () => [{ id: "1" }, { id: "2" }];
|
|
1563
|
-
\`\`\`
|
|
1564
|
-
|
|
1565
|
-
[\`frontend/src/routes/404/+page.svelte\`](frontend/src/routes/404/+page.svelte)
|
|
1566
|
-
prerenders to \`404.html\`, which is what makes an unmatched path return a real
|
|
1567
|
-
404. It has to be a route: SvelteKit never prerenders \`+error.svelte\` to a file,
|
|
1568
|
-
so that alone would ship no \`404.html\` at all.
|
|
1569
|
-
|
|
1570
|
-
shadcn-svelte is not a dependency \u2014
|
|
1571
|
-
its components are copied into
|
|
1572
|
-
[\`frontend/src/lib/components/ui/\`](frontend/src/lib/components/ui/) and owned by
|
|
1573
|
-
this project, so edit them freely. \`Button\` and \`Card\` are already there; add
|
|
1574
|
-
more with:
|
|
1575
|
-
|
|
1576
|
-
\`\`\`bash
|
|
1577
|
-
npx shadcn-svelte@latest add dialog input form
|
|
1578
|
-
\`\`\`
|
|
1579
|
-
|
|
1580
|
-
[\`components.json\`](components.json) is pre-configured, so that works with no
|
|
1581
|
-
\`shadcn-svelte init\` step. ${iconLibraryOf(icons).guidance.svelte}
|
|
1582
|
-
|
|
1583
|
-
\`\`\`ts
|
|
1584
|
-
${iconLibraryOf(icons).svelte.arrowImport}
|
|
1585
|
-
\`\`\`
|
|
1586
|
-
|
|
1587
|
-
[\`frontend/src/routes/+page.svelte\`](frontend/src/routes/+page.svelte) already
|
|
1588
|
-
does, and that is the form \`npx shadcn-svelte@latest add\` writes too.
|
|
1589
|
-
|
|
1590
|
-
Components import through the \`$lib\` alias
|
|
1591
|
-
(\`$lib/components/ui/button\`, \`$lib/utils\`), which SvelteKit points at
|
|
1592
|
-
\`frontend/src/lib/\` via \`kit.files\` in
|
|
1593
|
-
[\`vite.config.ts\`](vite.config.ts) \u2014 there is no \`paths\` entry to keep in
|
|
1594
|
-
sync, and adding one would just be a second answer that can disagree.
|
|
1595
|
-
|
|
1596
|
-
Colors come from the theme tokens in
|
|
1597
|
-
[\`frontend/src/index.css\`](frontend/src/index.css) \u2014 see **Theming** below.
|
|
1598
|
-
|
|
1599
|
-
> \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, not \`tsc\`. It
|
|
1600
|
-
> checks both halves \u2014 the backend's TypeScript and the components \u2014 where
|
|
1601
|
-
> \`tsc\` cannot read \`.svelte\` files at all. Keep it in the script: it is what
|
|
1602
|
-
> makes the frontend unable to drift from the backend defs. \`sync\` regenerates
|
|
1603
|
-
> \`.svelte-kit/\`, which \`tsconfig.json\` extends; \`npm install\` runs it too.`;
|
|
1604
|
-
},
|
|
1605
|
-
agentGuidanceSection(icons) {
|
|
1606
|
-
return `- \`frontend/src/\` \u2014 the SvelteKit app. Svelte 5 + Tailwind v4 + shadcn-svelte.
|
|
1607
|
-
- **There is no server.** This deploys to a static host with no runtime, and
|
|
1608
|
-
Xano is the backend. Never write \`+page.server.ts\`, \`+layout.server.ts\`,
|
|
1609
|
-
form actions, or server \`load\` \u2014 reach the backend through
|
|
1610
|
-
\`frontend/src/lib/api.ts\` instead, and never stand up a second backend here.
|
|
1611
|
-
- **The build will not stop you.** A project containing \`+page.server.ts\`
|
|
1612
|
-
compiles and deploys green, then fails in the browser on the live site. A
|
|
1613
|
-
passing build is not evidence that a server feature works \u2014 there is
|
|
1614
|
-
nothing to run it.
|
|
1615
|
-
- \`frontend/src/routes/\` \u2014 file-based routing. A page is \`+page.svelte\`, a
|
|
1616
|
-
nested route is a subdirectory. **Routes live under \`frontend/src/\`, not a
|
|
1617
|
-
top-level \`src/\`** \u2014 \`files\` in the \`sveltekit()\` plugin config in
|
|
1618
|
-
\`vite.config.ts\` points SvelteKit here. A file added under a top-level
|
|
1619
|
-
\`src/routes/\` is not a route and is never served.
|
|
1620
|
-
- **Routes are prerendered.** \`frontend/src/routes/+layout.ts\` sets
|
|
1621
|
-
\`prerender = true\` for the whole app, so every route is rendered to its own
|
|
1622
|
-
HTML document at build time and served as a real page. A static route needs
|
|
1623
|
-
nothing registered \u2014 add \`+page.svelte\` and it works.
|
|
1624
|
-
- **Prerendering renders at BUILD time**, so module-scope \`window\`/\`document\`
|
|
1625
|
-
access now breaks the build, not the browser. Use \`onMount\`, or guard with
|
|
1626
|
-
\`import { browser } from "$app/environment"\`. This is a page option, not a
|
|
1627
|
-
server \u2014 do not "fix" it by reaching for \`ssr\` or a server file.
|
|
1628
|
-
- **A dynamic route needs \`entries\`, or the build fails.** \`/posts/[id]\`
|
|
1629
|
-
cannot be prerendered unless the build knows which ids exist, so the build
|
|
1630
|
-
stops and names the route. Export
|
|
1631
|
-
\`const entries = () => [{ id: "1" }, { id: "2" }]\` from that route's
|
|
1632
|
-
\`+page.ts\`. This is the single most likely thing to catch you out when
|
|
1633
|
-
adding a detail page \u2014 and it is a build error, not a runtime surprise, so
|
|
1634
|
-
you will see it immediately.
|
|
1635
|
-
- \`frontend/src/routes/404/+page.svelte\` prerenders to \`404.html\`, which is
|
|
1636
|
-
what makes an unmatched path return a real 404 instead of silently serving a
|
|
1637
|
-
page with a 200. Keep it: without it a missing asset comes back as HTML and
|
|
1638
|
-
the browser reports \`Unexpected token '<'\`. It has to be a route \u2014 SvelteKit
|
|
1639
|
-
never prerenders \`+error.svelte\` to a file, so that alone would ship no
|
|
1640
|
-
\`404.html\`.
|
|
1641
|
-
- Do NOT add \`fallback\` to the adapter config. It writes an empty shell over
|
|
1642
|
-
the prerendered home page, and it turns the un-prerenderable-route build
|
|
1643
|
-
error into a silent runtime 404.
|
|
1644
|
-
- Data loading: call \`api.ts\` from the component, or from a universal
|
|
1645
|
-
\`+page.ts\` \`load\` if you need it before render. Both run in the browser.
|
|
1646
|
-
- \`frontend/src/lib/components/ui/\` \u2014 shadcn-svelte components, **copied in and
|
|
1647
|
-
owned by this project**. Edit them directly; there is no library to configure
|
|
1648
|
-
around.
|
|
1649
|
-
- Need one that isn't there? \`npx shadcn-svelte@latest add <name>\` \u2014 do not
|
|
1650
|
-
hand-roll it, and do not add a different component library. Note the
|
|
1651
|
-
\`-svelte\` suffix: the plain \`shadcn\` CLI writes React and will not work here.
|
|
1652
|
-
- ${iconLibraryOf(icons).guidance.svelte.replace(/\n/g, "\n ")}
|
|
1653
|
-
- That import form is what \`frontend/src/routes/+page.svelte\` already uses and
|
|
1654
|
-
what \`npx shadcn-svelte@latest add\` writes, so matching it keeps what you
|
|
1655
|
-
write consistent with what the CLI generates beside it. Do not add another
|
|
1656
|
-
icon library and do not paste raw inline \`<svg>\` markup.
|
|
1657
|
-
- Import via the \`$lib\` alias (\`$lib/components/ui/button\`, \`$lib/utils\`),
|
|
1658
|
-
which SvelteKit generates for both TypeScript and the bundler. Do not add a
|
|
1659
|
-
\`paths\` entry for it \u2014 a hand-written one is a second source of truth that
|
|
1660
|
-
can disagree with the generated one.
|
|
1661
|
-
- Components are Svelte 5 **runes** (\`$props()\`, \`$bindable()\`,
|
|
1662
|
-
\`{@render children?.()}\`) \u2014 not the Svelte 4 \`export let\` / slot API. Runes
|
|
1663
|
-
mode is FORCED in \`vite.config.ts\`, so \`export let\` is a compile error
|
|
1664
|
-
naming the file rather than a component that quietly builds in legacy mode.
|
|
1665
|
-
Do not "fix" that error by relaxing \`compilerOptions.runes\` \u2014 write the
|
|
1666
|
-
rune.
|
|
1667
|
-
- \`npm run typecheck\` runs \`svelte-kit sync && svelte-check\`, which checks both
|
|
1668
|
-
\`xano/\` and the components. Do not swap it for \`tsc --noEmit\`: \`tsc\` cannot
|
|
1669
|
-
read \`.svelte\` files and fails on the UI kit's barrels. \`sync\` regenerates
|
|
1670
|
-
\`.svelte-kit/\`, which \`tsconfig.json\` extends \u2014 run it after adding a route.`;
|
|
1671
|
-
}
|
|
1672
|
-
};
|
|
1673
|
-
|
|
1674
|
-
// src/emit/frontend-presets.ts
|
|
1675
|
-
var FRAMEWORKS = ["react", "svelte"];
|
|
1676
|
-
var DEFAULT_FRAMEWORK = "react";
|
|
1677
|
-
var PRESETS = {
|
|
1678
|
-
react: reactPreset,
|
|
1679
|
-
svelte: sveltePreset
|
|
1680
|
-
};
|
|
1681
|
-
function findFrontendPreset(id) {
|
|
1682
|
-
const normalized = id.trim().toLowerCase();
|
|
1683
|
-
return FRAMEWORKS.includes(normalized) ? PRESETS[normalized] : void 0;
|
|
1684
|
-
}
|
|
1685
|
-
function allFrontendPresets() {
|
|
1686
|
-
return FRAMEWORKS.map((id) => PRESETS[id]);
|
|
1687
|
-
}
|
|
1688
|
-
function resolveFrameworkFlag(raw) {
|
|
1689
|
-
const preset = findFrontendPreset(raw);
|
|
1690
|
-
if (preset === void 0) {
|
|
1691
|
-
throw new Error(
|
|
1692
|
-
`Unknown --framework "${raw}". Valid frameworks: ${FRAMEWORKS.join(", ")}.`
|
|
1693
|
-
);
|
|
1694
|
-
}
|
|
1695
|
-
return preset;
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
868
|
export {
|
|
869
|
+
sdkDep,
|
|
1699
870
|
renderPackageJson,
|
|
1700
871
|
renderTsconfig,
|
|
1701
872
|
renderViteConfig,
|
|
@@ -1711,13 +882,9 @@ export {
|
|
|
1711
882
|
initLanding,
|
|
1712
883
|
codegenLanding,
|
|
1713
884
|
renderIndexCss,
|
|
885
|
+
renderThemeScript,
|
|
1714
886
|
renderThemeModule,
|
|
1715
887
|
renderCnUtil,
|
|
1716
|
-
renderApiTs
|
|
1717
|
-
FRAMEWORKS,
|
|
1718
|
-
DEFAULT_FRAMEWORK,
|
|
1719
|
-
findFrontendPreset,
|
|
1720
|
-
allFrontendPresets,
|
|
1721
|
-
resolveFrameworkFlag
|
|
888
|
+
renderApiTs
|
|
1722
889
|
};
|
|
1723
|
-
//# sourceMappingURL=chunk-
|
|
890
|
+
//# sourceMappingURL=chunk-QUUB7HYK.js.map
|