Skip to content

Commit 9e2b4d5

Browse files
committed
added frontend to backend glue
1 parent 7cf1736 commit 9e2b4d5

7 files changed

Lines changed: 173 additions & 9 deletions

File tree

apps/backend/src/lib/all.remote.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './remote/auth.remote';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "$backend/all.remote.js";
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script lang="ts">
2+
import { loginWithEmail } from "$lib/all.remote";
3+
4+
5+
</script>
6+
7+
<main class="flex min-h-screen items-center justify-center">
8+
<form {...loginWithEmail}>
9+
<fieldset class="flex flex-col gap-4" disabled={!!loginWithEmail.pending}>
10+
<label class="text-sm" for="email">
11+
Email
12+
<input
13+
class="block border p-1"
14+
placeholder="test@example.com"
15+
autocomplete="email"
16+
{...loginWithEmail.fields.email.as('email')}
17+
/>
18+
</label>
19+
<button type="submit" class="bg-primary">Submit</button>
20+
</fieldset>
21+
</form>
22+
</main>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<script lang="ts">
2+
import { verifyOTPForm } from "$lib/all.remote";
3+
</script>
4+
5+
<main class="flex min-h-screen items-center justify-center">
6+
<form {...verifyOTPForm}>
7+
<fieldset class="flex flex-col gap-4" disabled={!!verifyOTPForm.pending}>
8+
<label class="text-sm">
9+
One Time Password
10+
<input
11+
class="block border p-1"
12+
placeholder="000000"
13+
autocomplete="off"
14+
{...verifyOTPForm.fields.otp.as('number')}
15+
/>
16+
</label>
17+
<button type="submit" class="bg-primary">Submit</button>
18+
</fieldset>
19+
</form>
20+
</main>

apps/frontend/src/routes/+page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
let { data: propData } = $props();
88
9-
9+
1010
</script>
1111

1212
<div class="flex justify-center items-center min-h-screen">
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Disables access to DOM typings like `HTMLElement` which are not available
2+
// inside a service worker and instantiates the correct globals
3+
/// <reference no-default-lib="true"/>
4+
/// <reference lib="esnext" />
5+
/// <reference lib="webworker" />
6+
7+
// Ensures that the `$service-worker` import has proper type definitions
8+
/// <reference types="@sveltejs/kit" />
9+
10+
// Only necessary if you have an import from `$env/static/public`
11+
/// <reference types="../.svelte-kit/ambient.d.ts" />
12+
13+
import { build, files, version } from '$service-worker';
14+
// import { PUBLIC_BACKEND_HOST, PUBLIC_BACKEND_INSECURE } from '$env/static/public';
15+
const PUBLIC_BACKEND_HOST = null;
16+
const PUBLIC_BACKEND_INSECURE = null;
17+
18+
// This gives `self` the correct types
19+
const self = globalThis.self as unknown as ServiceWorkerGlobalScope;
20+
21+
const dev = self.location.hostname === 'localhost';
22+
23+
// Force service worker to activate immediately and claim all clients
24+
self.addEventListener('install', (event) => {
25+
self.skipWaiting(); // Force activate new service worker immediately
26+
});
27+
28+
self.addEventListener('activate', (event) => {
29+
event.waitUntil(self.clients.claim()); // Take control of all clients immediately
30+
});
31+
32+
// Switch this to your production domain like api.example.com.
33+
// For now this is the backend dev server.
34+
const productionHost = PUBLIC_BACKEND_HOST || 'localhost:5174';
35+
// Switch this to true if your production domain has TLS.
36+
const productionSecure = !PUBLIC_BACKEND_INSECURE || !dev;
37+
38+
self.addEventListener('fetch', (event) => {
39+
const url = new URL(event.request.url);
40+
if (!url.pathname.startsWith('/_app/remote/')) return;
41+
42+
const newUrl = new URL(event.request.url);
43+
newUrl.host = dev ? 'localhost:5174' : productionHost;
44+
newUrl.protocol = productionSecure ? 'https:' : 'http:';
45+
46+
async function respond() {
47+
try {
48+
const req = event.request.clone();
49+
const headers = new Headers(req.headers);
50+
// Always mark as remote function call to ensure CORS headers
51+
headers.set('X-SvelteKit-Remote', 'true');
52+
53+
const init: RequestInit = {
54+
method: req.method,
55+
headers,
56+
credentials: 'include',
57+
referrer: req.referrer,
58+
referrerPolicy: req.referrerPolicy,
59+
redirect: req.redirect,
60+
cache: req.cache,
61+
};
62+
63+
if (req.method !== 'GET' && req.method !== 'HEAD') {
64+
// Use arrayBuffer for binary-safe forwarding, then convert back
65+
const bodyBuffer = await req.arrayBuffer();
66+
init.body = bodyBuffer.byteLength > 0 ? bodyBuffer : null;
67+
}
68+
69+
const response = await fetch(newUrl.toString(), init);
70+
71+
// Validate response before returning
72+
if (!response.ok) {
73+
console.error(
74+
`[SW] Backend error ${response.status}: ${response.statusText} for ${newUrl}`
75+
);
76+
return new Response(
77+
JSON.stringify({
78+
type: 'error',
79+
status: response.status,
80+
error: `Backend server error: ${response.statusText}`,
81+
}),
82+
{
83+
status: response.status,
84+
headers: { 'Content-Type': 'application/json' },
85+
}
86+
);
87+
}
88+
89+
return response;
90+
} catch (error) {
91+
console.error(`[SW] Network error for ${newUrl}:`, error);
92+
return new Response(
93+
JSON.stringify({
94+
type: 'error',
95+
status: 503,
96+
error: 'Backend server unreachable',
97+
}),
98+
{
99+
status: 503,
100+
headers: { 'Content-Type': 'application/json' },
101+
}
102+
);
103+
}
104+
}
105+
106+
event.respondWith(respond());
107+
});

apps/frontend/svelte.config.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
1-
// Tauri doesn't have a Node.js server to do proper SSR
2-
// so we will use adapter-static to prerender the app (SSG)
3-
// See: https://v2.tauri.app/start/frontend/sveltekit/ for more info
4-
import adapter from "@sveltejs/adapter-static";
5-
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
6-
import sveltePreprocess from "svelte-preprocess";
1+
import adapter from '@sveltejs/adapter-static';
2+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
73

84
/** @type {import('@sveltejs/kit').Config} */
95
const config = {
10-
preprocess: sveltePreprocess(),
6+
// Consult https://svelte.dev/docs/kit/integrations
7+
// for more information about preprocessors
8+
preprocess: vitePreprocess(),
9+
1110
kit: {
12-
adapter: adapter(),
11+
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
12+
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
13+
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
14+
adapter: adapter({ fallback: 'index.html' }),
15+
alias: {
16+
'$backend/*': '../backend/src/lib/*',
17+
},
18+
experimental: {
19+
remoteFunctions: true,
20+
},
21+
},
22+
compilerOptions: {
23+
experimental: {
24+
async: true,
25+
},
1326
},
1427
};
1528

0 commit comments

Comments
 (0)