swift-rust 1.2.1 → 1.4.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/bin/build.mjs +374 -9
- package/bin/dev-server.mjs +416 -35
- package/bin/runtime/fn-core.mjs +318 -0
- package/bin/runtime/navigator.js +238 -0
- package/dist/head.d.ts +3 -3
- package/dist/head.d.ts.map +1 -1
- package/dist/head.js +14 -0
- package/dist/head.js.map +1 -0
- package/dist/link.d.ts +1 -1
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +14 -0
- package/dist/link.js.map +1 -0
- package/package.json +1 -1
- package/dist/head.jsx +0 -15
- package/dist/head.jsx.map +0 -1
- package/dist/link.jsx +0 -6
- package/dist/link.jsx.map +0 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
// Portable request-time SSR handler used by emitted Vercel functions
|
|
2
|
+
// (edge / node / bun). No Bun-only APIs — renders with react-dom/server.
|
|
3
|
+
// Mirrors the dev-server route pipeline so emitted functions behave the same.
|
|
4
|
+
import { createElement } from "react";
|
|
5
|
+
|
|
6
|
+
async function renderTree(tree) {
|
|
7
|
+
try {
|
|
8
|
+
const { renderToReadableStream } = await import("react-dom/server.edge");
|
|
9
|
+
const stream = await renderToReadableStream(tree);
|
|
10
|
+
if (stream.allReady) await stream.allReady;
|
|
11
|
+
return await new Response(stream).text();
|
|
12
|
+
} catch {
|
|
13
|
+
const { renderToString } = await import("react-dom/server");
|
|
14
|
+
return renderToString(tree);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseCookies(request) {
|
|
19
|
+
const header = request.headers.get("cookie") || "";
|
|
20
|
+
const map = new Map();
|
|
21
|
+
for (const part of header.split(";")) {
|
|
22
|
+
const i = part.indexOf("=");
|
|
23
|
+
if (i > 0) map.set(part.slice(0, i).trim(), decodeURIComponent(part.slice(i + 1).trim()));
|
|
24
|
+
}
|
|
25
|
+
return { get: (k) => map.get(k), has: (k) => map.has(k) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function matchParams(pattern, pathname) {
|
|
29
|
+
const segs = pathname.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
30
|
+
const params = {};
|
|
31
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
32
|
+
const p = pattern[i];
|
|
33
|
+
if (p.startsWith("[...") && p.endsWith("]")) {
|
|
34
|
+
params[p.slice(4, -1)] = segs.slice(i);
|
|
35
|
+
return params;
|
|
36
|
+
}
|
|
37
|
+
if (p.startsWith("[") && p.endsWith("]")) params[p.slice(1, -1)] = segs[i];
|
|
38
|
+
}
|
|
39
|
+
return params;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const pick = (mod, ...keys) => {
|
|
43
|
+
for (const k of keys) if (mod && mod[k] != null) return mod[k];
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
|
46
|
+
const matchesMatcher = (pathname, matcher) => {
|
|
47
|
+
const list = Array.isArray(matcher) ? matcher : [matcher];
|
|
48
|
+
return list.some((m) => new RegExp(`^${String(m).replace(/\*\*/g, ".*").replace(/(?<!\.)\*/g, "[^/]*")}$`).test(pathname));
|
|
49
|
+
};
|
|
50
|
+
const esc = (s) =>
|
|
51
|
+
String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
52
|
+
|
|
53
|
+
// ── metadata (per-request) ──────────────────────────────────────────────────
|
|
54
|
+
function mergeMetadata(...metas) {
|
|
55
|
+
const out = {};
|
|
56
|
+
for (const m of metas) {
|
|
57
|
+
if (!m) continue;
|
|
58
|
+
if (m.title) out.title = typeof m.title === "string" ? m.title : (m.title.default ?? out.title);
|
|
59
|
+
if (m.description) out.description = m.description;
|
|
60
|
+
if (m.keywords) out.keywords = m.keywords;
|
|
61
|
+
if (m.openGraph) out.openGraph = { ...(out.openGraph || {}), ...m.openGraph };
|
|
62
|
+
if (m.twitter) out.twitter = { ...(out.twitter || {}), ...m.twitter };
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function metadataToHead(meta) {
|
|
67
|
+
if (!meta) return "";
|
|
68
|
+
const p = [];
|
|
69
|
+
if (typeof meta.title === "string") p.push(`<title>${esc(meta.title)}</title>`);
|
|
70
|
+
if (meta.description) p.push(`<meta name="description" content="${esc(meta.description)}" />`);
|
|
71
|
+
if (meta.keywords) p.push(`<meta name="keywords" content="${esc(Array.isArray(meta.keywords) ? meta.keywords.join(", ") : meta.keywords)}" />`);
|
|
72
|
+
const og = meta.openGraph;
|
|
73
|
+
if (og) {
|
|
74
|
+
if (og.title) p.push(`<meta property="og:title" content="${esc(og.title)}" />`);
|
|
75
|
+
if (og.description) p.push(`<meta property="og:description" content="${esc(og.description)}" />`);
|
|
76
|
+
if (og.type) p.push(`<meta property="og:type" content="${esc(og.type)}" />`);
|
|
77
|
+
if (og.url) p.push(`<meta property="og:url" content="${esc(og.url)}" />`);
|
|
78
|
+
for (const img of og.images || []) {
|
|
79
|
+
const url = typeof img === "string" ? img : img.url;
|
|
80
|
+
if (url) p.push(`<meta property="og:image" content="${esc(url)}" />`);
|
|
81
|
+
if (typeof img === "object" && img) {
|
|
82
|
+
if (img.width) p.push(`<meta property="og:image:width" content="${esc(img.width)}" />`);
|
|
83
|
+
if (img.height) p.push(`<meta property="og:image:height" content="${esc(img.height)}" />`);
|
|
84
|
+
if (img.alt) p.push(`<meta property="og:image:alt" content="${esc(img.alt)}" />`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const tw = meta.twitter;
|
|
89
|
+
if (tw) {
|
|
90
|
+
if (tw.card) p.push(`<meta name="twitter:card" content="${esc(tw.card)}" />`);
|
|
91
|
+
if (tw.title) p.push(`<meta name="twitter:title" content="${esc(tw.title)}" />`);
|
|
92
|
+
if (tw.description) p.push(`<meta name="twitter:description" content="${esc(tw.description)}" />`);
|
|
93
|
+
for (const img of tw.images || []) p.push(`<meta name="twitter:image" content="${esc(typeof img === "string" ? img : img.url)}" />`);
|
|
94
|
+
}
|
|
95
|
+
return p.join("\n");
|
|
96
|
+
}
|
|
97
|
+
function buildSeoHead(r) {
|
|
98
|
+
if (!r || typeof r !== "object") return "";
|
|
99
|
+
const out = [];
|
|
100
|
+
if (r.title) out.push(`<title>${esc(r.title)}</title>`);
|
|
101
|
+
if (r.description) out.push(`<meta name="description" content="${esc(r.description)}" />`);
|
|
102
|
+
if (r.canonical) out.push(`<link rel="canonical" href="${esc(r.canonical)}" />`);
|
|
103
|
+
if (r.robots) out.push(`<meta name="robots" content="${esc(r.robots)}" />`);
|
|
104
|
+
for (const [k, v] of Object.entries(r.openGraph || {})) out.push(`<meta property="og:${esc(k)}" content="${esc(v)}" />`);
|
|
105
|
+
const jsonLd = r.jsonLd ? (Array.isArray(r.jsonLd) ? r.jsonLd : [r.jsonLd]) : [];
|
|
106
|
+
for (const ld of jsonLd) out.push(`<script type="application/ld+json">${JSON.stringify(ld).replace(/</g, "\\u003c")}</script>`);
|
|
107
|
+
return out.join("\n");
|
|
108
|
+
}
|
|
109
|
+
// Drop captured metadata tags so per-request metadata/seo can replace them.
|
|
110
|
+
function stripMeta(head) {
|
|
111
|
+
return head
|
|
112
|
+
.replace(/<title>[\s\S]*?<\/title>/gi, "")
|
|
113
|
+
.replace(/<meta\s+name="description"[^>]*>/gi, "")
|
|
114
|
+
.replace(/<meta\s+name="keywords"[^>]*>/gi, "")
|
|
115
|
+
.replace(/<meta\s+property="og:[^"]*"[^>]*>/gi, "")
|
|
116
|
+
.replace(/<meta\s+name="twitter:[^"]*"[^>]*>/gi, "");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function cacheControl(plan) {
|
|
120
|
+
if (!plan) return null;
|
|
121
|
+
if (plan.ttl === 0 || plan.noStore) return "no-store";
|
|
122
|
+
const parts = [];
|
|
123
|
+
if (typeof plan.ttl === "number") parts.push(`s-maxage=${plan.ttl}`, "stale-while-revalidate");
|
|
124
|
+
return parts.length ? `public, ${parts.join(", ")}` : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function controlToResponse(c, url) {
|
|
128
|
+
if (!c || typeof c !== "object") return null;
|
|
129
|
+
if (c.kind === "redirect") return new Response(null, { status: c.status || 307, headers: { Location: new URL(c.to, url).toString() } });
|
|
130
|
+
if (c.kind === "notFound") return new Response("Not Found", { status: 404 });
|
|
131
|
+
if (c.kind === "response" && c.response) return c.response;
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
function thrownToResponse(err, url) {
|
|
135
|
+
if (err?.__response instanceof Response) return err.__response;
|
|
136
|
+
const d = err?.digest;
|
|
137
|
+
if (d && String(d).startsWith("REDIRECT")) {
|
|
138
|
+
const [, status, ...rest] = String(d).split(";");
|
|
139
|
+
return new Response(null, { status: Number(status) || 307, headers: { Location: new URL(rest.join(";"), url).toString() } });
|
|
140
|
+
}
|
|
141
|
+
if (d === "NOT_FOUND" || err?.name === "NotFoundError") return new Response("Not Found", { status: 404 });
|
|
142
|
+
if (d === "FORBIDDEN" || err?.name === "ForbiddenError") return new Response("Forbidden", { status: 403 });
|
|
143
|
+
if (d === "UNAUTHORIZED" || err?.name === "UnauthorizedError") return new Response("Unauthorized", { status: 401 });
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function makeRouteHandler(opts) {
|
|
148
|
+
return async function fetch(request) {
|
|
149
|
+
const url = new URL(request.url);
|
|
150
|
+
const params = matchParams(opts.pattern || [], url.pathname);
|
|
151
|
+
const setCookies = [];
|
|
152
|
+
const localsMap = new Map();
|
|
153
|
+
const ctx = {
|
|
154
|
+
url,
|
|
155
|
+
request,
|
|
156
|
+
method: request.method,
|
|
157
|
+
headers: request.headers,
|
|
158
|
+
params,
|
|
159
|
+
searchParams: Object.fromEntries(url.searchParams.entries()),
|
|
160
|
+
cookies: parseCookies(request),
|
|
161
|
+
locals: { get: (k) => localsMap.get(k), set: (k, v) => localsMap.set(k, v) },
|
|
162
|
+
runtime: opts.runtime,
|
|
163
|
+
__setCookies: setCookies,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
// proxy
|
|
168
|
+
for (const mod of opts.proxies || []) {
|
|
169
|
+
const fn = pick(mod, "default", "proxy");
|
|
170
|
+
if (typeof fn !== "function") continue;
|
|
171
|
+
if (mod.matcher && !matchesMatcher(url.pathname, mod.matcher)) continue;
|
|
172
|
+
const r = controlToResponse(await fn(ctx), url);
|
|
173
|
+
if (r) return r;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// i18n — resolve locale into locals
|
|
177
|
+
const i18nCfg = pick(opts.i18n || {}, "i18n", "default");
|
|
178
|
+
if (i18nCfg && Array.isArray(i18nCfg.locales)) {
|
|
179
|
+
let locale = i18nCfg.defaultLocale ?? i18nCfg.locales[0];
|
|
180
|
+
if (typeof i18nCfg.resolve === "function") locale = (await i18nCfg.resolve(ctx)) || locale;
|
|
181
|
+
else if (i18nCfg.strategy === "cookie") locale = ctx.cookies.get("locale") || locale;
|
|
182
|
+
else if (i18nCfg.strategy === "header") {
|
|
183
|
+
const al = request.headers.get("accept-language")?.split(",")[0]?.split("-")[0];
|
|
184
|
+
if (al && i18nCfg.locales.includes(al)) locale = al;
|
|
185
|
+
}
|
|
186
|
+
ctx.locals.set("locale", locale);
|
|
187
|
+
ctx.__locale = locale;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// schema / query
|
|
191
|
+
const querySpec = pick(opts.query || {}, "query");
|
|
192
|
+
for (const mod of opts.schemas || []) {
|
|
193
|
+
if (mod.params?.safeParse) {
|
|
194
|
+
const r = mod.params.safeParse(ctx.params);
|
|
195
|
+
if (!r.success) return Response.json({ error: "Invalid params", issues: r.error?.issues ?? r.error }, { status: 400 });
|
|
196
|
+
Object.assign(ctx.params, r.data);
|
|
197
|
+
}
|
|
198
|
+
const searchSchema = querySpec?.parse ?? mod.searchParams;
|
|
199
|
+
if (searchSchema?.safeParse) {
|
|
200
|
+
const r = searchSchema.safeParse(ctx.searchParams);
|
|
201
|
+
if (r.success) Object.assign(ctx.searchParams, r.data);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// guard (opt-in)
|
|
206
|
+
if (opts.guardEnabled) {
|
|
207
|
+
for (const mod of opts.guards || []) {
|
|
208
|
+
const fn = pick(mod, "default", "guard");
|
|
209
|
+
if (typeof fn !== "function") continue;
|
|
210
|
+
const r = controlToResponse(await fn(ctx), url);
|
|
211
|
+
if (r) return r;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// action (mutations)
|
|
216
|
+
let actionData;
|
|
217
|
+
if (ctx.method !== "GET" && ctx.method !== "HEAD" && opts.action) {
|
|
218
|
+
const fn = pick(opts.action, "default", "action");
|
|
219
|
+
if (typeof fn === "function") {
|
|
220
|
+
const actx = Object.assign({}, ctx, { formData: () => request.formData(), json: () => request.json() });
|
|
221
|
+
const result = await fn(actx);
|
|
222
|
+
const r = controlToResponse(result, url);
|
|
223
|
+
if (r) return r;
|
|
224
|
+
actionData = result;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// loaders (parallel)
|
|
229
|
+
const loaded = await Promise.all(
|
|
230
|
+
(opts.loaders || []).map(async (mod) => {
|
|
231
|
+
const fn = pick(mod, "default", "loader");
|
|
232
|
+
return typeof fn === "function" ? fn(ctx) : undefined;
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
const loaderData = loaded.length ? loaded[loaded.length - 1] : undefined;
|
|
236
|
+
|
|
237
|
+
// state
|
|
238
|
+
let serverState;
|
|
239
|
+
const stateFn = pick(opts.state || {}, "default", "state");
|
|
240
|
+
if (typeof stateFn === "function") serverState = await stateFn(ctx);
|
|
241
|
+
|
|
242
|
+
// seo
|
|
243
|
+
let seoHead = "";
|
|
244
|
+
const seoFn = pick(opts.seo || {}, "default", "seo");
|
|
245
|
+
if (typeof seoFn === "function") seoHead = buildSeoHead(await seoFn(Object.assign({}, ctx, { data: loaderData })));
|
|
246
|
+
|
|
247
|
+
// per-request metadata (layout metadata + page metadata/generateMetadata)
|
|
248
|
+
const metas = [];
|
|
249
|
+
for (const m of opts.layoutMetas || []) if (m?.metadata) metas.push(m.metadata);
|
|
250
|
+
const pageMod = opts.page;
|
|
251
|
+
if (typeof pageMod.generateMetadata === "function") {
|
|
252
|
+
metas.push(await pageMod.generateMetadata({ params: ctx.params, searchParams: ctx.searchParams }));
|
|
253
|
+
} else if (pageMod.metadata) {
|
|
254
|
+
metas.push(pageMod.metadata);
|
|
255
|
+
}
|
|
256
|
+
const metaHead = metadataToHead(mergeMetadata(...metas));
|
|
257
|
+
|
|
258
|
+
// Expose loader/action data to useLoaderData()/useActionData() via the
|
|
259
|
+
// router's globalThis context box (same channel the dev server uses).
|
|
260
|
+
const g = globalThis;
|
|
261
|
+
g.__SR_ROUTE_CTX__ = g.__SR_ROUTE_CTX__ || { current: null };
|
|
262
|
+
g.__SR_ROUTE_CTX__.current = { request: ctx, loaderData, actionData, loaders: {} };
|
|
263
|
+
|
|
264
|
+
// render: page → (slots) → layouts
|
|
265
|
+
const Page = pick(opts.page, "default", "Page", "page");
|
|
266
|
+
let tree = createElement(Page, { params: ctx.params, loaderData });
|
|
267
|
+
if (opts.isClient) {
|
|
268
|
+
tree = createElement("div", { id: "__sr_island_root", "data-sr-params": JSON.stringify(ctx.params) }, tree);
|
|
269
|
+
}
|
|
270
|
+
const layouts = opts.layouts || [];
|
|
271
|
+
const slotsByLayout = opts.slots || [];
|
|
272
|
+
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
273
|
+
const Layout = pick(layouts[i], "default", "Layout", "layout");
|
|
274
|
+
if (!Layout) continue;
|
|
275
|
+
const slotProps = {};
|
|
276
|
+
for (const slot of slotsByLayout[i] || []) {
|
|
277
|
+
const SlotComp = pick(slot.mod, "default", "Page", "Fragment", "page", "fragment");
|
|
278
|
+
if (SlotComp) slotProps[slot.name] = createElement(SlotComp, {});
|
|
279
|
+
}
|
|
280
|
+
tree = createElement(Layout, slotProps, tree);
|
|
281
|
+
}
|
|
282
|
+
const body = await renderTree(tree);
|
|
283
|
+
g.__SR_ROUTE_CTX__.current = null;
|
|
284
|
+
|
|
285
|
+
// head: captured assets (metadata stripped) + per-request metadata + seo
|
|
286
|
+
let head = stripMeta(opts.head || "");
|
|
287
|
+
head += metaHead;
|
|
288
|
+
if (/<title/i.test(seoHead)) head = head.replace(/<title>[\s\S]*?<\/title>/i, "");
|
|
289
|
+
head += seoHead;
|
|
290
|
+
|
|
291
|
+
const stateScript =
|
|
292
|
+
serverState !== undefined ? `<script>window.__SR_STATE__=${JSON.stringify(serverState).replace(/</g, "\\u003c")}</script>` : "";
|
|
293
|
+
const islandScript = opts.isClient && opts.islandSrc ? `<script type="module" src="${opts.islandSrc}"></script>` : "";
|
|
294
|
+
const html = `<!DOCTYPE html><html lang="${ctx.__locale || "en"}"><head>${head}</head><body>${body}${opts.bodyScripts || ""}${stateScript}${islandScript}</body></html>`;
|
|
295
|
+
|
|
296
|
+
// revalidate → Cache-Control + tags
|
|
297
|
+
let plan = opts.configRevalidate != null ? { ttl: opts.configRevalidate } : undefined;
|
|
298
|
+
const revFn = pick(opts.revalidate || {}, "default", "revalidate");
|
|
299
|
+
if (typeof revFn === "function") {
|
|
300
|
+
const p = await revFn(Object.assign({}, ctx, { data: loaderData, afterAction: ctx.method !== "GET" }));
|
|
301
|
+
if (p && typeof p === "object") plan = { ...plan, ...p };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const headers = new Headers({ "content-type": "text/html; charset=utf-8", "x-swift-rust-runtime": opts.runtime || "bun" });
|
|
305
|
+
for (const [k, v] of Object.entries(opts.config?.headers || {})) headers.set(k, String(v));
|
|
306
|
+
const cc = cacheControl(plan);
|
|
307
|
+
if (cc) headers.set("cache-control", cc);
|
|
308
|
+
const tags = plan?.tags || plan?.invalidate;
|
|
309
|
+
if (Array.isArray(tags) && tags.length) headers.set("x-vercel-cache-tags", tags.join(","));
|
|
310
|
+
for (const c of setCookies) headers.append("set-cookie", c);
|
|
311
|
+
return new Response(html, { headers });
|
|
312
|
+
} catch (err) {
|
|
313
|
+
const resp = thrownToResponse(err, url);
|
|
314
|
+
if (resp) return resp;
|
|
315
|
+
return new Response(`Internal Error: ${err?.message || err}`, { status: 500 });
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
// Swift-Rust client navigator — turns full-page loads into SPA navigation for
|
|
2
|
+
// <a>/<Link>. Intercepts same-origin clicks, fetches the destination HTML,
|
|
3
|
+
// swaps <body>, re-runs body scripts (island bootstrap + serialized state),
|
|
4
|
+
// syncs <title>/meta, and manages history. Ships in dev and in the build
|
|
5
|
+
// output (NOT dev-only like the HMR client).
|
|
6
|
+
(() => {
|
|
7
|
+
if (window.__SR_NAV__) return;
|
|
8
|
+
const nav = (window.__SR_NAV__ = { cache: new Map(), inflight: new Map() });
|
|
9
|
+
const ORIGIN = location.origin;
|
|
10
|
+
const MAX_CACHE = 32;
|
|
11
|
+
|
|
12
|
+
function internalAnchor(a) {
|
|
13
|
+
if (!a || a.target === "_blank" || a.hasAttribute("download")) return null;
|
|
14
|
+
if (a.dataset.srNoNav !== undefined) return null;
|
|
15
|
+
const raw = a.getAttribute("href");
|
|
16
|
+
if (!raw || raw.startsWith("#") || raw.startsWith("mailto:") || raw.startsWith("tel:")) return null;
|
|
17
|
+
let url;
|
|
18
|
+
try {
|
|
19
|
+
url = new URL(a.href, location.href);
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (url.origin !== ORIGIN) return null;
|
|
24
|
+
return url;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function remember(key, html) {
|
|
28
|
+
if (nav.cache.size >= MAX_CACHE) nav.cache.delete(nav.cache.keys().next().value);
|
|
29
|
+
nav.cache.set(key, html);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Fetch (and cache) a route's HTML. Deduped per URL so prefetch + click share.
|
|
33
|
+
function fetchDoc(url) {
|
|
34
|
+
const key = url;
|
|
35
|
+
if (nav.cache.has(key)) return Promise.resolve(nav.cache.get(key));
|
|
36
|
+
if (nav.inflight.has(key)) return nav.inflight.get(key);
|
|
37
|
+
const p = fetch(url, { headers: { "x-swift-rust-nav": "1" }, credentials: "same-origin" })
|
|
38
|
+
.then((res) => {
|
|
39
|
+
if (!res.ok && res.status !== 404) throw new Error("nav fetch " + res.status);
|
|
40
|
+
return res.text();
|
|
41
|
+
})
|
|
42
|
+
.then((html) => {
|
|
43
|
+
remember(key, html);
|
|
44
|
+
nav.inflight.delete(key);
|
|
45
|
+
return html;
|
|
46
|
+
})
|
|
47
|
+
.catch((err) => {
|
|
48
|
+
nav.inflight.delete(key);
|
|
49
|
+
throw err;
|
|
50
|
+
});
|
|
51
|
+
nav.inflight.set(key, p);
|
|
52
|
+
return p;
|
|
53
|
+
}
|
|
54
|
+
nav.prefetch = (url) => fetchDoc(new URL(url, location.href).href).catch(() => {});
|
|
55
|
+
|
|
56
|
+
// Scripts inserted via DOM cloning don't execute; clone them into fresh nodes.
|
|
57
|
+
function runScripts(root) {
|
|
58
|
+
for (const old of root.querySelectorAll("script")) {
|
|
59
|
+
const s = document.createElement("script");
|
|
60
|
+
for (const att of old.attributes) s.setAttribute(att.name, att.value);
|
|
61
|
+
s.textContent = old.textContent;
|
|
62
|
+
old.replaceWith(s);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// transition.tsx → wrap the DOM swap in the View Transitions API. Config is
|
|
67
|
+
// injected as window.__SR_TRANSITION__ = { type, duration }. Falls back to a
|
|
68
|
+
// plain swap when unsupported, type "none", or reduced-motion is requested.
|
|
69
|
+
function injectTransitionStyle() {
|
|
70
|
+
if (document.getElementById("__sr-transition-style")) return;
|
|
71
|
+
const s = document.createElement("style");
|
|
72
|
+
s.id = "__sr-transition-style";
|
|
73
|
+
s.textContent =
|
|
74
|
+
"::view-transition-old(root),::view-transition-new(root){animation-duration:var(--sr-transition-duration,250ms)}" +
|
|
75
|
+
'html[data-sr-transition="slide"]::view-transition-old(root){animation-name:sr-vt-slide-out}' +
|
|
76
|
+
'html[data-sr-transition="slide"]::view-transition-new(root){animation-name:sr-vt-slide-in}' +
|
|
77
|
+
"@keyframes sr-vt-slide-out{to{opacity:0;transform:translateX(-24px)}}" +
|
|
78
|
+
"@keyframes sr-vt-slide-in{from{opacity:0;transform:translateX(24px)}}";
|
|
79
|
+
(document.head || document.documentElement).appendChild(s);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function withTransition(apply) {
|
|
83
|
+
const t = window.__SR_TRANSITION__;
|
|
84
|
+
const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
85
|
+
if (!t || !t.type || t.type === "none" || reduce || typeof document.startViewTransition !== "function") {
|
|
86
|
+
apply();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const root = document.documentElement;
|
|
90
|
+
root.dataset.srTransition = t.type;
|
|
91
|
+
if (t.duration) root.style.setProperty("--sr-transition-duration", t.duration + "ms");
|
|
92
|
+
try {
|
|
93
|
+
const vt = document.startViewTransition(() => apply());
|
|
94
|
+
await vt.finished;
|
|
95
|
+
} catch {
|
|
96
|
+
// DOM was already updated inside the callback; nothing to recover.
|
|
97
|
+
} finally {
|
|
98
|
+
delete root.dataset.srTransition;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function syncHead(doc) {
|
|
103
|
+
const title = doc.querySelector("title");
|
|
104
|
+
if (title) document.title = title.textContent || document.title;
|
|
105
|
+
const selectors = ['meta[name="description"]', 'meta[property^="og:"]', 'meta[name^="twitter:"]', 'link[rel="canonical"]'];
|
|
106
|
+
for (const sel of selectors) {
|
|
107
|
+
document.head.querySelectorAll(sel).forEach((m) => m.remove());
|
|
108
|
+
doc.head.querySelectorAll(sel).forEach((m) => document.head.appendChild(m.cloneNode(true)));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// pending.tsx overlay: revealed only if a navigation outlasts the threshold,
|
|
113
|
+
// so fast (cached) navigations don't flash it.
|
|
114
|
+
let pendingTimer = null;
|
|
115
|
+
function showPending() {
|
|
116
|
+
const el = document.getElementById("__sr-pending");
|
|
117
|
+
if (el) el.hidden = false;
|
|
118
|
+
}
|
|
119
|
+
function clearPending() {
|
|
120
|
+
if (pendingTimer) {
|
|
121
|
+
clearTimeout(pendingTimer);
|
|
122
|
+
pendingTimer = null;
|
|
123
|
+
}
|
|
124
|
+
const el = document.getElementById("__sr-pending");
|
|
125
|
+
if (el) el.hidden = true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function navigate(href, { push = true, scroll = true, replace = false } = {}) {
|
|
129
|
+
let html;
|
|
130
|
+
nav.active = href;
|
|
131
|
+
if (pendingTimer) clearTimeout(pendingTimer);
|
|
132
|
+
const delay = typeof window.__SR_NAV_PENDING_DELAY === "number" ? window.__SR_NAV_PENDING_DELAY : 120;
|
|
133
|
+
pendingTimer = setTimeout(showPending, delay);
|
|
134
|
+
window.dispatchEvent(new CustomEvent("sr:navigate-start", { detail: { url: href } }));
|
|
135
|
+
try {
|
|
136
|
+
html = await fetchDoc(href);
|
|
137
|
+
} catch {
|
|
138
|
+
location.href = href; // hard fallback
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (nav.active !== href) return; // superseded by a newer navigation
|
|
142
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
143
|
+
if (!doc.body) {
|
|
144
|
+
location.href = href;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const apply = () => {
|
|
148
|
+
document.body.replaceWith(doc.body);
|
|
149
|
+
runScripts(document.body);
|
|
150
|
+
syncHead(doc);
|
|
151
|
+
};
|
|
152
|
+
await withTransition(apply);
|
|
153
|
+
if (push) {
|
|
154
|
+
if (replace) history.replaceState({ srNav: true }, "", href);
|
|
155
|
+
else history.pushState({ srNav: true }, "", href);
|
|
156
|
+
}
|
|
157
|
+
if (scroll) window.scrollTo(0, 0);
|
|
158
|
+
clearPending();
|
|
159
|
+
window.dispatchEvent(new CustomEvent("sr:navigate-end", { detail: { url: href } }));
|
|
160
|
+
}
|
|
161
|
+
nav.navigate = navigate;
|
|
162
|
+
|
|
163
|
+
document.addEventListener(
|
|
164
|
+
"click",
|
|
165
|
+
(e) => {
|
|
166
|
+
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
167
|
+
const a = e.target.closest && e.target.closest("a");
|
|
168
|
+
const url = internalAnchor(a);
|
|
169
|
+
if (!url) return;
|
|
170
|
+
e.preventDefault();
|
|
171
|
+
if (url.href === location.href) return;
|
|
172
|
+
navigate(url.href, {
|
|
173
|
+
push: true,
|
|
174
|
+
scroll: a.dataset.srScroll !== "false",
|
|
175
|
+
replace: a.dataset.srReplace === "true",
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
false,
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
window.addEventListener("popstate", () => {
|
|
182
|
+
navigate(location.href, { push: false, scroll: false });
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// ── Prefetch (prefetch.ts) ────────────────────────────────────────────────
|
|
186
|
+
// Strategy comes from the per-route prefetch.ts, injected as
|
|
187
|
+
// window.__SR_PREFETCH__ = { strategy, margin? }. Default: "hover".
|
|
188
|
+
// Per-link opt-out via data-sr-prefetch="false".
|
|
189
|
+
function strategy() {
|
|
190
|
+
const c = window.__SR_PREFETCH__;
|
|
191
|
+
return (c && c.strategy) || "hover";
|
|
192
|
+
}
|
|
193
|
+
function prefetchableURL(a) {
|
|
194
|
+
if (!a || a.dataset.srPrefetch === "false") return null;
|
|
195
|
+
return internalAnchor(a);
|
|
196
|
+
}
|
|
197
|
+
function intent(e) {
|
|
198
|
+
if (strategy() !== "hover") return;
|
|
199
|
+
const a = e.target.closest && e.target.closest("a");
|
|
200
|
+
const url = prefetchableURL(a);
|
|
201
|
+
if (url && url.href !== location.href) nav.prefetch(url.href);
|
|
202
|
+
}
|
|
203
|
+
document.addEventListener("mouseover", intent, { passive: true });
|
|
204
|
+
document.addEventListener("focusin", intent);
|
|
205
|
+
document.addEventListener("touchstart", intent, { passive: true });
|
|
206
|
+
|
|
207
|
+
let io = null;
|
|
208
|
+
function scanViewport() {
|
|
209
|
+
if (io) {
|
|
210
|
+
io.disconnect();
|
|
211
|
+
io = null;
|
|
212
|
+
}
|
|
213
|
+
if (strategy() !== "viewport" || !("IntersectionObserver" in window)) return;
|
|
214
|
+
const margin = (window.__SR_PREFETCH__ && window.__SR_PREFETCH__.margin) || "200px";
|
|
215
|
+
io = new IntersectionObserver(
|
|
216
|
+
(entries) => {
|
|
217
|
+
for (const en of entries) {
|
|
218
|
+
if (!en.isIntersecting) continue;
|
|
219
|
+
const url = prefetchableURL(en.target);
|
|
220
|
+
if (url && url.href !== location.href) nav.prefetch(url.href);
|
|
221
|
+
io.unobserve(en.target);
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{ rootMargin: margin },
|
|
225
|
+
);
|
|
226
|
+
document.querySelectorAll("a[href]").forEach((a) => {
|
|
227
|
+
if (prefetchableURL(a)) io.observe(a);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
window.addEventListener("sr:navigate-end", scanViewport);
|
|
231
|
+
if (document.readyState === "loading") {
|
|
232
|
+
document.addEventListener("DOMContentLoaded", scanViewport, { once: true });
|
|
233
|
+
} else {
|
|
234
|
+
scanViewport();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
injectTransitionStyle();
|
|
238
|
+
})();
|
package/dist/head.d.ts
CHANGED
|
@@ -9,13 +9,13 @@ export interface HeadProps {
|
|
|
9
9
|
export declare function Head({ children }: HeadProps): ReactNode;
|
|
10
10
|
export declare function Title({ children }: {
|
|
11
11
|
children: ReactNode;
|
|
12
|
-
}): import("react").JSX.Element;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
export declare function Meta({ name, content, property, }: {
|
|
14
14
|
name?: string;
|
|
15
15
|
property?: string;
|
|
16
16
|
content: string;
|
|
17
|
-
}): import("react").JSX.Element;
|
|
17
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
18
18
|
export declare function Style({ children }: {
|
|
19
19
|
children: ReactNode;
|
|
20
|
-
}): import("react").JSX.Element;
|
|
20
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
21
21
|
//# sourceMappingURL=head.d.ts.map
|
package/dist/head.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../src/head.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,aAE3C;AAED,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE
|
|
1
|
+
{"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../src/head.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,aAE3C;AAED,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAE1D;AAED,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,OAAO,EACP,QAAQ,GACT,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,2CAMA;AAED,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAK1D"}
|
package/dist/head.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function Head({ children }) {
|
|
3
|
+
return children;
|
|
4
|
+
}
|
|
5
|
+
export function Title({ children }) {
|
|
6
|
+
return _jsx("title", { children: children });
|
|
7
|
+
}
|
|
8
|
+
export function Meta({ name, content, property, }) {
|
|
9
|
+
return name ? (_jsx("meta", { name: name, content: content })) : (_jsx("meta", { property: property, content: content }));
|
|
10
|
+
}
|
|
11
|
+
export function Style({ children }) {
|
|
12
|
+
return (_jsx("style", { dangerouslySetInnerHTML: { __html: typeof children === "string" ? children : "" } }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=head.js.map
|
package/dist/head.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head.js","sourceRoot":"","sources":["../src/head.tsx"],"names":[],"mappings":";AAUA,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAa;IAC1C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAA2B;IACzD,OAAO,0BAAQ,QAAQ,GAAS,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,EACnB,IAAI,EACJ,OAAO,EACP,QAAQ,GAKT;IACC,OAAO,IAAI,CAAC,CAAC,CAAC,CACZ,eAAM,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAI,CACvC,CAAC,CAAC,CAAC,CACF,eAAM,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAI,CAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAA2B;IACzD,OAAO,CAEL,gBAAO,uBAAuB,EAAE,EAAE,MAAM,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,GAAI,CAC7F,CAAC;AACJ,CAAC"}
|
package/dist/link.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
|
6
6
|
replace?: boolean;
|
|
7
7
|
scroll?: boolean;
|
|
8
8
|
}
|
|
9
|
-
export declare function Link({ href, prefetch
|
|
9
|
+
export declare function Link({ href, prefetch, replace, scroll, children, ...rest }: LinkProps): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
//# sourceMappingURL=link.d.ts.map
|
package/dist/link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7D,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7D,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,2CAYrF"}
|
package/dist/link.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function Link({ href, prefetch, replace, scroll, children, ...rest }) {
|
|
3
|
+
// The client navigator (runtime/navigator.js) reads these data-* hints to
|
|
4
|
+
// drive SPA navigation. Plain <a> semantics are preserved when JS is off.
|
|
5
|
+
const dataAttrs = {};
|
|
6
|
+
if (replace)
|
|
7
|
+
dataAttrs["data-sr-replace"] = "true";
|
|
8
|
+
if (scroll === false)
|
|
9
|
+
dataAttrs["data-sr-scroll"] = "false";
|
|
10
|
+
if (prefetch === false)
|
|
11
|
+
dataAttrs["data-sr-prefetch"] = "false";
|
|
12
|
+
return (_jsx("a", { href: href, ...dataAttrs, ...rest, children: children }));
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=link.js.map
|
package/dist/link.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link.js","sourceRoot":"","sources":["../src/link.tsx"],"names":[],"mappings":";AAUA,MAAM,UAAU,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAa;IACpF,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,IAAI,OAAO;QAAE,SAAS,CAAC,iBAAiB,CAAC,GAAG,MAAM,CAAC;IACnD,IAAI,MAAM,KAAK,KAAK;QAAE,SAAS,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC;IAC5D,IAAI,QAAQ,KAAK,KAAK;QAAE,SAAS,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC;IAChE,OAAO,CACL,YAAG,IAAI,EAAE,IAAI,KAAM,SAAS,KAAM,IAAI,YACnC,QAAQ,GACP,CACL,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swift-rust",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "The full-stack React framework powered with Rust + Bun. TSX-first, Rust rendering, 10x faster than Next.js, single binary deploy.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://swift-rust.dev",
|
package/dist/head.jsx
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export function Head({ children }) {
|
|
2
|
-
return children;
|
|
3
|
-
}
|
|
4
|
-
export function Title({ children }) {
|
|
5
|
-
return <title>{children}</title>;
|
|
6
|
-
}
|
|
7
|
-
export function Meta({ name, content, property, }) {
|
|
8
|
-
return name ? (<meta name={name} content={content}/>) : (<meta property={property} content={content}/>);
|
|
9
|
-
}
|
|
10
|
-
export function Style({ children }) {
|
|
11
|
-
return (
|
|
12
|
-
// biome-ignore lint/security/noDangerouslySetInnerHtml: <style> contents are static CSS at build time
|
|
13
|
-
<style dangerouslySetInnerHTML={{ __html: typeof children === "string" ? children : "" }}/>);
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=head.jsx.map
|
package/dist/head.jsx.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"head.jsx","sourceRoot":"","sources":["../src/head.tsx"],"names":[],"mappings":"AAUA,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAa;IAC1C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAA2B;IACzD,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,EACnB,IAAI,EACJ,OAAO,EACP,QAAQ,GAKT;IACC,OAAO,IAAI,CAAC,CAAC,CAAC,CACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAG,CACvC,CAAC,CAAC,CAAC,CACF,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAG,CAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAA2B;IACzD,OAAO;IACL,sGAAsG;IACtG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAG,CAC7F,CAAC;AACJ,CAAC"}
|