Skip to content

Commit 512471d

Browse files
committed
Merge branch 'fix-importer'
2 parents 69364c2 + be03093 commit 512471d

27 files changed

Lines changed: 2687 additions & 352 deletions

services/web-importer/bun.lockb

19.2 KB
Binary file not shown.

services/web-importer/package.json

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,32 @@
44
"version": "0.0.1",
55
"type": "module",
66
"scripts": {
7-
"dev": "vite",
7+
"dev": "vite",
8+
"gen": "openapi-ts -i ../../tools/oathkeeper/bundled_openapi.yaml -o src/lib/sensorbucket -c @hey-api/client-fetch",
89
"build": "vite build",
910
"preview": "vite preview",
10-
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
11+
"check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
1112
},
1213
"devDependencies": {
13-
"@types/bun": "^1.2.11",
14-
"@types/papaparse": "^5.3.15",
15-
"@unocss/extractor-svelte": "^66.1.0-beta.12",
16-
"svelte-language-server": "^0.17.12",
17-
"typescript-svelte-plugin": "^0.3.46",
18-
"vitest": "^3.1.2",
19-
"@sveltejs/vite-plugin-svelte": "^5.0.3",
20-
"@tsconfig/svelte": "^5.0.4",
21-
"svelte": "^5.28.2",
22-
"svelte-check": "^4.1.6",
23-
"typescript": "~5.8.3",
24-
"vite": "^6.3.3"
14+
"@hey-api/openapi-ts": "^0.86.11",
15+
"@sveltejs/vite-plugin-svelte": "^6.2.1",
16+
"@tsconfig/svelte": "^5.0.5",
17+
"@types/bun": "^1.3.1",
18+
"@types/papaparse": "^5.3.16",
19+
"@unocss/extractor-svelte": "^66.5.4",
20+
"svelte": "^5.43.2",
21+
"svelte-check": "^4.3.3",
22+
"svelte-language-server": "^0.17.21",
23+
"typescript": "~5.9.3",
24+
"typescript-svelte-plugin": "^0.3.50",
25+
"vite": "^7.1.12",
26+
"vitest": "^4.0.5"
2527
},
2628
"dependencies": {
27-
"@hey-api/client-fetch": "^0.10.0",
28-
"bits-ui": "^1.4.1",
29-
"immer": "^10.1.1",
30-
"papaparse": "^5.5.2",
31-
"unocss": "^66.1.0-beta.12"
29+
"@hey-api/client-fetch": "^0.13.1",
30+
"bits-ui": "^2.14.1",
31+
"immer": "^10.2.0",
32+
"papaparse": "^5.5.3",
33+
"unocss": "^66.5.4"
3234
}
3335
}
Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
import {test, expect} from 'vitest';
2-
import {CSVParser} from "$lib/CSVParser";
1+
import { test, expect } from 'vitest';
2+
import { CSVParser } from "$lib/CSVParser";
33

44
test('CSVParser should call column parsers', async () => {
5-
const csvParser = new CSVParser({code: ""});
6-
csvParser.addColumn(/^device code$/g, () => (context, value) => {
7-
context.userData.code = value;
8-
})
9-
const file = 'other,data,notrelevant\ndevice code,device description,device properties\n1,2,3\n'
10-
const result = await csvParser.parse(file)
11-
expect(result.code == "1")
5+
const csvParser = new CSVParser({ code: "" });
6+
csvParser.addColumn(/^device code$/g, () => (context, value) => {
7+
context.userData.code = value;
8+
})
9+
const file = 'other,data,notrelevant\ndevice code,device description,device properties\n1,2,3\n'
10+
const result = await csvParser.parse(file)
11+
expect(result.code == "1")
1212
})
1313

1414
test('CSVParser should pass context to every onRowFinish', async () => {
15-
const csvParser = new CSVParser({code: "", other: "no"});
16-
csvParser.addColumn(/^device code$/g, () => (context, value) => {
17-
context.userData.code = value;
18-
})
19-
let pass = 0
20-
csvParser.afterRowParse = (context) => {
21-
if (pass === 0) {
22-
context.userData.other = "yes"
23-
} else {
24-
expect(context.userData.other === "yes");
25-
}
26-
pass++;
15+
const csvParser = new CSVParser({ code: "", other: "no" });
16+
csvParser.addColumn(/^device code$/g, () => (context, value) => {
17+
context.userData.code = value;
18+
})
19+
let pass = 0
20+
csvParser.afterRowParse = (context) => {
21+
if (pass === 0) {
22+
context.userData.other = "yes"
23+
} else {
24+
expect(context.userData.other === "yes");
2725
}
28-
const file = 'device code,device description,device properties\n1,2,3\n1,2,3\n'
29-
await csvParser.parse(file)
30-
})
26+
pass++;
27+
}
28+
const file = 'device code,device description,device properties\n1,2,3\n1,2,3\n'
29+
await csvParser.parse(file)
30+
})
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This file is auto-generated by @hey-api/openapi-ts
22

