chiitiler 1.14.2 → 1.16.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.
package/dist/cli.js CHANGED
@@ -21,6 +21,14 @@ function parseCacheStrategy(method, options) {
21
21
  endpoint: options.s3Endpoint,
22
22
  forcePathStyle: options.s3ForcePathStyle,
23
23
  });
24
+ if (method === 'gcs')
25
+ return caches.gcsCache({
26
+ bucket: options.gcsCacheBucket,
27
+ projectId: options.gcsProjectId,
28
+ keyFilename: options.gcsKeyFilename,
29
+ prefix: options.gcsCachePrefix,
30
+ apiEndpoint: options.gcsApiEndpoint,
31
+ });
24
32
  // command-line is not specified -> try to read from env
25
33
  const cacheEnv = process.env.CHIITILER_CACHE_METHOD;
26
34
  if (cacheEnv === 'memory')
@@ -40,6 +48,14 @@ function parseCacheStrategy(method, options) {
40
48
  endpoint: process.env.CHIITILER_S3_ENDPOINT,
41
49
  forcePathStyle: process.env.CHIITILER_S3_FORCE_PATH_STYLE === 'true',
42
50
  });
51
+ if (cacheEnv === 'gcs')
52
+ return caches.gcsCache({
53
+ bucket: process.env.CHIITILER_GCS_CACHE_BUCKET ?? '',
54
+ prefix: process.env.CHIITILER_GCS_CACHE_PREFIX,
55
+ projectId: process.env.CHIITILER_GCS_PROJECT_ID,
56
+ keyFilename: process.env.CHIITILER_GCS_KEY_FILENAME,
57
+ apiEndpoint: process.env.CHIITILER_GCS_API_ENDPOINT,
58
+ });
43
59
  // undefined or invalid
44
60
  return caches.noneCache();
45
61
  }
@@ -88,6 +104,11 @@ export function createProgram() {
88
104
  .option('-s3b --s3-cache-bucket <bucket-name>', 's3 cache bucket name', '')
89
105
  .option('-s3e --s3-endpoint <url>', 's3 endpoint url', '')
90
106
  .option('-3p --s3-force-path-style', 's3 force path style', '')
107
+ .option('-gcsb --gcs-cache-bucket <bucket-name>', 'gcs cache bucket name', '')
108
+ .option('-gcsp --gcs-project-id <project-id>', 'gcs project id', '')
109
+ .option('-gcsk --gcs-key-filename <key-filename>', 'gcs key filename', '')
110
+ .option('-gcsp --gcs-cache-prefix <prefix>', 'gcs cache prefix', '')
111
+ .option('-gcse --gcs-api-endpoint <api-endpoint>', 'gcs api endpoint', '')
91
112
  .option('-p --port <port>', 'port number')
92
113
  .option('-r --stream', 'stream mode')
93
114
  .option('-D --debug', 'debug mode')
@@ -101,6 +122,11 @@ export function createProgram() {
101
122
  s3Region: options.s3Region,
102
123
  s3Endpoint: options.s3Endpoint,
103
124
  s3ForcePathStyle: options.s3ForcePathStyle === 'true',
125
+ gcsCacheBucket: options.gcsCacheBucket,
126
+ gcsCachePrefix: options.gcsCachePrefix,
127
+ gcsProjectId: options.gcsProjectId,
128
+ gcsKeyFilename: options.gcsKeyFilename,
129
+ gcsApiEndpoint: options.gcsApiEndpoint,
104
130
  }),
105
131
  port: parsePort(options.port),
106
132
  debug: parseDebug(options.debug),
package/dist/gcs.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { Storage } from '@google-cloud/storage';
2
+ declare const getStorageClient: ({ projectId, keyFilename, apiEndpoint }: {
3
+ projectId?: string;
4
+ keyFilename?: string;
5
+ apiEndpoint?: string;
6
+ }) => Storage;
7
+ export { getStorageClient };
package/dist/gcs.js ADDED
@@ -0,0 +1,14 @@
1
+ import { Storage } from '@google-cloud/storage';
2
+ let storageClient; // singleton
3
+ const getStorageClient = function ({ projectId, keyFilename, apiEndpoint }) {
4
+ if (storageClient !== undefined)
5
+ return storageClient;
6
+ const storageOptions = {
7
+ projectId,
8
+ keyFilename,
9
+ apiEndpoint
10
+ };
11
+ storageClient = new Storage(storageOptions);
12
+ return storageClient;
13
+ };
14
+ export { getStorageClient };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { getRenderedBbox, getRenderedTile, GetRenderedBboxOptions, GetRenderedTileOptions } from './render/index.js';
1
+ import { getRenderedBbox, getRenderedTile, getRenderedImage, GetRenderedBboxOptions, GetRenderedTileOptions, GetRenderedImageOptions } from './render/index.js';
2
2
  export declare function getRenderedBboxBuffer(options: GetRenderedBboxOptions): Promise<Buffer>;
