@riffyh/server 1.0.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.
@@ -0,0 +1,228 @@
1
+ import { Elysia } from "elysia";
2
+ import * as _$_riffyh_commons0 from "@riffyh/commons";
3
+
4
+ //#region src/index.d.ts
5
+ declare const server: Elysia<"", {
6
+ decorator: {};
7
+ store: {};
8
+ derive: {};
9
+ resolve: {};
10
+ }, {
11
+ typebox: {};
12
+ error: {};
13
+ } & {
14
+ typebox: {};
15
+ error: {};
16
+ } & {
17
+ typebox: {};
18
+ error: {};
19
+ }, {
20
+ schema: {};
21
+ standaloneSchema: {};
22
+ macro: {};
23
+ macroFn: {};
24
+ parser: {};
25
+ response: {};
26
+ } & {
27
+ schema: {};
28
+ standaloneSchema: {};
29
+ macro: {};
30
+ macroFn: {};
31
+ parser: {};
32
+ } & {
33
+ schema: {};
34
+ standaloneSchema: {};
35
+ macro: {};
36
+ macroFn: {};
37
+ parser: {};
38
+ response: {};
39
+ }, {
40
+ get: {
41
+ body: unknown;
42
+ params: {};
43
+ query: unknown;
44
+ headers: unknown;
45
+ response: {
46
+ 200: Response;
47
+ };
48
+ };
49
+ } & {
50
+ health: {
51
+ get: {
52
+ body: unknown;
53
+ params: {};
54
+ query: unknown;
55
+ headers: unknown;
56
+ response: {
57
+ 200: string;
58
+ };
59
+ };
60
+ };
61
+ } & {
62
+ dataSources: {
63
+ get: {
64
+ body: unknown;
65
+ params: {};
66
+ query: unknown;
67
+ headers: unknown;
68
+ response: {
69
+ 200: {
70
+ key: string;
71
+ name: string;
72
+ iconUrl: string;
73
+ }[];
74
+ 422: {
75
+ type: "validation";
76
+ on: string;
77
+ summary?: string;
78
+ message?: string;
79
+ found?: unknown;
80
+ property?: string;
81
+ expected?: string;
82
+ };
83
+ };
84
+ };
85
+ };
86
+ } & {
87
+ gallery: {
88
+ get: {
89
+ body: unknown;
90
+ params: {};
91
+ query: {
92
+ id: string;
93
+ dataSource: string;
94
+ };
95
+ headers: unknown;
96
+ response: {
97
+ 200: {
98
+ tags: {
99
+ key: string;
100
+ name: string;
101
+ type: _$_riffyh_commons0.TagType;
102
+ id: string;
103
+ slug: string;
104
+ }[];
105
+ key: string;
106
+ title: {
107
+ display: string;
108
+ original: string | null;
109
+ };
110
+ id: string;
111
+ cover: {
112
+ src: string;
113
+ width: number;
114
+ height: number;
115
+ };
116
+ pages: {
117
+ src: string;
118
+ width: number;
119
+ height: number;
120
+ order: number;
121
+ }[];
122
+ };
123
+ 422: {
124
+ type: "validation";
125
+ on: string;
126
+ summary?: string;
127
+ message?: string;
128
+ found?: unknown;
129
+ property?: string;
130
+ expected?: string;
131
+ };
132
+ };
133
+ };
134
+ };
135
+ } & {
136
+ listing: {
137
+ get: {
138
+ body: unknown;
139
+ params: {};
140
+ query: {
141
+ query?: string | undefined;
142
+ page: number;
143
+ dataSource: never;
144
+ };
145
+ headers: unknown;
146
+ response: {
147
+ 200: {
148
+ galleries: {
149
+ key: string;
150
+ title: {
151
+ display: string;
152
+ original: string | null;
153
+ };
154
+ id: string;
155
+ cover: {
156
+ src: string;
157
+ width: number;
158
+ height: number;
159
+ };
160
+ }[];
161
+ currentPage: number;
162
+ maximumPages: number;
163
+ };
164
+ 422: {
165
+ type: "validation";
166
+ on: string;
167
+ summary?: string;
168
+ message?: string;
169
+ found?: unknown;
170
+ property?: string;
171
+ expected?: string;
172
+ };
173
+ };
174
+ };
175
+ };
176
+ } & {
177
+ image: {
178
+ get: {
179
+ body: unknown;
180
+ params: {};
181
+ query: {
182
+ url: string;
183
+ dataSource: never;
184
+ format: "webp" | "jpg";
185
+ };
186
+ headers: unknown;
187
+ response: {
188
+ 200: Response;
189
+ 422: {
190
+ type: "validation";
191
+ on: string;
192
+ summary?: string;
193
+ message?: string;
194
+ found?: unknown;
195
+ property?: string;
196
+ expected?: string;
197
+ };
198
+ };
199
+ };
200
+ };
201
+ }, {
202
+ derive: {};
203
+ resolve: {};
204
+ schema: {};
205
+ standaloneSchema: {};
206
+ response: {};
207
+ }, {
208
+ derive: {};
209
+ resolve: {};
210
+ schema: {};
211
+ standaloneSchema: {};
212
+ response: {};
213
+ } & {
214
+ derive: {};
215
+ resolve: {};
216
+ schema: {};
217
+ standaloneSchema: {};
218
+ } & {
219
+ derive: {};
220
+ resolve: {};
221
+ schema: {};
222
+ standaloneSchema: {};
223
+ response: {};
224
+ }>;
225
+ type Server = typeof server;
226
+ //#endregion
227
+ export { Server };
228
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ import { Elysia, t } from "elysia";
3
+ import { swagger } from "@elysiajs/swagger";
4
+ import { cors } from "@elysiajs/cors";
5
+ import { defineCacheInstance } from "@rayriffy/filesystem";
6
+ import sharp from "sharp";
7
+ import { galleryModel, listingResultModel } from "@riffyh/commons";
8
+ import debug from "debug";
9
+ import path from "node:path";
10
+ //#region src/index.ts
11
+ const log = debug("riffyh:server");
12
+ const cache = defineCacheInstance();
13
+ log("warming up server...");
14
+ const configFile = process.env.RIFFYH_CONFIG_PATH || "./riffyh.config.ts";
15
+ const configPath = path.resolve(configFile);
16
+ log(`resolving config file at ${configPath}...`);
17
+ const config = await import(configPath).then((o) => o.default);
18
+ log(`loaded configuration with ${config.dataSources.length} data sources`);
19
+ const dataSourceKeys = t.Union(config.dataSources.map((o) => t.Literal(o.key)));
20
+ const server = new Elysia().use(swagger({ exclude: ["/_image"] })).use(cors()).get("/", ({ redirect }) => redirect("/swagger")).get("/health", () => "healthy").get("/dataSources", () => config.dataSources.map((o) => ({
21
+ key: o.key,
22
+ name: o.name,
23
+ iconUrl: o.iconUrl
24
+ })), { response: t.Array(t.Object({
25
+ key: t.String(),
26
+ name: t.String(),
27
+ iconUrl: t.String()
28
+ })) }).get("/gallery", async ({ query }) => {
29
+ const dataSource = config.dataSources.find((o) => o.key === query.dataSource);
30
+ if (dataSource === void 0) throw new Error(`data source ${query.dataSource} not found`);
31
+ return dataSource.getGallery({ id: query.id });
32
+ }, {
33
+ query: t.Object({
34
+ id: t.String(),
35
+ dataSource: t.String()
36
+ }),
37
+ response: galleryModel
38
+ }).get("/listing", async ({ query }) => {
39
+ const dataSource = config.dataSources.find((o) => o.key === query.dataSource);
40
+ if (dataSource === void 0) throw new Error(`data source ${query.dataSource} not found`);
41
+ return dataSource.getListing({
42
+ searchQuery: query.query || null,
43
+ page: query.page
44
+ });
45
+ }, {
46
+ query: t.Object({
47
+ query: t.Optional(t.String()),
48
+ page: t.Number(),
49
+ dataSource: dataSourceKeys
50
+ }),
51
+ response: listingResultModel
52
+ }).get("/image", async ({ query }) => {
53
+ const cacheKeys = [
54
+ query.dataSource,
55
+ query.url,
56
+ query.format
57
+ ];
58
+ const cachedImage = await cache.read(cacheKeys);
59
+ if (cachedImage !== null) return new Response(Buffer.from(cachedImage.data), { headers: { "Content-Type": `image/${query.format}` } });
60
+ const dataSource = config.dataSources.find((o) => o.key === query.dataSource);
61
+ if (dataSource === void 0) throw new Error(`data source ${query.dataSource} not found`);
62
+ const resizedImage = await sharp(await dataSource.getImage({ url: query.url })).resize({ width: 1280 }).toFormat(query.format, { quality: 72 }).toBuffer();
63
+ await cache.write(cacheKeys, resizedImage, 864e5);
64
+ return new Response(resizedImage, { headers: { "Content-Type": `image/${query.format}` } });
65
+ }, { query: t.Object({
66
+ url: t.String(),
67
+ format: t.Union([t.Literal("webp"), t.Literal("jpg")]),
68
+ dataSource: dataSourceKeys
69
+ }) }).listen(3e3);
70
+ console.log(`🦊 Elysia is running at http://${server.server?.hostname}:${server.server?.port}`);
71
+ //#endregion
72
+ export {};
73
+
74
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { t, Elysia } from \"elysia\";\nimport { swagger } from \"@elysiajs/swagger\";\nimport { cors } from \"@elysiajs/cors\";\nimport { defineCacheInstance } from \"@rayriffy/filesystem\";\nimport sharp from \"sharp\";\n\nimport { galleryModel, listingResultModel, type Config } from \"@riffyh/commons\";\nimport debug from \"debug\";\nimport path from \"node:path\";\n\nconst log = debug(\"riffyh:server\");\nconst cache = defineCacheInstance();\n\nlog(\"warming up server...\");\n\nconst configFile = process.env.RIFFYH_CONFIG_PATH || \"./riffyh.config.ts\";\nconst configPath = path.resolve(configFile);\nlog(`resolving config file at ${configPath}...`);\nconst config: Config = await import(configPath).then((o) => o.default);\n\nlog(`loaded configuration with ${config.dataSources.length} data sources`);\n\nconst dataSourceKeys = t.Union(config.dataSources.map((o) => t.Literal(o.key)));\n\nconst server = new Elysia()\n .use(\n swagger({\n exclude: [\"/_image\"],\n }),\n )\n .use(cors())\n .get(\"/\", ({ redirect }) => redirect(\"/swagger\"))\n .get(\"/health\", () => \"healthy\")\n .get(\n \"/dataSources\",\n () =>\n config.dataSources.map((o) => ({\n key: o.key,\n name: o.name,\n iconUrl: o.iconUrl,\n })),\n {\n response: t.Array(\n t.Object({\n key: t.String(),\n name: t.String(),\n iconUrl: t.String(),\n }),\n ),\n },\n )\n .get(\n \"/gallery\",\n async ({ query }) => {\n const dataSource = config.dataSources.find((o) => o.key === query.dataSource);\n if (dataSource === undefined) throw new Error(`data source ${query.dataSource} not found`);\n\n return dataSource.getGallery({\n id: query.id,\n });\n },\n {\n query: t.Object({\n id: t.String(),\n dataSource: t.String(),\n }),\n response: galleryModel,\n },\n )\n .get(\n \"/listing\",\n async ({ query }) => {\n const dataSource = config.dataSources.find((o) => o.key === query.dataSource);\n if (dataSource === undefined) throw new Error(`data source ${query.dataSource} not found`);\n\n return dataSource.getListing({\n searchQuery: query.query || null,\n page: query.page,\n });\n },\n {\n query: t.Object({\n query: t.Optional(t.String()),\n page: t.Number(),\n dataSource: dataSourceKeys,\n }),\n response: listingResultModel,\n },\n )\n .get(\n \"/image\",\n async ({ query }) => {\n const cacheKeys = [query.dataSource, query.url, query.format];\n\n const cachedImage = await cache.read<Buffer>(cacheKeys);\n if (cachedImage !== null)\n return new Response(Buffer.from(cachedImage.data), {\n headers: {\n \"Content-Type\": `image/${query.format}`,\n },\n });\n\n const dataSource = config.dataSources.find((o) => o.key === query.dataSource);\n if (dataSource === undefined) throw new Error(`data source ${query.dataSource} not found`);\n\n const fetchedImage = await dataSource.getImage({\n url: query.url,\n });\n const resizedImage = await sharp(fetchedImage)\n .resize({\n width: 1280,\n })\n .toFormat(query.format, {\n quality: 72,\n })\n .toBuffer();\n await cache.write(\n cacheKeys,\n resizedImage,\n 86_400_000, // 1 month\n );\n\n return new Response(resizedImage, {\n headers: {\n \"Content-Type\": `image/${query.format}`,\n },\n });\n },\n {\n query: t.Object({\n url: t.String(),\n format: t.Union([t.Literal(\"webp\"), t.Literal(\"jpg\")]),\n dataSource: dataSourceKeys,\n }),\n },\n )\n .listen(3000);\n\nexport type Server = typeof server;\n\nconsole.log(`🦊 Elysia is running at http://${server.server?.hostname}:${server.server?.port}`);\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@riffyh/server",
3
+ "version": "1.0.0",
4
+ "bin": "dist/index.mjs",
5
+ "main": "dist/index.mjs",
6
+ "types": "dist/index.d.mts",
7
+ "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/rayriffy/rayriffy-h.git"
11
+ },
12
+ "files": [
13
+ "dist/"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org"
18
+ },
19
+ "dependencies": {
20
+ "@elysiajs/cors": "1.4.1",
21
+ "@elysiajs/swagger": "1.3.1",
22
+ "@rayriffy/filesystem": "1.0.1",
23
+ "@sinclair/typebox": "0.34.49",
24
+ "debug": "4.4.3",
25
+ "elysia": "1.4.28",
26
+ "sharp": "^0.34.5",
27
+ "@riffyh/commons": "2.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/debug": "4.1.13",
31
+ "tsdown": "0.21.7"
32
+ },
33
+ "scripts": {
34
+ "test": "echo \"Error: no test specified\" && exit 1",
35
+ "dev": "bun run --watch src/index.ts",
36
+ "build": "tsdown",
37
+ "start": "bun run dist/index.mjs"
38
+ }
39
+ }