@squadbase/vantage 0.1.0 → 0.2.0
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/README.md +5 -2
- package/dist/{chunk-YLAB6UQS.js → chunk-46QI6GFC.js} +2 -2
- package/dist/{chunk-YLAB6UQS.js.map → chunk-46QI6GFC.js.map} +1 -1
- package/dist/{chunk-WQZYXXQW.js → chunk-DIABD3KZ.js} +2 -2
- package/dist/chunk-DIABD3KZ.js.map +1 -0
- package/dist/chunk-DTDVSFRY.js +29 -0
- package/dist/chunk-DTDVSFRY.js.map +1 -0
- package/dist/chunk-EHPJXDJU.js +51 -0
- package/dist/chunk-EHPJXDJU.js.map +1 -0
- package/dist/{chunk-PRFBSQA4.js → chunk-UHZ7XSAN.js} +10 -5
- package/dist/chunk-UHZ7XSAN.js.map +1 -0
- package/dist/cli.js +19 -11
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +23 -2
- package/dist/components/index.js +116 -2
- package/dist/components/index.js.map +1 -1
- package/dist/{define-page-B6y9TOfZ.d.ts → define-page-BfhrK99G.d.ts} +5 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/markdown/index.js.map +1 -1
- package/dist/query/index.d.ts +69 -2
- package/dist/query/index.js +85 -2
- package/dist/query/index.js.map +1 -1
- package/dist/router/index.d.ts +86 -1
- package/dist/router/index.js +71 -7
- package/dist/router/index.js.map +1 -1
- package/dist/server/node.js +1 -1
- package/dist/server/node.js.map +1 -1
- package/dist/ui/index.js +1 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/vite/index.js +2 -2
- package/docs/en/agent-skills.md +12 -8
- package/docs/en/changelog.md +98 -0
- package/docs/en/cli-reference.md +1 -1
- package/docs/en/components.md +2 -0
- package/docs/en/data-fetching.md +77 -13
- package/docs/en/pages-and-metadata.md +6 -3
- package/docs/en/parts/placeholder.md +38 -0
- package/docs/en/parts/sparkline.md +47 -0
- package/docs/en/routing.md +82 -4
- package/docs/index.json +75 -13
- package/docs/ja/agent-skills.md +13 -9
- package/docs/ja/changelog.md +89 -0
- package/docs/ja/cli-reference.md +1 -1
- package/docs/ja/components.md +2 -0
- package/docs/ja/data-fetching.md +76 -12
- package/docs/ja/pages-and-metadata.md +6 -3
- package/docs/ja/parts/placeholder.md +37 -0
- package/docs/ja/parts/sparkline.md +47 -0
- package/docs/ja/routing.md +80 -4
- package/package.json +1 -1
- package/skills/vantage-add-feature/SKILL.md +14 -12
- package/skills/vantage-app/SKILL.md +55 -24
- package/skills/vantage-pitfalls/SKILL.md +27 -13
- package/templates/AGENTS.md +65 -23
- package/dist/chunk-ATYZ45XL.js +0 -19
- package/dist/chunk-ATYZ45XL.js.map +0 -1
- package/dist/chunk-PRFBSQA4.js.map +0 -1
- package/dist/chunk-WQZYXXQW.js.map +0 -1
|
@@ -9,6 +9,11 @@ interface PageConfig {
|
|
|
9
9
|
title?: string;
|
|
10
10
|
/** Description metadata for the page. */
|
|
11
11
|
description?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Short label for navigation built from `useRoutes()`. Defaults to `title`,
|
|
14
|
+
* which is often too long for a nav ("Overview · Acme Analytics").
|
|
15
|
+
*/
|
|
16
|
+
navLabel?: string;
|
|
12
17
|
/**
|
|
13
18
|
* Component rendered while the route is loading.
|
|
14
19
|
* (Reserved — not yet applied to Vantage's code-split routes in the prototype.)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { P as PageComponent, a as PageConfig, d as definePage } from './define-page-
|
|
1
|
+
export { P as PageComponent, a as PageConfig, d as definePage } from './define-page-BfhrK99G.js';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -10,6 +10,6 @@ import 'react';
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/** Framework version, kept in sync with package.json at build time. */
|
|
13
|
-
declare const VERSION = "0.
|
|
13
|
+
declare const VERSION = "0.2.0";
|
|
14
14
|
|
|
15
15
|
export { VERSION };
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runtime/define-page.ts","../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../src/runtime/define-page.ts","../src/index.ts"],"names":[],"mappings":";;;AAyCO,SAAS,WAAW,MAAA,EAAgC;AACzD,EAAA,OAAO,MAAA;AACT;;;AChCO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["import type { ComponentType, ReactNode } from \"react\"\n\n/**\n * Optional per-page configuration. The only required part of a page module is\n * its default-exported component; `definePage` covers everything else.\n */\nexport interface PageConfig {\n /** Document title applied when this route is active. */\n title?: string\n /** Description metadata for the page. */\n description?: string\n /**\n * Short label for navigation built from `useRoutes()`. Defaults to `title`,\n * which is often too long for a nav (\"Overview · Acme Analytics\").\n */\n navLabel?: string\n /**\n * Component rendered while the route is loading.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n pendingComponent?: ComponentType\n /**\n * Component rendered when the route throws.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n errorComponent?: ComponentType<{ error: unknown }>\n /**\n * Validate/transform the URL search params for this route.\n * (Reserved — not yet applied to Vantage's code-split routes in the prototype.)\n */\n validateSearch?: (search: Record<string, unknown>) => Record<string, unknown>\n}\n\n/**\n * Declare optional page configuration.\n *\n * ```tsx\n * export const page = definePage({ title: \"Monthly Analysis\" })\n * export default function MonthlyAnalysis() { return <div/> }\n * ```\n */\nexport function definePage(config: PageConfig): PageConfig {\n return config\n}\n\n/** Convenience type for a Vantage page component. */\nexport type PageComponent = ComponentType & { (): ReactNode }\n","/**\n * `@squadbase/vantage` — public runtime surface.\n *\n * The only import most pages need. Server state lives in\n * `@squadbase/vantage/query`, navigation in `@squadbase/vantage/router`,\n * UI in `@squadbase/vantage/ui`, and API types in `@squadbase/vantage/server`.\n */\nexport { definePage } from \"./runtime/define-page\"\nexport type { PageConfig, PageComponent } from \"./runtime/define-page\"\n\n/** Framework version, kept in sync with package.json at build time. */\nexport const VERSION = \"0.2.0\"\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/markdown/index.tsx"],"names":["MarkdownRenderer"],"mappings":";;;;;;;;AAyBO,IAAM,gBAAA,GAAmB,UAAA;AAAA,EAC9B,SAASA,iBAAAA,CAAiB,EAAE,OAAA,EAAS,SAAA,IAAa,GAAA,EAAK;AACrD,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,mBAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,yBAAA,EAA2B,SAAS,CAAA;AAAA,QAElD,8BAAC,UAAA,EAAA,EAAW,OAAA,EAAS,EAAE,IAAA,IAAS,QAAA,EAAA,OAAA,EAAQ;AAAA;AAAA,KAC1C;AAAA,EAEJ;AACF;AACA,gBAAA,CAAiB,WAAA,GAAc,kBAAA","file":"index.js","sourcesContent":["/**\n * `@squadbase/vantage/markdown` — markdown rendering, on its own subpath.\n *\n * This lives apart from `@squadbase/vantage/components` on purpose. Streamdown\n * bundles Shiki with every language grammar it supports — several hundred\n * chunks and roughly 11 MB of build output. Re-exporting it from the shared\n * `components` barrel would create an import edge that bundlers cannot drop,\n * so every app would emit that payload whether or not it renders markdown.\n * Behind its own entry, only apps that import this pay for it.\n */\nimport { forwardRef } from \"react\"\nimport { Streamdown } from \"streamdown\"\nimport { code } from \"@streamdown/code\"\n\nimport { cn } from \"../ui/cn
|
|
1
|
+
{"version":3,"sources":["../../src/markdown/index.tsx"],"names":["MarkdownRenderer"],"mappings":";;;;;;;;AAyBO,IAAM,gBAAA,GAAmB,UAAA;AAAA,EAC9B,SAASA,iBAAAA,CAAiB,EAAE,OAAA,EAAS,SAAA,IAAa,GAAA,EAAK;AACrD,IAAA,uBACE,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAA,EAAU,mBAAA;AAAA,QACV,SAAA,EAAW,EAAA,CAAG,yBAAA,EAA2B,SAAS,CAAA;AAAA,QAElD,8BAAC,UAAA,EAAA,EAAW,OAAA,EAAS,EAAE,IAAA,IAAS,QAAA,EAAA,OAAA,EAAQ;AAAA;AAAA,KAC1C;AAAA,EAEJ;AACF;AACA,gBAAA,CAAiB,WAAA,GAAc,kBAAA","file":"index.js","sourcesContent":["/**\n * `@squadbase/vantage/markdown` — markdown rendering, on its own subpath.\n *\n * This lives apart from `@squadbase/vantage/components` on purpose. Streamdown\n * bundles Shiki with every language grammar it supports — several hundred\n * chunks and roughly 11 MB of build output. Re-exporting it from the shared\n * `components` barrel would create an import edge that bundlers cannot drop,\n * so every app would emit that payload whether or not it renders markdown.\n * Behind its own entry, only apps that import this pay for it.\n */\nimport { forwardRef } from \"react\"\nimport { Streamdown } from \"streamdown\"\nimport { code } from \"@streamdown/code\"\n\nimport { cn } from \"../ui/cn\"\n\n// Streamdown's own stylesheet. Vite resolves this in the app build; it is\n// scoped to this optional entry, so apps that never import it stay unaffected.\nimport \"streamdown/styles.css\"\n\nexport interface MarkdownRendererProps {\n content: string\n className?: string\n}\n\nexport const MarkdownRenderer = forwardRef<HTMLDivElement, MarkdownRendererProps>(\n function MarkdownRenderer({ content, className }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"markdown-renderer\"\n className={cn(\"text-sm leading-relaxed\", className)}\n >\n <Streamdown plugins={{ code }}>{content}</Streamdown>\n </div>\n )\n },\n)\nMarkdownRenderer.displayName = \"MarkdownRenderer\"\n"]}
|
package/dist/query/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QueryClient } from '@tanstack/react-query';
|
|
1
|
+
import { QueryClient, UseMutationOptions, UseQueryOptions, QueryKey, UseMutationResult, UseQueryResult } from '@tanstack/react-query';
|
|
2
2
|
export { QueryClient, QueryKey, UseInfiniteQueryOptions, UseMutationOptions, UseMutationResult, UseQueryOptions, UseQueryResult, keepPreviousData, useInfiniteQuery, useIsFetching, useIsMutating, useMutation, useQueries, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -33,5 +33,72 @@ declare function apiUrl(path: string): string;
|
|
|
33
33
|
* existing `queryFn` style.
|
|
34
34
|
*/
|
|
35
35
|
declare function apiFetch(path: string, init?: RequestInit): Promise<Response>;
|
|
36
|
+
/** Query-string values accepted by the API helpers. */
|
|
37
|
+
type ApiSearch = Record<string, string | number | boolean | null | undefined | (string | number)[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Append a query string to an API path. `undefined`/`null` entries are dropped
|
|
40
|
+
* so an unset filter leaves the URL — and the query key — unchanged. Array
|
|
41
|
+
* values repeat the key, matching `URLSearchParams.getAll` on the server.
|
|
42
|
+
*/
|
|
43
|
+
declare function apiPath(path: string, search?: ApiSearch): string;
|
|
44
|
+
/**
|
|
45
|
+
* A non-2xx response from `server/api`. `message` is the server's `HttpError`
|
|
46
|
+
* message when there was one; anything else surfaces as a generic status text,
|
|
47
|
+
* mirroring what the server chose to disclose.
|
|
48
|
+
*/
|
|
49
|
+
declare class ApiError extends Error {
|
|
50
|
+
/** HTTP status of the response. */
|
|
51
|
+
readonly status: number;
|
|
52
|
+
/** Parsed response body, when there was one. */
|
|
53
|
+
readonly body: unknown;
|
|
54
|
+
/** `x-vantage-request-id`, to correlate with the server's terminal log. */
|
|
55
|
+
readonly requestId: string | undefined;
|
|
56
|
+
constructor(message: string, status: number, body: unknown, requestId?: string);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fetch an API route and parse its JSON, throwing `ApiError` on a non-2xx.
|
|
60
|
+
* This is what the API hooks call; use it directly in a loader or an event
|
|
61
|
+
* handler where a hook doesn't fit.
|
|
62
|
+
*/
|
|
63
|
+
declare function apiJson<T = unknown>(path: string, init?: RequestInit): Promise<T>;
|
|
64
|
+
|
|
65
|
+
interface ApiQueryOptions<TData> extends Omit<UseQueryOptions<TData, ApiError>, "queryKey" | "queryFn"> {
|
|
66
|
+
/** Query-string values; `undefined` entries are omitted. */
|
|
67
|
+
search?: ApiSearch;
|
|
68
|
+
/** Extra `fetch` init (headers, credentials, …). */
|
|
69
|
+
init?: RequestInit;
|
|
70
|
+
/** Override the derived `["api", url]` key. */
|
|
71
|
+
queryKey?: QueryKey;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* GET an API route.
|
|
75
|
+
*
|
|
76
|
+
* ```tsx
|
|
77
|
+
* const { data, isPending, error } = useApiQuery<Monthly>("/api/monthly-analysis")
|
|
78
|
+
* const filtered = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* The key defaults to `["api", <url with query string>]`, so changing `search`
|
|
82
|
+
* refetches and `invalidateQueries({ queryKey: ["api"] })` clears everything.
|
|
83
|
+
*/
|
|
84
|
+
declare function useApiQuery<TData = unknown>(path: string, options?: ApiQueryOptions<TData>): UseQueryResult<TData, ApiError>;
|
|
85
|
+
interface ApiMutationOptions<TData, TVariables> extends Omit<UseMutationOptions<TData, ApiError, TVariables>, "mutationFn"> {
|
|
86
|
+
/** HTTP method (default `"POST"`). */
|
|
87
|
+
method?: "POST" | "PUT" | "PATCH" | "DELETE";
|
|
88
|
+
/** Extra `fetch` init (headers, credentials, …). */
|
|
89
|
+
init?: RequestInit;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Write to an API route. The mutation variables are sent as the JSON body.
|
|
93
|
+
*
|
|
94
|
+
* ```tsx
|
|
95
|
+
* const save = useApiMutation<Customer, { id: string; name: string }>(
|
|
96
|
+
* (vars) => `/api/customers/${vars.id}`,
|
|
97
|
+
* { method: "PUT" },
|
|
98
|
+
* )
|
|
99
|
+
* save.mutate({ id: "1", name: "Northwind" })
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
declare function useApiMutation<TData = unknown, TVariables = void>(path: string | ((variables: TVariables) => string), options?: ApiMutationOptions<TData, TVariables>): UseMutationResult<TData, ApiError, TVariables>;
|
|
36
103
|
|
|
37
|
-
export { apiBaseUrl, apiFetch, apiUrl, createQueryClient };
|
|
104
|
+
export { ApiError, type ApiMutationOptions, type ApiQueryOptions, type ApiSearch, apiBaseUrl, apiFetch, apiJson, apiPath, apiUrl, createQueryClient, useApiMutation, useApiQuery };
|
package/dist/query/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { createQueryClient } from '../chunk-
|
|
1
|
+
export { createQueryClient } from '../chunk-DTDVSFRY.js';
|
|
2
|
+
import { useQuery, useMutation } from '@tanstack/react-query';
|
|
2
3
|
export { QueryClient, keepPreviousData, useInfiniteQuery, useIsFetching, useIsMutating, useMutation, useQueries, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
4
|
|
|
4
5
|
// @squadbase/vantage — generated build. Do not edit.
|
|
@@ -16,7 +17,89 @@ function apiUrl(path) {
|
|
|
16
17
|
function apiFetch(path, init) {
|
|
17
18
|
return fetch(apiUrl(path), init);
|
|
18
19
|
}
|
|
20
|
+
function apiPath(path, search) {
|
|
21
|
+
if (!search) return path;
|
|
22
|
+
const params = new URLSearchParams();
|
|
23
|
+
for (const key of Object.keys(search).sort()) {
|
|
24
|
+
const value = search[key];
|
|
25
|
+
if (value === void 0 || value === null) continue;
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
for (const item of value) params.append(key, String(item));
|
|
28
|
+
} else {
|
|
29
|
+
params.append(key, String(value));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const qs = params.toString();
|
|
33
|
+
if (!qs) return path;
|
|
34
|
+
return path + (path.includes("?") ? "&" : "?") + qs;
|
|
35
|
+
}
|
|
36
|
+
var ApiError = class extends Error {
|
|
37
|
+
/** HTTP status of the response. */
|
|
38
|
+
status;
|
|
39
|
+
/** Parsed response body, when there was one. */
|
|
40
|
+
body;
|
|
41
|
+
/** `x-vantage-request-id`, to correlate with the server's terminal log. */
|
|
42
|
+
requestId;
|
|
43
|
+
constructor(message, status, body, requestId) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "ApiError";
|
|
46
|
+
this.status = status;
|
|
47
|
+
this.body = body;
|
|
48
|
+
this.requestId = requestId;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
async function apiJson(path, init) {
|
|
52
|
+
const res = await apiFetch(path, init);
|
|
53
|
+
const requestId = res.headers.get("x-vantage-request-id") ?? void 0;
|
|
54
|
+
const text = await res.text();
|
|
55
|
+
let body;
|
|
56
|
+
if (text) {
|
|
57
|
+
try {
|
|
58
|
+
body = JSON.parse(text);
|
|
59
|
+
} catch {
|
|
60
|
+
body = text;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!res.ok) {
|
|
64
|
+
const serverMessage = typeof body === "object" && body !== null && typeof body.error === "string" ? body.error : void 0;
|
|
65
|
+
throw new ApiError(
|
|
66
|
+
serverMessage ?? `${res.status} ${res.statusText || "Request failed"}`,
|
|
67
|
+
res.status,
|
|
68
|
+
body,
|
|
69
|
+
requestId
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return body;
|
|
73
|
+
}
|
|
74
|
+
var API_KEY = "api";
|
|
75
|
+
function useApiQuery(path, options = {}) {
|
|
76
|
+
const { search, init, queryKey, ...rest } = options;
|
|
77
|
+
const url = apiPath(path, search);
|
|
78
|
+
return useQuery({
|
|
79
|
+
queryKey: queryKey ?? [API_KEY, url],
|
|
80
|
+
// The signal comes from TanStack so an unmounted/refetched query aborts;
|
|
81
|
+
// a caller-supplied signal wins.
|
|
82
|
+
queryFn: ({ signal }) => apiJson(url, { ...init, signal: init?.signal ?? signal }),
|
|
83
|
+
...rest
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function useApiMutation(path, options = {}) {
|
|
87
|
+
const { method = "POST", init, ...rest } = options;
|
|
88
|
+
return useMutation({
|
|
89
|
+
mutationFn: (variables) => {
|
|
90
|
+
const url = typeof path === "function" ? path(variables) : path;
|
|
91
|
+
const hasBody = variables !== void 0 && variables !== null;
|
|
92
|
+
return apiJson(url, {
|
|
93
|
+
method,
|
|
94
|
+
...init,
|
|
95
|
+
headers: hasBody ? { "content-type": "application/json", ...init?.headers } : init?.headers,
|
|
96
|
+
...hasBody ? { body: JSON.stringify(variables) } : {}
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
...rest
|
|
100
|
+
});
|
|
101
|
+
}
|
|
19
102
|
|
|
20
|
-
export { apiBaseUrl, apiFetch, apiUrl };
|
|
103
|
+
export { ApiError, apiBaseUrl, apiFetch, apiJson, apiPath, apiUrl, useApiMutation, useApiQuery };
|
|
21
104
|
//# sourceMappingURL=index.js.map
|
|
22
105
|
//# sourceMappingURL=index.js.map
|
package/dist/query/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/query/api.ts"],"names":[],"mappings":";;;;;;AAaO,SAAS,UAAA,GAAqB;AAEnC,EAAA,MAAM,MAAO,MAAA,CAAA,IAAA,CAA6D,GAAA;AAC1E,EAAA,MAAM,GAAA,GAAM,KAAK,mBAAA,IAAuB,EAAA;AACxC,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC/B;AAOO,SAAS,OAAO,IAAA,EAAsB;AAC3C,EAAA,MAAM,MAAM,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,IAAI,IAAI,CAAA,CAAA;AAClD,EAAA,OAAO,YAAW,GAAI,GAAA;AACxB;AAOO,SAAS,QAAA,CAAS,MAAc,IAAA,EAAuC;AAC5E,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,IAAI,CAAA,EAAG,IAAI,CAAA;AACjC","file":"index.js","sourcesContent":["/**\n * The one seam for calling the API from client code. All `/api/*` requests go\n * through here so a split deployment (client on S3/CloudFront, server on Lambda)\n * can point the client at a different origin without touching page code.\n *\n * The base is read from `import.meta.env.PUBLIC_API_BASE_URL` — a `PUBLIC_`\n * prefixed var so it is inlined into the client bundle (see envPrefix in the\n * Vite plugin). It can be set in `.env` or injected at build time via\n * `vantage build --api-base-url <url>`. When unset it is empty, so requests stay\n * same-origin relative paths — identical to hand-written `fetch(\"/api/...\")`.\n */\n\n/** The configured API base URL (no trailing slash), or \"\" for same-origin. */\nexport function apiBaseUrl(): string {\n // `import.meta.env` is typed in the generated .vantage/types, not here.\n const env = (import.meta as { env?: Record<string, string | undefined> }).env\n const raw = env?.PUBLIC_API_BASE_URL ?? \"\"\n return raw.replace(/\\/+$/, \"\")\n}\n\n/**\n * Build a full API URL. Pass the path exactly as it maps to `server/api/**`,\n * including the `/api` prefix — e.g. `apiUrl(\"/api/customers\")`. With no base\n * configured this returns the relative path unchanged.\n */\nexport function apiUrl(path: string): string {\n const rel = path.startsWith(\"/\") ? path : `/${path}`\n return apiBaseUrl() + rel\n}\n\n/**\n * Thin `fetch` wrapper that resolves the path against the API base. Returns the\n * raw `Response` — parsing and error handling stay with the caller, matching the\n * existing `queryFn` style.\n */\nexport function apiFetch(path: string, init?: RequestInit): Promise<Response> {\n return fetch(apiUrl(path), init)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/query/api.ts","../../src/query/hooks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The one seam for calling the API from client code. All `/api/*` requests go\n * through here so a split deployment (client on S3/CloudFront, server on Lambda)\n * can point the client at a different origin without touching page code.\n *\n * The base is read from `import.meta.env.PUBLIC_API_BASE_URL` — a `PUBLIC_`\n * prefixed var so it is inlined into the client bundle (see envPrefix in the\n * Vite plugin). It can be set in `.env` or injected at build time via\n * `vantage build --api-base-url <url>`. When unset it is empty, so requests stay\n * same-origin relative paths — identical to hand-written `fetch(\"/api/...\")`.\n */\n\n/** The configured API base URL (no trailing slash), or \"\" for same-origin. */\nexport function apiBaseUrl(): string {\n // `import.meta.env` is typed in the generated .vantage/types, not here.\n const env = (import.meta as { env?: Record<string, string | undefined> }).env\n const raw = env?.PUBLIC_API_BASE_URL ?? \"\"\n return raw.replace(/\\/+$/, \"\")\n}\n\n/**\n * Build a full API URL. Pass the path exactly as it maps to `server/api/**`,\n * including the `/api` prefix — e.g. `apiUrl(\"/api/customers\")`. With no base\n * configured this returns the relative path unchanged.\n */\nexport function apiUrl(path: string): string {\n const rel = path.startsWith(\"/\") ? path : `/${path}`\n return apiBaseUrl() + rel\n}\n\n/**\n * Thin `fetch` wrapper that resolves the path against the API base. Returns the\n * raw `Response` — parsing and error handling stay with the caller, matching the\n * existing `queryFn` style.\n */\nexport function apiFetch(path: string, init?: RequestInit): Promise<Response> {\n return fetch(apiUrl(path), init)\n}\n\n/** Query-string values accepted by the API helpers. */\nexport type ApiSearch = Record<\n string,\n string | number | boolean | null | undefined | (string | number)[]\n>\n\n/**\n * Append a query string to an API path. `undefined`/`null` entries are dropped\n * so an unset filter leaves the URL — and the query key — unchanged. Array\n * values repeat the key, matching `URLSearchParams.getAll` on the server.\n */\nexport function apiPath(path: string, search?: ApiSearch): string {\n if (!search) return path\n const params = new URLSearchParams()\n // Sorted so two calls with the same filters produce the same query key.\n for (const key of Object.keys(search).sort()) {\n const value = search[key]\n if (value === undefined || value === null) continue\n if (Array.isArray(value)) {\n for (const item of value) params.append(key, String(item))\n } else {\n params.append(key, String(value))\n }\n }\n const qs = params.toString()\n if (!qs) return path\n return path + (path.includes(\"?\") ? \"&\" : \"?\") + qs\n}\n\n/**\n * A non-2xx response from `server/api`. `message` is the server's `HttpError`\n * message when there was one; anything else surfaces as a generic status text,\n * mirroring what the server chose to disclose.\n */\nexport class ApiError extends Error {\n /** HTTP status of the response. */\n readonly status: number\n /** Parsed response body, when there was one. */\n readonly body: unknown\n /** `x-vantage-request-id`, to correlate with the server's terminal log. */\n readonly requestId: string | undefined\n\n constructor(message: string, status: number, body: unknown, requestId?: string) {\n super(message)\n this.name = \"ApiError\"\n this.status = status\n this.body = body\n this.requestId = requestId\n }\n}\n\n/**\n * Fetch an API route and parse its JSON, throwing `ApiError` on a non-2xx.\n * This is what the API hooks call; use it directly in a loader or an event\n * handler where a hook doesn't fit.\n */\nexport async function apiJson<T = unknown>(path: string, init?: RequestInit): Promise<T> {\n const res = await apiFetch(path, init)\n const requestId = res.headers.get(\"x-vantage-request-id\") ?? undefined\n\n // Read as text first: an error response may be HTML from a proxy, and a 204\n // has no body at all — neither should throw a JSON parse error at the caller.\n const text = await res.text()\n let body: unknown\n if (text) {\n try {\n body = JSON.parse(text)\n } catch {\n body = text\n }\n }\n\n if (!res.ok) {\n const serverMessage =\n typeof body === \"object\" && body !== null && typeof (body as { error?: unknown }).error === \"string\"\n ? (body as { error: string }).error\n : undefined\n throw new ApiError(\n serverMessage ?? `${res.status} ${res.statusText || \"Request failed\"}`,\n res.status,\n body,\n requestId,\n )\n }\n\n return body as T\n}\n","/**\n * Hooks for the app's own `server/api` routes. They are `useQuery`/`useMutation`\n * with the parts every page was repeating — base URL, JSON parsing, non-2xx to\n * `ApiError`, a query key derived from the URL — moved into the framework.\n * Everything else about TanStack Query stays available through the options.\n */\nimport { useMutation, useQuery } from \"@tanstack/react-query\"\nimport type {\n QueryKey,\n UseMutationOptions,\n UseMutationResult,\n UseQueryOptions,\n UseQueryResult,\n} from \"@tanstack/react-query\"\nimport { apiJson, apiPath, type ApiError, type ApiSearch } from \"./api\"\n\n/** Query-key namespace, so `invalidateQueries({ queryKey: [\"api\"] })` works. */\nconst API_KEY = \"api\"\n\nexport interface ApiQueryOptions<TData>\n extends Omit<UseQueryOptions<TData, ApiError>, \"queryKey\" | \"queryFn\"> {\n /** Query-string values; `undefined` entries are omitted. */\n search?: ApiSearch\n /** Extra `fetch` init (headers, credentials, …). */\n init?: RequestInit\n /** Override the derived `[\"api\", url]` key. */\n queryKey?: QueryKey\n}\n\n/**\n * GET an API route.\n *\n * ```tsx\n * const { data, isPending, error } = useApiQuery<Monthly>(\"/api/monthly-analysis\")\n * const filtered = useApiQuery<Row[]>(\"/api/customers\", { search: { segment } })\n * ```\n *\n * The key defaults to `[\"api\", <url with query string>]`, so changing `search`\n * refetches and `invalidateQueries({ queryKey: [\"api\"] })` clears everything.\n */\nexport function useApiQuery<TData = unknown>(\n path: string,\n options: ApiQueryOptions<TData> = {},\n): UseQueryResult<TData, ApiError> {\n const { search, init, queryKey, ...rest } = options\n const url = apiPath(path, search)\n return useQuery<TData, ApiError>({\n queryKey: queryKey ?? [API_KEY, url],\n // The signal comes from TanStack so an unmounted/refetched query aborts;\n // a caller-supplied signal wins.\n queryFn: ({ signal }) => apiJson<TData>(url, { ...init, signal: init?.signal ?? signal }),\n ...rest,\n })\n}\n\nexport interface ApiMutationOptions<TData, TVariables>\n extends Omit<UseMutationOptions<TData, ApiError, TVariables>, \"mutationFn\"> {\n /** HTTP method (default `\"POST\"`). */\n method?: \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\"\n /** Extra `fetch` init (headers, credentials, …). */\n init?: RequestInit\n}\n\n/**\n * Write to an API route. The mutation variables are sent as the JSON body.\n *\n * ```tsx\n * const save = useApiMutation<Customer, { id: string; name: string }>(\n * (vars) => `/api/customers/${vars.id}`,\n * { method: \"PUT\" },\n * )\n * save.mutate({ id: \"1\", name: \"Northwind\" })\n * ```\n */\nexport function useApiMutation<TData = unknown, TVariables = void>(\n path: string | ((variables: TVariables) => string),\n options: ApiMutationOptions<TData, TVariables> = {},\n): UseMutationResult<TData, ApiError, TVariables> {\n const { method = \"POST\", init, ...rest } = options\n return useMutation<TData, ApiError, TVariables>({\n mutationFn: (variables: TVariables) => {\n const url = typeof path === \"function\" ? path(variables) : path\n const hasBody = variables !== undefined && variables !== null\n return apiJson<TData>(url, {\n method,\n ...init,\n headers: hasBody\n ? { \"content-type\": \"application/json\", ...(init?.headers as Record<string, string>) }\n : init?.headers,\n ...(hasBody ? { body: JSON.stringify(variables) } : {}),\n })\n },\n ...rest,\n })\n}\n"]}
|
package/dist/router/index.d.ts
CHANGED
|
@@ -1,6 +1,91 @@
|
|
|
1
1
|
export { Outlet, notFound, redirect, useRouterState } from '@tanstack/react-router';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The app's route list, published once by the client bootstrap and read by the
|
|
6
|
+
* route hooks. A module-level store rather than React context: the list is
|
|
7
|
+
* fixed for the lifetime of the bundle — the generated route tree is imported
|
|
8
|
+
* by `.vantage/client-entry.tsx`, which accepts no HMR update, so adding a page
|
|
9
|
+
* full-reloads the dev server — and pages can read it without a provider.
|
|
10
|
+
*
|
|
11
|
+
* `client/bootstrap` and `router/` are separate published subpaths but tsup
|
|
12
|
+
* hoists this module into a shared chunk, so both see the same instance.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** One page route, as described by the generated manifest. */
|
|
16
|
+
interface RouteInfo {
|
|
17
|
+
/** Display path with `:param` placeholders — e.g. `/sales/:customerId`. */
|
|
18
|
+
path: string;
|
|
19
|
+
/** The same path in `Link`'s token form — e.g. `/sales/$customerId`. */
|
|
20
|
+
to: string;
|
|
21
|
+
/** Dynamic parameter names in order; a catch-all is reported as `_splat`. */
|
|
22
|
+
params: string[];
|
|
23
|
+
/** True when the route carries at least one dynamic parameter. */
|
|
24
|
+
dynamic: boolean;
|
|
25
|
+
/** True for a directory's index route (`index.tsx`). */
|
|
26
|
+
index: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Ready-to-render nav label: `navLabel`, else `title`, else the path. Always
|
|
29
|
+
* a string, so a nav needs no fallback of its own.
|
|
30
|
+
*/
|
|
31
|
+
label: string;
|
|
32
|
+
/** `definePage({ title })`, extracted statically at generate time. */
|
|
33
|
+
title?: string;
|
|
34
|
+
/** `definePage({ description })`. */
|
|
35
|
+
description?: string;
|
|
36
|
+
/** `definePage({ navLabel })`. */
|
|
37
|
+
navLabel?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Every page route in the app, in the framework's scan order (shallow before
|
|
42
|
+
* deep, static before dynamic, alphabetical) — the order a nav wants.
|
|
43
|
+
*
|
|
44
|
+
* ```tsx
|
|
45
|
+
* // Dynamic routes have no single URL, so a nav lists only static ones.
|
|
46
|
+
* const routes = useRoutes().filter((route) => !route.dynamic)
|
|
47
|
+
* routes.map((route) => <Link key={route.path} to={route.to}>{route.label}</Link>)
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function useRoutes(): readonly RouteInfo[];
|
|
51
|
+
/**
|
|
52
|
+
* The route currently rendered, or `undefined` on the 404 route (no page
|
|
53
|
+
* matched). Use it for breadcrumbs or a page header that mirrors `definePage`.
|
|
54
|
+
*/
|
|
55
|
+
declare function useCurrentRoute(): RouteInfo | undefined;
|
|
56
|
+
|
|
57
|
+
interface SearchStateOptions {
|
|
58
|
+
/**
|
|
59
|
+
* Replace the current history entry instead of pushing a new one.
|
|
60
|
+
* Defaults to `true` so dragging a slider doesn't fill the back button.
|
|
61
|
+
*/
|
|
62
|
+
replace?: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A string search param, as `useState`. The value is always a string —
|
|
66
|
+
* TanStack parses `?year=2024` into a number, and this hook normalizes it back.
|
|
67
|
+
*
|
|
68
|
+
* ```tsx
|
|
69
|
+
* const [region, setRegion] = useSearchParam("region", "all")
|
|
70
|
+
* <SegmentedControl value={region} onValueChange={setRegion} options={REGIONS} />
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* Writing the default value (or `null`) drops the key from the URL.
|
|
74
|
+
*/
|
|
75
|
+
declare function useSearchParam(key: string, defaultValue?: string, options?: SearchStateOptions): [string, (value: string | null) => void];
|
|
76
|
+
/**
|
|
77
|
+
* Any JSON-serializable search param, as `useState` — arrays for a multi-select,
|
|
78
|
+
* an object for a whole filter bar. Supports a functional update.
|
|
79
|
+
*
|
|
80
|
+
* ```tsx
|
|
81
|
+
* const [segments, setSegments] = useSearchState<string[]>("segments", [])
|
|
82
|
+
* setSegments((prev) => [...prev, "enterprise"])
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* Writing a value deep-equal to the default drops the key from the URL.
|
|
86
|
+
*/
|
|
87
|
+
declare function useSearchState<T>(key: string, defaultValue: T, options?: SearchStateOptions): [T, (value: T | ((prev: T) => T)) => void];
|
|
88
|
+
|
|
4
89
|
/**
|
|
5
90
|
* Vantage's thin router API. Users depend on `@squadbase/vantage/router`
|
|
6
91
|
* instead of `@tanstack/react-router`, so the underlying router can evolve
|
|
@@ -33,4 +118,4 @@ declare function useNavigate(): (opts: {
|
|
|
33
118
|
replace?: boolean;
|
|
34
119
|
}) => void;
|
|
35
120
|
|
|
36
|
-
export { Link, type LinkProps, useNavigate, useParams, useSearch };
|
|
121
|
+
export { Link, type LinkProps, type RouteInfo, type SearchStateOptions, useCurrentRoute, useNavigate, useParams, useRoutes, useSearch, useSearchParam, useSearchState };
|
package/dist/router/index.js
CHANGED
|
@@ -1,9 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRoutes, findRoute } from '../chunk-EHPJXDJU.js';
|
|
2
|
+
import { useRouterState, Link as Link$1, useParams as useParams$1, useSearch, useNavigate } from '@tanstack/react-router';
|
|
2
3
|
export { Outlet, notFound, redirect, useRouterState } from '@tanstack/react-router';
|
|
3
|
-
import { createElement } from 'react';
|
|
4
|
+
import { useCallback, createElement } from 'react';
|
|
4
5
|
|
|
5
6
|
// @squadbase/vantage — generated build. Do not edit.
|
|
7
|
+
function useRoutes() {
|
|
8
|
+
return getRoutes();
|
|
9
|
+
}
|
|
10
|
+
function useCurrentRoute() {
|
|
11
|
+
const path = useRouterState({
|
|
12
|
+
select: (state) => {
|
|
13
|
+
const matches = state.matches;
|
|
14
|
+
const leaf = matches[matches.length - 1];
|
|
15
|
+
return leaf?.staticData?.routePath;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return path ? findRoute(path) : void 0;
|
|
19
|
+
}
|
|
20
|
+
function useRawSearch() {
|
|
21
|
+
return useSearch({ strict: false });
|
|
22
|
+
}
|
|
23
|
+
function useSearchWriter(key, options) {
|
|
24
|
+
const navigate = useNavigate();
|
|
25
|
+
const replace = options.replace ?? true;
|
|
26
|
+
return useCallback(
|
|
27
|
+
(next) => {
|
|
28
|
+
navigate({
|
|
29
|
+
search: (prev) => {
|
|
30
|
+
const merged = { ...prev };
|
|
31
|
+
if (next === void 0) delete merged[key];
|
|
32
|
+
else merged[key] = next;
|
|
33
|
+
return merged;
|
|
34
|
+
},
|
|
35
|
+
replace
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
[navigate, key, replace]
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
function useSearchParam(key, defaultValue = "", options = {}) {
|
|
42
|
+
const search = useRawSearch();
|
|
43
|
+
const write = useSearchWriter(key, options);
|
|
44
|
+
const raw = search[key];
|
|
45
|
+
const value = raw === void 0 || raw === null ? defaultValue : String(raw);
|
|
46
|
+
const set = useCallback(
|
|
47
|
+
(next) => {
|
|
48
|
+
write(next === null || next === defaultValue ? void 0 : next);
|
|
49
|
+
},
|
|
50
|
+
[write, defaultValue]
|
|
51
|
+
);
|
|
52
|
+
return [value, set];
|
|
53
|
+
}
|
|
54
|
+
function useSearchState(key, defaultValue, options = {}) {
|
|
55
|
+
const search = useRawSearch();
|
|
56
|
+
const write = useSearchWriter(key, options);
|
|
57
|
+
const raw = search[key];
|
|
58
|
+
const value = raw === void 0 || raw === null ? defaultValue : raw;
|
|
59
|
+
const set = useCallback(
|
|
60
|
+
(next) => {
|
|
61
|
+
const resolved = typeof next === "function" ? next(value) : next;
|
|
62
|
+
const isDefault = JSON.stringify(resolved) === JSON.stringify(defaultValue);
|
|
63
|
+
write(isDefault ? void 0 : resolved);
|
|
64
|
+
},
|
|
65
|
+
[write, value, defaultValue]
|
|
66
|
+
);
|
|
67
|
+
return [value, set];
|
|
68
|
+
}
|
|
6
69
|
|
|
70
|
+
// src/router/index.ts
|
|
7
71
|
function Link({ activeClassName, className, ...props }) {
|
|
8
72
|
const anyLink = Link$1;
|
|
9
73
|
return createElement(anyLink, {
|
|
@@ -15,13 +79,13 @@ function Link({ activeClassName, className, ...props }) {
|
|
|
15
79
|
function useParams() {
|
|
16
80
|
return useParams$1({ strict: false });
|
|
17
81
|
}
|
|
18
|
-
function
|
|
19
|
-
return useSearch
|
|
82
|
+
function useSearch2() {
|
|
83
|
+
return useSearch({ strict: false });
|
|
20
84
|
}
|
|
21
|
-
function
|
|
22
|
-
return useNavigate
|
|
85
|
+
function useNavigate2() {
|
|
86
|
+
return useNavigate();
|
|
23
87
|
}
|
|
24
88
|
|
|
25
|
-
export { Link, useNavigate, useParams, useSearch };
|
|
89
|
+
export { Link, useCurrentRoute, useNavigate2 as useNavigate, useParams, useRoutes, useSearch2 as useSearch, useSearchParam, useSearchState };
|
|
26
90
|
//# sourceMappingURL=index.js.map
|
|
27
91
|
//# sourceMappingURL=index.js.map
|
package/dist/router/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/router/index.ts"],"names":["TanstackLink","useParamsBase","useSearchBase","useNavigateBase"],"mappings":";;;;;;AAiCO,SAAS,KAAK,EAAE,eAAA,EAAiB,SAAA,EAAW,GAAG,OAAM,EAAyB;AAEnF,EAAA,MAAM,OAAA,GAAUA,MAAA;AAChB,EAAA,OAAO,cAAc,OAAA,EAAS;AAAA,IAC5B,GAAG,KAAA;AAAA,IACH,SAAA;AAAA,IACA,WAAA,EAAa,eAAA,GAAkB,EAAE,SAAA,EAAW,CAAA,EAAG,SAAA,IAAa,EAAE,CAAA,CAAA,EAAI,eAAe,CAAA,CAAA,CAAG,IAAA,EAAK,EAAE,GAAI;AAAA,GAChG,CAAA;AACH;AAGO,SAAS,SAAA,GAAoC;AAElD,EAAA,OAAOC,WAAA,CAAc,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AACxC;AAGO,SAAS,SAAA,GAAqC;AAEnD,EAAA,OAAOC,WAAA,CAAc,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AACxC;AAGO,SAAS,WAAA,GAAoI;AAElJ,EAAA,OAAOC,aAAA,EAAgB;AACzB","file":"index.js","sourcesContent":["/**\n * Vantage's thin router API. Users depend on `@squadbase/vantage/router`\n * instead of `@tanstack/react-router`, so the underlying router can evolve\n * without touching user code. Only the ergonomic, SPA-relevant surface is\n * exposed; typed-route generics are intentionally relaxed to plain strings.\n */\nimport {\n Link as TanstackLink,\n Outlet,\n useNavigate as useNavigateBase,\n useParams as useParamsBase,\n useSearch as useSearchBase,\n useRouterState,\n redirect,\n notFound,\n} from \"@tanstack/react-router\"\nimport { createElement, type ReactNode } from \"react\"\n\nexport { Outlet, useRouterState, redirect, notFound }\n\nexport interface LinkProps {\n to: string\n params?: Record<string, string>\n search?: Record<string, unknown>\n hash?: string\n replace?: boolean\n className?: string\n activeClassName?: string\n children?: ReactNode\n [key: string]: unknown\n}\n\n/** Client-side navigation link. */\nexport function Link({ activeClassName, className, ...props }: LinkProps): ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anyLink = TanstackLink as any\n return createElement(anyLink, {\n ...props,\n className,\n activeProps: activeClassName ? { className: `${className ?? \"\"} ${activeClassName}`.trim() } : undefined,\n })\n}\n\n/** Route params for the current route (e.g. `{ customerId: \"42\" }`). */\nexport function useParams(): Record<string, string> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useParamsBase({ strict: false }) as any\n}\n\n/** Validated/raw search params for the current route. */\nexport function useSearch(): Record<string, unknown> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useSearchBase({ strict: false }) as any\n}\n\n/** Imperative navigation. `navigate({ to: \"/sales/42\" })`. */\nexport function useNavigate(): (opts: { to: string; params?: Record<string, string>; search?: Record<string, unknown>; replace?: boolean }) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useNavigateBase() as any\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/router/routes.ts","../../src/router/search.ts","../../src/router/index.ts"],"names":["TanstackLink","useParamsBase","useSearch","useSearchBase","useNavigate","useNavigateBase"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Route-introspection hooks. The route list comes from the generated manifest,\n * so a nav built on `useRoutes()` picks up a new page file the moment it is\n * created — no hand-maintained link array.\n */\nimport { useRouterState } from \"@tanstack/react-router\"\nimport { findRoute, getRoutes, type RouteInfo } from \"./registry\"\n\n/**\n * Every page route in the app, in the framework's scan order (shallow before\n * deep, static before dynamic, alphabetical) — the order a nav wants.\n *\n * ```tsx\n * // Dynamic routes have no single URL, so a nav lists only static ones.\n * const routes = useRoutes().filter((route) => !route.dynamic)\n * routes.map((route) => <Link key={route.path} to={route.to}>{route.label}</Link>)\n * ```\n */\nexport function useRoutes(): readonly RouteInfo[] {\n return getRoutes()\n}\n\n/**\n * The route currently rendered, or `undefined` on the 404 route (no page\n * matched). Use it for breadcrumbs or a page header that mirrors `definePage`.\n */\nexport function useCurrentRoute(): RouteInfo | undefined {\n // Selecting the path string (not the match object) keeps the subscription\n // stable — the component re-renders on navigation, not on every router tick.\n const path = useRouterState({\n select: (state) => {\n const matches = state.matches\n const leaf = matches[matches.length - 1] as\n | { staticData?: { routePath?: string } }\n | undefined\n return leaf?.staticData?.routePath\n },\n })\n return path ? findRoute(path) : undefined\n}\n","/**\n * URL-backed component state. A dashboard's filters belong in the URL: the view\n * survives a reload and can be pasted to a colleague. These hooks read and write\n * a single search-param key with a `useState`-shaped API.\n */\nimport { useCallback } from \"react\"\nimport { useNavigate, useSearch } from \"@tanstack/react-router\"\n\nexport interface SearchStateOptions {\n /**\n * Replace the current history entry instead of pushing a new one.\n * Defaults to `true` so dragging a slider doesn't fill the back button.\n */\n replace?: boolean\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nfunction useRawSearch(): Record<string, unknown> {\n return useSearch({ strict: false }) as any\n}\n\n/**\n * Writer for one key. Passing `undefined` removes the key so defaults never\n * show up in the URL.\n */\nfunction useSearchWriter(key: string, options: SearchStateOptions): (next: unknown) => void {\n const navigate = useNavigate() as any\n const replace = options.replace ?? true\n return useCallback(\n (next: unknown) => {\n // No `to`: TanStack keeps the current route and its path params, so this\n // works unchanged on a dynamic route like `/sales/$customerId`.\n navigate({\n search: (prev: Record<string, unknown>) => {\n const merged = { ...prev }\n if (next === undefined) delete merged[key]\n else merged[key] = next\n return merged\n },\n replace,\n })\n },\n [navigate, key, replace],\n )\n}\n\n/**\n * A string search param, as `useState`. The value is always a string —\n * TanStack parses `?year=2024` into a number, and this hook normalizes it back.\n *\n * ```tsx\n * const [region, setRegion] = useSearchParam(\"region\", \"all\")\n * <SegmentedControl value={region} onValueChange={setRegion} options={REGIONS} />\n * ```\n *\n * Writing the default value (or `null`) drops the key from the URL.\n */\nexport function useSearchParam(\n key: string,\n defaultValue = \"\",\n options: SearchStateOptions = {},\n): [string, (value: string | null) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : String(raw)\n\n const set = useCallback(\n (next: string | null) => {\n write(next === null || next === defaultValue ? undefined : next)\n },\n [write, defaultValue],\n )\n\n return [value, set]\n}\n\n/**\n * Any JSON-serializable search param, as `useState` — arrays for a multi-select,\n * an object for a whole filter bar. Supports a functional update.\n *\n * ```tsx\n * const [segments, setSegments] = useSearchState<string[]>(\"segments\", [])\n * setSegments((prev) => [...prev, \"enterprise\"])\n * ```\n *\n * Writing a value deep-equal to the default drops the key from the URL.\n */\nexport function useSearchState<T>(\n key: string,\n defaultValue: T,\n options: SearchStateOptions = {},\n): [T, (value: T | ((prev: T) => T)) => void] {\n const search = useRawSearch()\n const write = useSearchWriter(key, options)\n\n const raw = search[key]\n const value = raw === undefined || raw === null ? defaultValue : (raw as T)\n\n const set = useCallback(\n (next: T | ((prev: T) => T)) => {\n const resolved = typeof next === \"function\" ? (next as (prev: T) => T)(value) : next\n // Structural comparison: the parsed value is plain JSON, so stringify is\n // both sufficient and cheap at filter sizes.\n const isDefault = JSON.stringify(resolved) === JSON.stringify(defaultValue)\n write(isDefault ? undefined : resolved)\n },\n [write, value, defaultValue],\n )\n\n return [value, set]\n}\n","/**\n * Vantage's thin router API. Users depend on `@squadbase/vantage/router`\n * instead of `@tanstack/react-router`, so the underlying router can evolve\n * without touching user code. Only the ergonomic, SPA-relevant surface is\n * exposed; typed-route generics are intentionally relaxed to plain strings.\n */\nimport {\n Link as TanstackLink,\n Outlet,\n useNavigate as useNavigateBase,\n useParams as useParamsBase,\n useSearch as useSearchBase,\n useRouterState,\n redirect,\n notFound,\n} from \"@tanstack/react-router\"\nimport { createElement, type ReactNode } from \"react\"\n\nexport { Outlet, useRouterState, redirect, notFound }\n\nexport { useRoutes, useCurrentRoute } from \"./routes\"\nexport type { RouteInfo } from \"./registry\"\n\nexport { useSearchParam, useSearchState } from \"./search\"\nexport type { SearchStateOptions } from \"./search\"\n\nexport interface LinkProps {\n to: string\n params?: Record<string, string>\n search?: Record<string, unknown>\n hash?: string\n replace?: boolean\n className?: string\n activeClassName?: string\n children?: ReactNode\n [key: string]: unknown\n}\n\n/** Client-side navigation link. */\nexport function Link({ activeClassName, className, ...props }: LinkProps): ReactNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const anyLink = TanstackLink as any\n return createElement(anyLink, {\n ...props,\n className,\n activeProps: activeClassName ? { className: `${className ?? \"\"} ${activeClassName}`.trim() } : undefined,\n })\n}\n\n/** Route params for the current route (e.g. `{ customerId: \"42\" }`). */\nexport function useParams(): Record<string, string> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useParamsBase({ strict: false }) as any\n}\n\n/** Validated/raw search params for the current route. */\nexport function useSearch(): Record<string, unknown> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useSearchBase({ strict: false }) as any\n}\n\n/** Imperative navigation. `navigate({ to: \"/sales/42\" })`. */\nexport function useNavigate(): (opts: { to: string; params?: Record<string, string>; search?: Record<string, unknown>; replace?: boolean }) => void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return useNavigateBase() as any\n}\n"]}
|
package/dist/server/node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sortApiRoutes, corsMiddleware, matchApiRoute, dispatchApi } from '../chunk-
|
|
1
|
+
import { sortApiRoutes, corsMiddleware, matchApiRoute, dispatchApi } from '../chunk-46QI6GFC.js';
|
|
2
2
|
import '../chunk-B7LLBNLV.js';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
package/dist/server/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/node.ts"],"names":[],"mappings":"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","file":"node.js","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport { Hono } from \"hono\"\nimport { serve } from \"@hono/node-server\"\nimport type { Segment } from \"../core/types
|
|
1
|
+
{"version":3,"sources":["../../src/server/node.ts"],"names":[],"mappings":"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","file":"node.js","sourcesContent":["import fs from \"node:fs\"\nimport path from \"node:path\"\nimport { fileURLToPath } from \"node:url\"\nimport { Hono } from \"hono\"\nimport { serve } from \"@hono/node-server\"\nimport type { Segment } from \"../core/types\"\nimport { corsMiddleware } from \"./cors\"\nimport { dispatchApi, matchApiRoute, sortApiRoutes } from \"./dispatch\"\nimport type { ApiModule } from \"./index\"\n\n/** A statically-imported API route for the production server. */\nexport interface ProdApiRoute {\n routePath: string\n segments: Segment[]\n module: ApiModule\n}\n\nconst MIME: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json; charset=utf-8\",\n}\n\n/**\n * Start the production Node server: API routes first, then static client\n * assets, then SPA fallback to index.html. Runtime-agnostic Hono keeps the door\n * open for future Bun/Deno/Workers adapters.\n */\nexport function startNodeServer(opts: {\n apiRoutes: ProdApiRoute[]\n /** Absolute path to the built client directory (dist/client). */\n clientDir: string\n port?: number\n}): void {\n const { clientDir } = opts\n const indexHtml = path.join(clientDir, \"index.html\")\n const env = { ...process.env }\n\n const routes = sortApiRoutes(\n opts.apiRoutes.map((r) => ({\n routePath: r.routePath,\n segments: r.segments,\n hasCatchall: r.segments.some((s) => s.kind === \"catchall\"),\n staticCount: r.segments.filter((s) => s.kind === \"static\").length,\n load: async () => r.module,\n })),\n )\n\n const app = new Hono()\n\n // CORS for split deployments (client on a different origin). Off unless\n // CORS_ORIGIN is set; must be registered before the /api routes below.\n const cors = corsMiddleware(env)\n if (cors) {\n app.use(\"/api\", cors)\n app.use(\"/api/*\", cors)\n }\n\n const apiHandler = async (c: { req: { url: string; raw: Request } }) => {\n const url = new URL(c.req.url)\n const match = matchApiRoute(routes, url.pathname)\n if (!match) return Response.json({ error: \"Not Found\", path: url.pathname }, { status: 404 })\n const mod = await match.route.load()\n return dispatchApi(mod, c.req.raw, match.params, env)\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n app.all(\"/api\", apiHandler as any)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n app.all(\"/api/*\", apiHandler as any)\n\n // Static assets + SPA fallback.\n app.get(\"/*\", (c) => {\n const url = new URL(c.req.url)\n const filePath = safeJoin(clientDir, url.pathname)\n if (filePath && fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const ext = path.extname(filePath)\n const body = fs.readFileSync(filePath)\n return new Response(body, { headers: { \"content-type\": MIME[ext] ?? \"application/octet-stream\" } })\n }\n if (fs.existsSync(indexHtml)) {\n return new Response(fs.readFileSync(indexHtml), { headers: { \"content-type\": MIME[\".html\"]! } })\n }\n return new Response(\"Not Found\", { status: 404 })\n })\n\n const port = opts.port ?? Number(process.env.PORT ?? 3000)\n serve({ fetch: app.fetch, port }, (info) => {\n // eslint-disable-next-line no-console\n console.log(`[vantage] server listening on http://localhost:${info.port}`)\n })\n}\n\n/** Prevent path traversal outside the client dir. */\nfunction safeJoin(root: string, urlPath: string): string | null {\n const decoded = decodeURIComponent(urlPath.split(\"?\")[0]!)\n const joined = path.join(root, decoded)\n const normalizedRoot = path.resolve(root)\n const normalizedJoined = path.resolve(joined)\n if (normalizedJoined !== normalizedRoot && !normalizedJoined.startsWith(normalizedRoot + path.sep)) {\n return null\n }\n return normalizedJoined\n}\n\n/** Resolve a path relative to this module (used by generated entry). */\nexport function resolveFromEntry(entryUrl: string, ...segments: string[]): string {\n return path.resolve(path.dirname(fileURLToPath(entryUrl)), ...segments)\n}\n"]}
|
package/dist/ui/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Badge, Button, Calendar, CalendarDayButton, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-
|
|
1
|
+
export { Badge, Button, Calendar, CalendarDayButton, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, toggleVariants, useIsMobile, useSidebar } from '../chunk-DIABD3KZ.js';
|
|
2
2
|
import { cn } from '../chunk-A2UUGASH.js';
|
|
3
3
|
export { cn } from '../chunk-A2UUGASH.js';
|
|
4
4
|
import { Accordion as Accordion$1 } from '@base-ui/react/accordion';
|