3
3
  export { getRenderedBbox as getRenderedBboxStream };
4
+ export declare function getRenderedImageBuffer(options: GetRenderedImageOptions): Promise<Buffer>;
5
+ export { getRenderedImage as getRenderedImageStream };
4
6
  export declare function getRenderedTileBuffer(options: GetRenderedTileOptions): Promise<Buffer>;
5
7
  export { getRenderedTile as getRenderedTileStream };
6
8
  export * as ChiitilerCache from './cache/index.js';
package/dist/index.js CHANGED
@@ -1,9 +1,14 @@
1
- import { getRenderedBbox, getRenderedTile, } from './render/index.js';
1
+ import { getRenderedBbox, getRenderedTile, getRenderedImage, } from './render/index.js';
2
2
  export async function getRenderedBboxBuffer(options) {
3
3
  const sharp = await getRenderedBbox(options);
4
4
  return sharp.toBuffer();
5
5
  }
6
6
  export { getRenderedBbox as getRenderedBboxStream };
7
+ export async function getRenderedImageBuffer(options) {
8
+ const sharp = await getRenderedImage(options);
9
+ return sharp.toBuffer();
10
+ }
11
+ export { getRenderedImage as getRenderedImageStream };
7
12
  export async function getRenderedTileBuffer(options) {
8
13
  const sharp = await getRenderedTile(options);
9
14
  return sharp.toBuffer();
@@ -23,4 +23,17 @@ type GetRenderedBboxOptions = {
23
23
  quality: number;
24
24
  };
25
25
  declare function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, }: GetRenderedBboxOptions): Promise<sharp.Sharp>;
26
- export { getRenderedTile, getRenderedBbox, type GetRenderedBboxOptions, type GetRenderedTileOptions, type SupportedFormat, };
26
+ type GetRenderedImageOptions = {
27
+ stylejson: string | StyleSpecification;
28
+ cache: Cache;
29
+ ext: SupportedFormat;
30
+ quality: number;
31
+ bearing: number;
32
+ pitch: number;
33
+ zoom: number;
34
+ center: [number, number];
35
+ height: number;
36
+ width: number;
37
+ };
38
+ declare function getRenderedImage(options: GetRenderedImageOptions): Promise<sharp.Sharp>;
39
+ export { getRenderedTile, getRenderedBbox, getRenderedImage, type GetRenderedBboxOptions, type GetRenderedTileOptions, type GetRenderedImageOptions, type SupportedFormat, };
@@ -121,7 +121,7 @@ async function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, })
121
121
  height,
122
122
  center,
123
123
  }, cache, 'static');
