@riffyh/server 1.0.2 → 1.0.3

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/dist/index.d.mts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Elysia } from "elysia";
2
- import * as _$_riffyh_commons0 from "@riffyh/commons";
3
2
 
4
3
  //#region src/index.d.ts
5
4
  declare const server: Elysia<"", {
@@ -76,20 +75,9 @@ declare const server: Elysia<"", {
76
75
  query: unknown;
77
76
  headers: unknown;
78
77
  response: {
79
- 200: {
80
- key: string;
81
- name: string;
82
- iconUrl: string;
83
- }[];
84
- 422: {
85
- type: "validation";
86
- on: string;
87
- summary?: string;
88
- message?: string;
89
- found?: unknown;
90
- property?: string;
91
- expected?: string;
92
- };
78
+ [x: string]: any;
79
+ [x: number]: any;
80
+ [x: symbol]: any;
93
81
  };
94
82
  };
95
83
  };
@@ -104,41 +92,9 @@ declare const server: Elysia<"", {
104
92
  };
105
93
  headers: unknown;
106
94
  response: {
107
- 200: {
108
- tags: {
109
- key: string;
110
- name: string;
111
- id: string;
112
- slug: string;
113
- type: _$_riffyh_commons0.TagType;
114
- }[];
115
- key: string;
116
- title: {
117
- display: string;
118
- original: string | null;
119
- };
120
- id: string;
121
- cover: {
122
- src: string;
123
- width: number;
124
- height: number;
125
- };
126
- pages: {
127
- src: string;
128
- width: number;
129
- height: number;
130
- order: number;
131
- }[];
132
- };
133
- 422: {
134
- type: "validation";
135
- on: string;
136
- summary?: string;
137
- message?: string;
138
- found?: unknown;
139
- property?: string;
140
- expected?: string;
141
- };
95
+ [x: string]: any;
96
+ [x: number]: any;
97
+ [x: symbol]: any;
142
98
  };
143
99
  };
144
100
  };
@@ -149,37 +105,14 @@ declare const server: Elysia<"", {
149
105
  params: {};
150
106
  query: {
151
107
  query?: string | undefined;
152
- page: number;
153
108
  dataSource: never;
109
+ page: number;
154
110
  };
155
111
  headers: unknown;
156
112
  response: {
157
- 200: {
158
- galleries: {
159
- key: string;
160
- title: {
161
- display: string;
162
- original: string | null;
163
- };
164
- id: string;
165
- cover: {
166
- src: string;
167
- width: number;
168
- height: number;
169
- };
170
- }[];
171
- currentPage: number;
172
- maximumPages: number;
173
- };
174
- 422: {
175
- type: "validation";
176
- on: string;
177
- summary?: string;
178
- message?: string;
179
- found?: unknown;
180
- property?: string;
181
- expected?: string;
182
- };
113
+ [x: string]: any;
114
+ [x: number]: any;
115
+ [x: symbol]: any;
183
116
  };
184
117
  };
185
118
  };
@@ -237,10 +170,10 @@ declare const server: Elysia<"", {
237
170
  body: unknown;
238
171
  params: {};
239
172
  query: {
240
- type: "page" | "cover";
241
- url: string;
242
173
  dataSource: never;
243
- format: "avif" | "webp" | "jpg";
174
+ url: string;
175
+ format: "webp" | "jpeg";
176
+ type: "page" | "cover";
244
177
  };
245
178
  headers: unknown;
246
179
  response: {
package/dist/index.mjs CHANGED
@@ -116,11 +116,7 @@ const server = new Elysia().use(swagger({ exclude: ["/_image"] })).use(toon()).u
116
116
  } });