3-
import type { ClientOptions } from './types.gen';
4-
import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch';
3+
import { type ClientOptions, type Config, createClient, createConfig } from './client';
4+
import type { ClientOptions as ClientOptions2 } from './types.gen';
55

66
/**
77
* The `createClientConfig()` function will be called on client initialization
@@ -11,8 +11,8 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient,
1111
* `setConfig()`. This is useful for example if you're using Next.js
1212
* to ensure your client always has the correct values.
1313
*/
14-
export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
14+
export type CreateClientConfig<T extends ClientOptions = ClientOptions2> = (override?: Config<ClientOptions & T>) => Config<Required<ClientOptions> & T>;
1515

16-
export const client = createClient(createConfig<ClientOptions>({
16+
export const client = createClient(createConfig<ClientOptions2>({
1717
baseUrl: 'https://sensorbucket.nl/api'
18-
}));
18+
}));
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
// This file is auto-generated by @hey-api/openapi-ts
2+
3+
import { createSseClient } from '../core/serverSentEvents.gen';
4+
import type { HttpMethod } from '../core/types.gen';
5+
import { getValidRequestBody } from '../core/utils.gen';
6+
import type {
7+
Client,
8+
Config,
9+
RequestOptions,
10+
ResolvedRequestOptions,
11+
} from './types.gen';
12+
import {
13+
buildUrl,
14+
createConfig,
15+
createInterceptors,
16+
getParseAs,
17+
mergeConfigs,
18+
mergeHeaders,
19+
setAuthParams,
20+
} from './utils.gen';
21+
22+
type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
23+
body?: any;
24+
headers: ReturnType<typeof mergeHeaders>;
25+
};
26+
27+
export const createClient = (config: Config = {}): Client => {
28+
let _config = mergeConfigs(createConfig(), config);
29+
30+
const getConfig = (): Config => ({ ..._config });
31+
32+
const setConfig = (config: Config): Config => {
33+
_config = mergeConfigs(_config, config);
34+
return getConfig();
35+
};
36+
37+
const interceptors = createInterceptors<
38+
Request,
39+
Response,
40+
unknown,
41+
ResolvedRequestOptions
42+
>();
43+
44+
const beforeRequest = async (options: RequestOptions) => {
45+
const opts = {
46+
..._config,
47+
...options,
48+
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
49+
headers: mergeHeaders(_config.headers, options.headers),
50+
serializedBody: undefined,
51+
};
52+
53+
if (opts.security) {
54+
await setAuthParams({
55+
...opts,
56+
security: opts.security,
57+
});
58+
}
59+
60+
if (opts.requestValidator) {
61+
await opts.requestValidator(opts);
62+
}
63+
64+
if (opts.body !== undefined && opts.bodySerializer) {
65+
opts.serializedBody = opts.bodySerializer(opts.body);
66+
}
67+
68+
// remove Content-Type header if body is empty to avoid sending invalid requests
69+
if (opts.body === undefined || opts.serializedBody === '') {
70+
opts.headers.delete('Content-Type');
71+
}
72+
73+
const url = buildUrl(opts);
74+
75+
return { opts, url };
76+
};
77+
78+
const request: Client['request'] = async (options) => {
79+
// @ts-expect-error
80+
const { opts, url } = await beforeRequest(options);
81+
const requestInit: ReqInit = {
82+
redirect: 'follow',
83+
...opts,
84+
body: getValidRequestBody(opts),
85+
};
86+
87+
let request = new Request(url, requestInit);
88+
89+
for (const fn of interceptors.request.fns) {
90+
if (fn) {
91+
request = await fn(request, opts);
92+
}
93+
}
94+
95+
// fetch must be assigned here, otherwise it would throw the error:
96+
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
97+
const _fetch = opts.fetch!;
98+
let response = await _fetch(request);
99+
100+
for (const fn of interceptors.response.fns) {
101+
if (fn) {
102+
response = await fn(response, request, opts);
103+
}
104+
}
105+
106+
const result = {
107+
request,
108+
response,
109+
};
110+
111+
if (response.ok) {
112+
const parseAs =
113+
(opts.parseAs === 'auto'
114+
? getParseAs(response.headers.get('Content-Type'))
115+
: opts.parseAs) ?? 'json';
116+
117+
if (
118+
response.status === 204 ||
119+
response.headers.get('Content-Length') === '0'
120+
) {
121+
let emptyData: any;
122+
switch (parseAs) {
123+
case 'arrayBuffer':
124+
case 'blob':
125+
case 'text':
126+
emptyData = await response[parseAs]();
127+
break;
128+
case 'formData':
129+
emptyData = new FormData();
130+
break;
131+
case 'stream':
132+
emptyData = response.body;
133+
break;
134+
case 'json':
135+
default:
136+
emptyData = {};
137+
break;
138+
}
139+
return opts.responseStyle === 'data'
140+
? emptyData
141+
: {
142+
data: emptyData,
143+
...result,
144+
};
145+
}
146+
147+
let data: any;
148+
switch (parseAs) {
149+
case 'arrayBuffer':
150+
case 'blob':
151+
case 'formData':
152+
case 'json':
153+
case 'text':
154+
data = await response[parseAs]();
155+
break;
156+
case 'stream':
157+
return opts.responseStyle === 'data'
158+
? response.body
159+
: {
160+
data: response.body,
161+
...result,
162+
};
163+
}
164+
165+
if (parseAs === 'json') {
166+
if (opts.responseValidator) {
167+
await opts.responseValidator(data);
168+
}
169+
170+
if (opts.responseTransformer) {
171+
data = await opts.responseTransformer(data);
172+
}
173+
}
174+
175+
return opts.responseStyle === 'data'
176+
? data
177+
: {
178+
data,
179+
...result,
180+
};
181+
}
182+
183+
const textError = await response.text();
184+
let jsonError: unknown;
185+
186+
try {
187+
jsonError = JSON.parse(textError);
188+
} catch {
189+
// noop
190+
}
191+
192+
const error = jsonError ?? textError;
193+
let finalError = error;
194+
195+
for (const fn of interceptors.error.fns) {
196+
if (fn) {
197+
finalError = (await fn(error, response, request, opts)) as string;
198+
}
199+
}
200+
201+
finalError = finalError || ({} as string);
202+
203+
if (opts.throwOnError) {
204+
throw finalError;
205+
}
206+
207+
// TODO: we probably want to return error and improve types
208+
return opts.responseStyle === 'data'
209+
? undefined
210+
: {
211+
error: finalError,
212+
...result,
213+
};
214+
};
215+
216+
const makeMethodFn =
217+
(method: Uppercase<HttpMethod>) => (options: RequestOptions) =>
218+
request({ ...options, method });
219+
220+
const makeSseFn =
221+
(method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
222+
const { opts, url } = await beforeRequest(options);
223+
return createSseClient({
224+
...opts,
225+
body: opts.body as BodyInit | null | undefined,
226+
headers: opts.headers as unknown as Record<string, string>,
227+
method,
228+
onRequest: async (url, init) => {
229+
let request = new Request(url, init);
230+
for (const fn of interceptors.request.fns) {
231+
if (fn) {
232+
request = await fn(request, opts);
233+
}
234+
}
235+
return request;
236+
},
237+
url,
238+
});
239+
};
240+
241+
return {
242+
buildUrl,
243+
connect: makeMethodFn('CONNECT'),
244+
delete: makeMethodFn('DELETE'),
245+
get: makeMethodFn('GET'),
246+
getConfig,
247+
head: makeMethodFn('HEAD'),
248+
interceptors,
249+
options: makeMethodFn('OPTIONS'),
250+
patch: makeMethodFn('PATCH'),
251+
post: makeMethodFn('POST'),
252+
put: makeMethodFn('PUT'),
253+
request,
254+
setConfig,
255+
sse: {
256+
connect: makeSseFn('CONNECT'),
257+
delete: makeSseFn('DELETE'),
258+
get: makeSseFn('GET'),
259+
head: makeSseFn('HEAD'),
260+
options: makeSseFn('OPTIONS'),
261+
patch: makeSseFn('PATCH'),
262+
post: makeSseFn('POST'),
263+
put: makeSseFn('PUT'),
264+
trace: makeSseFn('TRACE'),
265+
},
266+
trace: makeMethodFn('TRACE'),
267+
} as Client;
268+
};

0 commit comments

Comments
 (0)