Skip to content

Commit d82f73c

Browse files
authored
feat(back): file system routes and forms (#66)
* feat(api): saveFile * feat(api): saveFile * feat(back): filesystem complete * fix(back): reviews * refactor(back): generic fs * fix(back): fs naming convention * fix(back): fs naming convention * fix: pnpm lock
1 parent 4fe527e commit d82f73c

50 files changed

Lines changed: 1217 additions & 347 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
VITE_API_BASE_URL=http://localhost:3000
1+
# Leave empty for local environment / no api authentication
2+
API_URL=http://localhost:3000
3+
4+
# Set to production
5+
NODE_ENV=development
6+
7+
# Leaving this empty will generate a new unique random session secret at start
8+
SESSION_SECRET=

eslint.config.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ export default [
2323
},
2424
{
2525
rules: {
26-
'no-console': 'error',
2726
'svelte/no-unused-svelte-ignore': 'off',
2827
},
2928
},

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,8 @@
108108
"src/**/*.{ts,svelte}": [
109109
"eslint --fix"
110110
]
111+
},
112+
"dependencies": {
113+
"svelte-kit-sessions": "catalog:core"
111114
}
112115
}

pnpm-lock.yaml

Lines changed: 150 additions & 109 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ catalogs:
2121
svelte: ^5.48.0
2222
svelte-check: ^4.3.5
2323
vite: ^7.3.1
24+
svelte-kit-sessions: "^0.4.0"
2425
css:
2526
'@alexanderniebuhr/prettier-plugin-unocss': ^0.0.4
2627
'@unocss/extractor-svelte': ^66.6.3

src/app.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ declare global {
1010
}
1111
}
1212

13+
declare module 'svelte-kit-sessions' {
14+
interface SessionData {
15+
path: string;
16+
}
17+
}
18+
1319
export {};

src/demo.spec.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/hooks.server.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1+
import { env } from '$env/dynamic/private';
12
import { paraglideMiddleware } from '$lib/paraglide/server';
2-
import type { Handle } from '@sveltejs/kit';
3+
import { type Handle, redirect } from '@sveltejs/kit';
4+
import { sequence } from '@sveltejs/kit/hooks';
5+
import * as crypto from 'node:crypto';
6+
import { sveltekitSessionHandle } from 'svelte-kit-sessions';
7+
8+
if (!env.SESSION_SECRET) {
9+
env.SESSION_SECRET = crypto.randomBytes(20).toString('hex');
10+
console.log(`SESSION_SECRET not found, generating a temporary one: ${env.SESSION_SECRET}`);
11+
}
12+
13+
const sessionHandle = sveltekitSessionHandle({
14+
secret: env.SESSION_SECRET,
15+
});
16+
17+
const checkAuthorizationHandle: Handle = async ({ event, resolve }) => {
18+
if (!event.locals.session.data.path && event.url.pathname !== '/load-project') {
19+
throw redirect(302, '/load-project');
20+
}
21+
return resolve(event);
22+
};
323

424
const handleParaglide: Handle = ({ event, resolve }) =>
525
paraglideMiddleware(event.request, ({ request, locale }) => {
@@ -10,4 +30,4 @@ const handleParaglide: Handle = ({ event, resolve }) =>
1030
});
1131
});
1232

13-
export const handle: Handle = handleParaglide;
33+
export const handle: Handle = sequence(sessionHandle, handleParaglide, checkAuthorizationHandle);
Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,77 @@ export interface MiddlewareParams {
66
options: RequestOptions;
77
}
88

9-
export type MiddlewareNext = (params?: MiddlewareParams) => Promise<Response>;
9+
export type FullResponse = Response & { content: any };
10+
11+
export type MiddlewareNext = (params?: MiddlewareParams) => Promise<FullResponse>;
1012

1113
export type Middleware = (
1214
params: MiddlewareParams,
1315
next: MiddlewareNext,
14-
) => Promise<Response | undefined> | undefined;
16+
) => Promise<FullResponse | undefined> | undefined;
1517

16-
type BaseRequest = (path: string, options: RequestOptions) => Promise<Response>;
18+
type BaseRequest = (path: string, options: RequestOptions) => Promise<FullResponse>;
1719