117
117
  }, { query: t.Object({
118
118
  url: t.String(),
119
- format: t.Union([
120
- t.Literal("avif"),
121
- t.Literal("webp"),
122
- t.Literal("jpg")
123
- ]),
119
+ format: t.Union([t.Literal("webp"), t.Literal("jpeg")]),
124
120
  type: t.Union([t.Literal("cover"), t.Literal("page")]),
125
121
  dataSource: dataSourceKeys
126
122
  }) }).listen({
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/bytebin.ts","../src/index.ts"],"sourcesContent":["import { secretbox, randomBytes } from \"tweetnacl\";\nimport { decodeUTF8, encodeUTF8, encodeBase64, decodeBase64 } from \"tweetnacl-util\";\n\nexport const upload = async (content: string, key: string): Promise<string> => {\n const nonce = randomBytes(secretbox.nonceLength);\n const keyUint8Array = decodeBase64(key);\n const messageUint8 = decodeUTF8(content);\n const box = secretbox(messageUint8, nonce, keyUint8Array);\n\n const fullMessage = new Uint8Array(nonce.length + box.length);\n fullMessage.set(nonce);\n fullMessage.set(box, nonce.length);\n\n const base64FullMessage = encodeBase64(fullMessage);\n const response = await fetch(\"https://api.pastes.dev/post\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"text/plain\",\n \"User-Agent\": \"RiffyH (github.com/rayriffy/rayriffy-h)\",\n },\n body: base64FullMessage,\n });\n\n if (!response.ok) throw new Error(\"failed to upload content\");\n\n const data = response.json() as Promise<{ key: string }>;\n return (await data).key;\n};\n\nexport const download = async (code: string, key: string): Promise<string> => {\n const response = await fetch(`https://api.pastes.dev/${code}`);\n\n if (!response.ok) throw new Error(`failed to download content with code ${code}`);\n\n const encryptedContent = await response.text();\n\n const keyUint8Array = decodeBase64(key);\n const messageWithNonceAsUint8Array = decodeBase64(encryptedContent);\n const nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength);\n const message = messageWithNonceAsUint8Array.slice(\n secretbox.nonceLength,\n encryptedContent.length,\n );\n\n const decrypted = secretbox.open(message, nonce, keyUint8Array);\n\n if (!decrypted) throw new Error(\"could not decrypt message\");\n\n return encodeUTF8(decrypted);\n};\n","#!/usr/bin/env bun\n\nimport { t, Elysia } from \"elysia\";\nimport { swagger } from \"@elysiajs/swagger\";\nimport { cors } from \"@elysiajs/cors\";\nimport { toon } from \"@toon-tools/elysia\";\n\nimport { defineCacheInstance } from \"@rayriffy/filesystem\";\nimport sharp from \"sharp\";\nimport { galleryModel, listingResultModel, type Config } from \"@riffyh/commons\";\nimport debug from \"debug\";\nimport path from \"node:path\";\nimport { download, upload } from \"./bytebin\";\nimport { secretbox, randomBytes } from \"tweetnacl\";\nimport { encodeBase64, decodeBase64 } from \"tweetnacl-util\";\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\ntry {\n if (\n typeof config.secretboxKey !== \"string\" ||\n decodeBase64(config.secretboxKey).length !== secretbox.keyLength\n )\n throw new Error(\"key length mismatch\");\n // oxlint-disable-next-line no-unused-vars\n} catch (_) {\n const generatedKey = encodeBase64(randomBytes(secretbox.keyLength));\n console.error(\n `unable to parse secret key. please either generate key via https://tweetnacl.js.org/#/secretbox or copy following key to configuration: ${generatedKey}`,\n );\n process.exit(1);\n}\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(toon())\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: dataSourceKeys,\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 .post(\"/collection/export\", ({ body }) => upload(body, config.secretboxKey), {\n body: t.String(),\n })\n .get(\"/collection/import\", async ({ query }) => download(query.key, config.secretboxKey), {\n query: t.Object({\n key: t.String(),\n }),\n })\n .get(\n \"/image\",\n async ({ query }) => {\n const cacheKeys = [query.dataSource, query.url, query.format, query.type];\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 \"Cache-Control\": \"public, max-age=86400000\",\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: query.type === \"cover\" ? 640 : 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 \"Cache-Control\": \"public, max-age=86400\",\n \"CDN-Cache-Control\": \"public, max-age=2592000\",\n \"Cloudflare-CDN-Cache-Control\": \"public, max-age=2592000\",\n },\n });\n },\n {\n query: t.Object({\n url: t.String(),\n format: t.Union([t.Literal(\"avif\"), t.Literal(\"webp\"), t.Literal(\"jpg\")]),\n type: t.Union([t.Literal(\"cover\"), t.Literal(\"page\")]),\n dataSource: dataSourceKeys,\n }),\n },\n )\n .listen({\n hostname: config.hostname ?? \"0.0.0.0\",\n port: config.port ?? 3000,\n });\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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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/bytebin.ts","../src/index.ts"],"sourcesContent":["import { secretbox, randomBytes } from \"tweetnacl\";\nimport { decodeUTF8, encodeUTF8, encodeBase64, decodeBase64 } from \"tweetnacl-util\";\n\nexport const upload = async (content: string, key: string): Promise<string> => {\n const nonce = randomBytes(secretbox.nonceLength);\n const keyUint8Array = decodeBase64(key);\n const messageUint8 = decodeUTF8(content);\n const box = secretbox(messageUint8, nonce, keyUint8Array);\n\n const fullMessage = new Uint8Array(nonce.length + box.length);\n fullMessage.set(nonce);\n fullMessage.set(box, nonce.length);\n\n const base64FullMessage = encodeBase64(fullMessage);\n const response = await fetch(\"https://api.pastes.dev/post\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"text/plain\",\n \"User-Agent\": \"RiffyH (github.com/rayriffy/rayriffy-h)\",\n },\n body: base64FullMessage,\n });\n\n if (!response.ok) throw new Error(\"failed to upload content\");\n\n const data = response.json() as Promise<{ key: string }>;\n return (await data).key;\n};\n\nexport const download = async (code: string, key: string): Promise<string> => {\n const response = await fetch(`https://api.pastes.dev/${code}`);\n\n if (!response.ok) throw new Error(`failed to download content with code ${code}`);\n\n const encryptedContent = await response.text();\n\n const keyUint8Array = decodeBase64(key);\n const messageWithNonceAsUint8Array = decodeBase64(encryptedContent);\n const nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength);\n const message = messageWithNonceAsUint8Array.slice(\n secretbox.nonceLength,\n encryptedContent.length,\n );\n\n const decrypted = secretbox.open(message, nonce, keyUint8Array);\n\n if (!decrypted) throw new Error(\"could not decrypt message\");\n\n return encodeUTF8(decrypted);\n};\n","#!/usr/bin/env bun\n\nimport { t, Elysia } from \"elysia\";\nimport { swagger } from \"@elysiajs/swagger\";\nimport { cors } from \"@elysiajs/cors\";\nimport { toon } from \"@toon-tools/elysia\";\n\nimport { defineCacheInstance } from \"@rayriffy/filesystem\";\nimport sharp from \"sharp\";\nimport { galleryModel, listingResultModel, type Config } from \"@riffyh/commons\";\nimport debug from \"debug\";\nimport path from \"node:path\";\nimport { download, upload } from \"./bytebin\";\nimport { secretbox, randomBytes } from \"tweetnacl\";\nimport { encodeBase64, decodeBase64 } from \"tweetnacl-util\";\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\ntry {\n if (\n typeof config.secretboxKey !== \"string\" ||\n decodeBase64(config.secretboxKey).length !== secretbox.keyLength\n )\n throw new Error(\"key length mismatch\");\n // oxlint-disable-next-line no-unused-vars\n} catch (_) {\n const generatedKey = encodeBase64(randomBytes(secretbox.keyLength));\n console.error(\n `unable to parse secret key. please either generate key via https://tweetnacl.js.org/#/secretbox or copy following key to configuration: ${generatedKey}`,\n );\n process.exit(1);\n}\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(toon())\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: dataSourceKeys,\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 .post(\"/collection/export\", ({ body }) => upload(body, config.secretboxKey), {\n body: t.String(),\n })\n .get(\"/collection/import\", async ({ query }) => download(query.key, config.secretboxKey), {\n query: t.Object({\n key: t.String(),\n }),\n })\n .get(\n \"/image\",\n async ({ query }) => {\n const cacheKeys = [query.dataSource, query.url, query.format, query.type];\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 \"Cache-Control\": \"public, max-age=86400000\",\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: query.type === \"cover\" ? 640 : 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 \"Cache-Control\": \"public, max-age=86400\",\n \"CDN-Cache-Control\": \"public, max-age=2592000\",\n \"Cloudflare-CDN-Cache-Control\": \"public, max-age=2592000\",\n },\n });\n },\n {\n query: t.Object({\n url: t.String(),\n format: t.Union([t.Literal(\"webp\"), t.Literal(\"jpeg\")]),\n type: t.Union([t.Literal(\"cover\"), t.Literal(\"page\")]),\n dataSource: dataSourceKeys,\n }),\n },\n )\n .listen({\n hostname: config.hostname ?? \"0.0.0.0\",\n port: config.port ?? 3000,\n });\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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riffyh/server",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rayriffy/rayriffy-h.git"
@@ -16,21 +16,21 @@
16
16
  "registry": "https://registry.npmjs.org"
17
17
  },
18
18
  "dependencies": {
19
- "@elysiajs/cors": "1.4.1",
19
+ "@elysiajs/cors": "1.4.2",
20
20
  "@elysiajs/swagger": "1.3.1",
21
21
  "@rayriffy/filesystem": "1.0.1",
22
22
  "@sinclair/typebox": "0.34.49",
23
23
  "@toon-tools/elysia": "1.1.0",
24
24
  "debug": "4.4.3",
25
- "elysia": "1.4.28",
26
- "sharp": "0.34.5",
25
+ "elysia": "1.4.29",
26
+ "sharp": "0.35.2",
27
27
  "tweetnacl": "1.0.3",
28
28
  "tweetnacl-util": "0.15.1",
29
- "@riffyh/commons": "2.1.1"
29
+ "@riffyh/commons": "2.1.2"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/debug": "4.1.13",
33
- "tsdown": "0.21.7"
33
+ "tsdown": "0.22.3"
34
34
  },
35
35
  "scripts": {
36
36
  "dev": "tsdown --watch",