124
- let _sharp = sharp(pixels, {
124
+ const _sharp = sharp(pixels, {
125
125
  raw: {
126
126
  width,
127
127
  height,
@@ -138,4 +138,31 @@ async function getRenderedBbox({ stylejson, bbox, size, cache, ext, quality, })
138
138
  return _sharp.webp({ quality, effort: 0 });
139
139
  }
140
140
  }
141
- export { getRenderedTile, getRenderedBbox, };
141
+ async function getRenderedImage(options) {
142
+ const style = await loadStyle(options.stylejson, options.cache);
143
+ const pixels = await render(style, {
144
+ center: options.center,
145
+ height: options.height,
146
+ width: options.width,
147
+ zoom: options.zoom,
148
+ bearing: options.bearing,
149
+ pitch: options.pitch,
150
+ }, options.cache, 'static');
151
+ const _sharp = sharp(pixels, {
152
+ raw: {
153
+ width: options.width,
154
+ height: options.height,
155
+ channels: 4,
156
+ },
157
+ });
158
+ switch (options.ext) {
159
+ case 'png':
160
+ return _sharp.png();
161
+ case 'jpeg':
162
+ case 'jpg':
163
+ return _sharp.jpeg({ quality: options.quality });
164
+ case 'webp':
165
+ return _sharp.webp({ quality: options.quality, effort: 0 });
166
+ }
167
+ }
168
+ export { getRenderedTile, getRenderedBbox, getRenderedImage, };
@@ -8,8 +8,6 @@ type InitServerOptions = {
8
8
  };
9
9
  type InitializedServer = {
10
10
  app: Hono;
11
- tiles: Hono;
12
- clip: Hono;
13
11
  start: () => void;
14
12
  };
15
13
  declare function initServer(options: InitServerOptions): InitializedServer;
@@ -1,230 +1,43 @@
1
1
  import { Hono } from 'hono/quick';
2
- import { stream } from 'hono/streaming';
3
2
  import { serve } from '@hono/node-server';
4
- import { validateStyleMin, } from '@maplibre/maplibre-gl-style-spec';
5
3
  import { getDebugPage, getEditorgPage } from './debug.js';
6
- import { getRenderedTile, getRenderedBbox, } from '../render/index.js';
7
- function isValidStylejson(stylejson) {
8
- return validateStyleMin(stylejson).length === 0;
9
- }
10
- function isValidXyz(x, y, z) {
11
- if (x < 0 || y < 0 || z < 0)
12
- return false;
13
- if (x >= 2 ** z || y >= 2 ** z)
14
- return false;
15
- return true;
16
- }
17
- function isSupportedFormat(ext) {
18
- return ['png', 'jpeg', 'jpg', 'webp'].includes(ext);
19
- }
4
+ import { createClipRouter } from './routes/clip.js';
5
+ import { createTilesRouter } from './routes/tiles.js';
6
+ import { createCameraRouter } from './routes/camera.js';
20
7
  function initServer(options) {
21
- const tiles = new Hono()
22
- .get('/:z/:x/:y_ext', async (c) => {
23
- const url = c.req.query('url');
24
- if (url === undefined)
25
- return c.body('url is required', 400);
26
- // path params
27
- const z = Number(c.req.param('z'));
28
- const x = Number(c.req.param('x'));
29
- let [_y, ext] = c.req.param('y_ext').split('.');
30
- const y = Number(_y);
31
- if (!isValidXyz(x, y, z))
32
- return c.body('invalid xyz', 400);
33
- if (!isSupportedFormat(ext))
34
- return c.body('invalid format', 400);
35
- // query params
36
- const tileSize = Number(c.req.query('tileSize') ?? 512);
37
- const quality = Number(c.req.query('quality') ?? 100);
38
- const margin = Number(c.req.query('margin') ?? 0);
39
- c.header('Content-Type', `image/${ext}`);
40
- try {
41
- const sharp = await getRenderedTile({
42
- stylejson: url,
43
- z,
44
- x,
45
- y,
46
- tileSize,
47
- cache: options.cache,
48
- margin,
49
- ext,
50
- quality,
51
- });
52
- if (options.stream) {
53
- // stream mode
54
- return stream(c, async (stream) => {
55
- for await (const chunk of sharp) {
56
- stream.write(chunk);
57
- }
58
- });
59
- }
60
- else {
61
- const buf = await sharp.toBuffer();
62
- return c.body(buf);
63
- }
64
- }
65
- catch (e) {
66
- console.error(`render error: ${e}`);
67
- return c.body('failed to render tile', 400);
68
- }
69
- })
70
- .post('/:z/:x/:y_ext', async (c) => {
71
- // body
72
- const { style } = await c.req.json();
73
- if (!isValidStylejson(style))
74
- return c.body('invalid stylejson', 400);
75
- // path params
76
- const z = Number(c.req.param('z'));
77
- const x = Number(c.req.param('x'));
78
- let [_y, ext] = c.req.param('y_ext').split('.');
79
- const y = Number(_y);
80
- if (!isValidXyz(x, y, z))
81
- return c.body('invalid xyz', 400);
82
- if (!isSupportedFormat(ext))
83
- return c.body('invalid format', 400);
84
- // query params
85
- const tileSize = Number(c.req.query('tileSize') ?? 512);
86
- const quality = Number(c.req.query('quality') ?? 100);
87
- const margin = Number(c.req.query('margin') ?? 0);
88
- c.header('Content-Type', `image/${ext}`);
89
- try {
90
- const sharp = await getRenderedTile({
91
- stylejson: style,
92
- z,
93
- x,
94
- y,
95
- tileSize,
96
- cache: options.cache,
97
- margin,
98
- ext,
99
- quality,
100
- });
101
- if (options.stream) {
102
- // stream mode
103
- return stream(c, async (stream) => {
104
- for await (const chunk of sharp) {
105
- stream.write(chunk);
106
- }
107
- });
108
- }
109
- else {
110
- const buf = await sharp.toBuffer();
111
- return c.body(buf);
112
- }
113
- }
114
- catch (e) {
115
- console.error(`render error: ${e}`);
116
- return c.body('failed to render tile', 400);
117
- }
118
- });
119
- const clip = new Hono()
120
- .get('/:filename_ext', async (c) => {
121
- // path params
122
- const [filename, ext] = c.req.param('filename_ext').split('.');
123
- if (filename !== 'clip')
124
- return c.body('not found', 404);
125
- if (!isSupportedFormat(ext))
126
- return c.body('invalid format', 400);
127
- // query params
128
- const bbox = c.req.query('bbox'); // ?bbox=minx,miny,maxx,maxy
129
- if (bbox === undefined)
130
- return c.body('bbox is required', 400);
131
- const [minx, miny, maxx, maxy] = bbox.split(',').map(Number);
132
- if (minx >= maxx || miny >= maxy)
133
- return c.body('invalid bbox', 400);
134
- const url = c.req.query('url');
135
- if (url === undefined)
136
- return c.body('url is required', 400);
137
- const quality = Number(c.req.query('quality') ?? 100);
138
- const size = Number(c.req.query('size') ?? 1024);
139
- c.header('Content-Type', `image/${ext}`);
140
- try {
141
- const sharp = await getRenderedBbox({
142
- stylejson: url,
143
- bbox: [minx, miny, maxx, maxy],
144
- size,
145
- cache: options.cache,
146
- ext,
147
- quality,
148
- });
149
- if (options.stream) {
150
- // stream mode
151
- return stream(c, async (stream) => {
152
- for await (const chunk of sharp) {
153
- stream.write(chunk);
154
- }
155
- });
156
- }
157
- else {
158
- const buf = await sharp.toBuffer();
159
- return c.body(buf);
160
- }
161
- }
162
- catch (e) {
163
- console.error(`render error: ${e}`);
164
- return c.body('failed to render tile', 400);
165
- }
166
- })
167
- .post('/:filename_ext', async (c) => {
168
- // body
169
- const { style } = await c.req.json();
170
- if (!isValidStylejson(style))
171
- return c.body('invalid stylejson', 400);
172
- // path params
173
- const [filename, ext] = c.req.param('filename_ext').split('.');
174
- if (filename !== 'clip')
175
- return c.body('not found', 404);
176
- if (!isSupportedFormat(ext))
177
- return c.body('invalid format', 400);
178
- // query params
179
- const bbox = c.req.query('bbox'); // ?bbox=minx,miny,maxx,maxy
180
- if (bbox === undefined)
181
- return c.body('bbox is required', 400);
182
- const [minx, miny, maxx, maxy] = bbox.split(',').map(Number);
183
- if (minx >= maxx || miny >= maxy)
184
- return c.body('invalid bbox', 400);
185
- const quality = Number(c.req.query('quality') ?? 100);
186
- const size = Number(c.req.query('size') ?? 1024);
187
- c.header('Content-Type', `image/${ext}`);
188
- try {
189
- const sharp = await getRenderedBbox({
190
- stylejson: style,
191
- bbox: [minx, miny, maxx, maxy],
192
- size,
193
- cache: options.cache,
194
- ext,
195
- quality,
196
- });
197
- if (options.stream) {
198
- // stream mode
199
- return stream(c, async (stream) => {
200
- for await (const chunk of sharp) {
201
- stream.write(chunk);
202
- }
203
- });
204
- }
205
- else {
206
- const buf = await sharp.toBuffer();
207
- return c.body(buf);
208
- }
209
- }
210
- catch (e) {
211
- console.error(`render error: ${e}`);
212
- return c.body('failed to render tile', 400);
213
- }
214
- });
215
8
  const hono = new Hono();
216
9
  if (options.debug) {
217
10
  hono.get('/debug', getDebugPage);
218
11
  hono.get('/editor', getEditorgPage);
219
12
  }
220
13
  hono.get('/health', (c) => c.text('OK'));
221
- hono.route('/tiles', tiles);
222
- hono.route('/', clip);
14
+ hono.route('/static', createCameraRouter({
15
+ cache: options.cache,
16
+ stream: options.stream,
17
+ }));
18
+ hono.route('/tiles', createTilesRouter({
19
+ cache: options.cache,
20
+ stream: options.stream,
21
+ }));
22
+ hono.route('/', createClipRouter({
23
+ cache: options.cache,
24
+ stream: options.stream,
25
+ }));
223
26
  return {
224
27
  app: hono,
225
- tiles,
226
- clip,
227
- start: () => serve({ port: options.port, fetch: hono.fetch }),
28
+ start: () => {
29
+ const server = serve({ port: options.port, fetch: hono.fetch });
30
+ process.on('SIGINT', () => {
31
+ console.log('shutting down server...');
32
+ server.close();
33
+ process.exit(0);
34
+ });
35
+ process.on('SIGTERM', () => {
36
+ console.log('shutting down server...');
37
+ server.close();
38
+ process.exit(0);
39
+ });
40
+ },
228
41
  };
229
42
  }
230
43
  export { initServer };
@@ -0,0 +1,36 @@
1
+ import { Cache } from '../../cache/index.js';
2
+ declare function createCameraRouter(options: {
3
+ cache: Cache;
4
+ stream: boolean;
5
+ }): import("hono/hono-base").HonoBase<import("hono/types").BlankEnv, {
6
+ "/:camera/:dimensions_ext": {
7
+ $get: {
8
+ input: {
9
+ param: {
10
+ camera: string;
11
+ } & {
12
+ dimensions_ext: string;
13
+ };
14
+ };
15
+ output: {};
16
+ outputFormat: string;
17
+ status: import("hono/utils/http-status").StatusCode;
18
+ };
19
+ };
20
+ } & {
21
+ "/:camera/:dimensions_ext": {
22
+ $post: {
23
+ input: {
24
+ param: {
25
+ camera: string;
26
+ } & {
27
+ dimensions_ext: string;
28
+ };
29
+ };
30
+ output: {};
31
+ outputFormat: string;
32
+ status: import("hono/utils/http-status").StatusCode;
33
+ };
34
+ };
35
+ }, "/", "/:camera/:dimensions_ext">;
36
+ export { createCameraRouter };
@@ -0,0 +1,128 @@
1
+ import { Hono } from 'hono';
2
+ import { stream } from 'hono/streaming';
3
+ import { isSupportedFormat, isValidCamera, isValidDimensions, isValidStylejson, } from '../utils.js';
4
+ import { getRenderedImage } from '../../render/index.js';
5
+ function createCameraRouter(options) {
6
+ const camera = new Hono()
7
+ .get('/:camera/:dimensions_ext', async (c) => {
8
+ // path params
9
+ const camera = c.req
10
+ .param('camera')
11
+ .match(/([\d.]+),([\d.]+),([\d.]+)(?:@(\d+)(?:,(\d+))?)?/);
12
+ const [_dimensions, ext] = c.req.param('dimensions_ext').split('.');
13
+ const dimensions = _dimensions.match(/(\d+)x(\d+)?/);
14
+ if (!camera || !isValidCamera(camera))
15
+ return c.body('invalid camera', 400);
16
+ if (!dimensions || !isValidDimensions(dimensions))
17
+ return c.body('invalid dimensions', 400);
18
+ if (!isSupportedFormat(ext))
19
+ return c.body('invalid format', 400);
20
+ const [, _lon, _lat, _zoom, _bearing, _pitch] = camera;
21
+ const [, _width, _height] = dimensions;
22
+ const lat = Number(_lat);
23
+ const lon = Number(_lon);
24
+ const zoom = Number(_zoom);
25
+ const bearing = Number(_bearing ?? 0);
26
+ const pitch = Number(_pitch ?? 0);
27
+ const height = Number(_height);
28
+ const width = Number(_width);
29
+ // query params
30
+ const url = c.req.query('url');
31
+ if (url === undefined)
32
+ return c.body('url is required', 400);
33
+ const quality = Number(c.req.query('quality') ?? 100);
34
+ c.header('Content-Type', `image/${ext}`);
35
+ try {
36
+ const sharp = await getRenderedImage({
37
+ stylejson: url,
38
+ cache: options.cache,
39
+ ext,
40
+ quality,
41
+ center: [lon, lat],
42
+ zoom,
43
+ bearing,
44
+ pitch,
45
+ height,
46
+ width,
47
+ });
48
+ if (options.stream) {
49
+ // stream mode
50
+ return stream(c, async (stream) => {
51
+ for await (const chunk of sharp) {
52
+ stream.write(chunk);
53
+ }
54
+ });
55
+ }
56
+ else {
57
+ const buf = await sharp.toBuffer();
58
+ return c.body(buf);
59
+ }
60
+ }
61
+ catch (e) {
62
+ console.error(`render error: ${e}`);
63
+ return c.body('failed to render static image', 400);
64
+ }
65
+ })
66
+ .post('/:camera/:dimensions_ext', async (c) => {
67
+ // body
68
+ const { style } = await c.req.json();
69
+ if (!isValidStylejson(style))
70
+ return c.body('invalid stylejson', 400);
71
+ // path params
72
+ const camera = c.req
73
+ .param('camera')
74
+ .match(/([\d.]+),([\d.]+),([\d.]+)(?:@(\d+)(?:,(\d+))?)?/);
75
+ const [_dimensions, ext] = c.req.param('dimensions_ext').split('.');
76
+ const dimensions = _dimensions.match(/(\d+)x(\d+)?/);
77
+ if (!camera || !isValidCamera(camera))
78
+ return c.body('invalid camera', 400);
79
+ if (!dimensions || !isValidDimensions(dimensions))
80
+ return c.body('invalid dimensions', 400);
81
+ if (!isSupportedFormat(ext))
82
+ return c.body('invalid format', 400);
83
+ const [, _lon, _lat, _zoom, _bearing, _pitch] = camera;
84
+ const [, _width, _height] = dimensions;
85
+ const lat = Number(_lat);
86
+ const lon = Number(_lon);
87
+ const zoom = Number(_zoom);
88
+ const bearing = Number(_bearing ?? 0);
89
+ const pitch = Number(_pitch ?? 0);
90
+ const height = Number(_height);
91
+ const width = Number(_width);
92
+ // query params
93
+ const quality = Number(c.req.query('quality') ?? 100);
94
+ c.header('Content-Type', `image/${ext}`);
95
+ try {
96
+ const sharp = await getRenderedImage({
97
+ stylejson: style,
98
+ cache: options.cache,
99
+ ext,
100
+ quality,
101
+ center: [lon, lat],
102
+ zoom,
103
+ bearing,
104
+ pitch,
105
+ height,
106
+ width,
107
+ });
108
+ if (options.stream) {
109
+ // stream mode
110
+ return stream(c, async (stream) => {
111
+ for await (const chunk of sharp) {
112
+ stream.write(chunk);
113
+ }
114
+ });
115
+ }
116
+ else {
117
+ const buf = await sharp.toBuffer();
118
+ return c.body(buf);
119
+ }
120
+ }
121
+ catch (e) {
122
+ console.error(`render error: ${e}`);
123
+ return c.body('failed to render static image', 400);
124
+ }
125
+ });
126
+ return camera;
127
+ }
128
+ export { createCameraRouter };
@@ -0,0 +1,32 @@
1
+ import { Cache } from '../../cache/index.js';
2
+ declare function createClipRouter(options: {
3
+ cache: Cache;
4
+ stream: boolean;
5
+ }): import("hono/hono-base").HonoBase<import("hono/types").BlankEnv, {
6
+ "/:filename_ext": {
7
+ $get: {
8
+ input: {
9
+ param: {
10
+ filename_ext: string;
11
+ };
12
+ };
13
+ output: {};
14
+ outputFormat: string;
15
+ status: import("hono/utils/http-status").StatusCode;
16
+ };
17
+ };
18
+ } & {
19
+ "/:filename_ext": {
20
+ $post: {
21
+ input: {
22
+ param: {
23
+ filename_ext: string;
24
+ };
25
+ };
26
+ output: {};
27
+ outputFormat: string;
28
+ status: import("hono/utils/http-status").StatusCode;
29
+ };
30
+ };
31
+ }, "/", "/:filename_ext">;
32
+ export { createClipRouter };