1820
export class HttpClient {
1921
private readonly _baseUrl: string;
2022
private readonly _baseOptions: RequestOptions;
2123
private readonly _middlewares: Middleware[];
2224

23-
constructor(baseUrl: string) {
25+
constructor(baseUrl: string, options?: RequestOptions) {
2426
this._baseUrl = baseUrl;
25-
this._baseOptions = {};
27+
this._baseOptions = options ?? {
28+
headers: {
29+
'Content-Type': 'application/json',
30+
},
31+
};
2632
this._middlewares = [];
2733
}
2834

29-
get(path: string, options?: RequestOptions): Promise<Response> {
35+
get(path: string, options?: RequestOptions): Promise<FullResponse> {
3036
return this._applyMiddlewares(path, options, (newPath, newOptions) => {
31-
return fetch(newPath, {
37+
return this._request(newPath, {
3238
...newOptions,
3339
method: 'GET',
3440
});
3541
});
3642
}
3743

38-
post(path: string, body?: any, options?: RequestOptions): Promise<Response> {
44+
post(path: string, body?: string, options?: RequestOptions): Promise<FullResponse> {
3945
return this._applyMiddlewares(path, options, (newPath, newOptions) => {
40-
return fetch(newPath, {
46+
return this._request(newPath, {
4147
...newOptions,
4248
method: 'POST',
4349
body: body,
4450
});
4551
});
4652
}
4753

48-
put(path: string, body?: any, options?: RequestOptions): Promise<Response> {
54+
put(path: string, body?: string, options?: RequestOptions): Promise<FullResponse> {
4955
return this._applyMiddlewares(path, options, (newPath, newOptions) => {
50-
return fetch(newPath, {
56+
return this._request(newPath, {
5157
...newOptions,
5258
method: 'PUT',
5359
body: body,
5460
});
5561
});
5662
}
5763

58-
patch(path: string, body?: any, options?: RequestOptions): Promise<Response> {
59-
return this._applyMiddlewares(path, options, (newPath, newOptions) => {
60-
return fetch(newPath, {
64+
patch(path: string, body?: string, options?: RequestOptions): Promise<FullResponse> {
65+
return this._applyMiddlewares(path, options, async (newPath, newOptions) => {
66+
return this._request(newPath, {
6167
...newOptions,
6268
method: 'PATCH',
6369
body: body,
6470
});
6571
});
6672
}
6773

68-
delete(path: string, options?: RequestOptions): Promise<Response> {
74+
delete(path: string, options?: RequestOptions): Promise<FullResponse> {
6975
return this._applyMiddlewares(path, options, (newPath, newOptions) => {
70-
return fetch(newPath, {
76+
return this._request(newPath, {
7177
...newOptions,
7278
method: 'DELETE',
73-
});
79+
}) as Promise<FullResponse>;
7480
});
7581
}
7682

@@ -79,11 +85,17 @@ export class HttpClient {
7985
return this;
8086
}
8187

88+
private async _request(path: string, request: RequestInit): Promise<FullResponse> {
89+
const res = (await fetch(path, request)) as FullResponse;
90+
res.content = null;
91+
return res;
92+
}
93+
8294
private _applyMiddlewares(
8395
path: string,
8496
options: RequestOptions | undefined,
8597
callback: BaseRequest,
86-
): Promise<Response> {
98+
): Promise<FullResponse> {
8799
const baseParams = {
88100
path,
89101
fullPath: this._getUrl(path),
@@ -93,14 +105,14 @@ export class HttpClient {
93105
},
94106
};
95107
const middlewares = this._middlewares.slice();
96-
let response: Response;
108+
let response: FullResponse;
97109

98-
const execution = async (params?: MiddlewareParams): Promise<Response> => {
110+
const execution = async (params?: MiddlewareParams): Promise<FullResponse> => {
99111
if (!params) params = baseParams;
100112

101113
const middleware = middlewares.shift();
102114

103-
if (!middleware) response = (await callback(params.fullPath, params.options)) as Response;
115+
if (!middleware) response = (await callback(params.fullPath, params.options)) as FullResponse;
104116
else response = (await middleware(params, execution)) ?? response;
105117

106118
return response;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export class FileSystemError extends Error {
2+
message: string;
3+
constructor(message: string) {
4+
super();
5+
this.message = message;
6+
}
7+
}

0 commit comments

Comments
 (0)