diff --git a/src/index.ts b/src/index.ts index 8b8e5b4..8e950e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ export { CUSTOM_MAP_ID, DEFAULT_MAP_ID } from './lib/constants.js' export type { MapInfo, + MapInfoResponse, MapShareState, MapShareStateUpdate, DownloadStateUpdate, diff --git a/src/routes/maps.ts b/src/routes/maps.ts index 5817616..08f0f0e 100644 --- a/src/routes/maps.ts +++ b/src/routes/maps.ts @@ -10,6 +10,7 @@ import { } from '../lib/constants.js' import { errors } from '../lib/errors.js' import { addTrailingSlash, noop } from '../lib/utils.js' +import type { MapInfoResponse } from '../types.js' type MapRequest = IRequestStrict & { params: { @@ -27,14 +28,17 @@ export function MapsRouter({ base = '/' }, ctx: Context) { const router = IttyRouter({ base }) - router.get(`/:mapId/info`, async (request) => { - const info = await ctx.getMapInfo(request.params.mapId) - return { - created: info.mapCreatedAt, - size: info.estimatedSizeBytes, - name: info.mapName, - } - }) + router.get( + `/:mapId/info`, + async (request): Promise => { + const info = await ctx.getMapInfo(request.params.mapId) + return { + created: info.mapCreatedAt, + size: info.estimatedSizeBytes, + name: info.mapName, + } + }, + ) const uploadHandler: RequestHandler = async (request) => { const writable = ctx.createMapWritableStream(request.params.mapId) diff --git a/src/types.ts b/src/types.ts index a91f00e..020670b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -105,6 +105,16 @@ const MapInfo = T.Object({ }), }) +export const MapInfoResponse = T.Object({ + created: T.Number({ + description: 'Timestamp (ms since epoch) when the map was created', + }), + size: T.Number({ description: 'Estimated size of the map data in bytes' }), + name: T.String({ description: 'The name of the map' }), +}) + +export type MapInfoResponse = Static + const MapShareBase = T.Intersect([ T.Object({ receiverDeviceId: T.String({ @@ -126,6 +136,9 @@ export type MapShareState = DistributiveIntersection< Static > +/** + * @deprecated We don't yet return this type from any API, and it may be removed in a future release. Use MapInfoResponse instead. + */ export type MapInfo = Static export type FetchContext = { diff --git a/test/maps.test.ts b/test/maps.test.ts index 9e77397..1eaad2e 100644 --- a/test/maps.test.ts +++ b/test/maps.test.ts @@ -6,8 +6,10 @@ import { setTimeout as delay } from 'node:timers/promises' import { fileURLToPath } from 'node:url' import { Reader } from 'styled-map-package' +import Value from 'typebox/value' import { describe, it, expect, vi } from 'vitest' +import { MapInfoResponse } from '../src/types.js' import { DEMOTILES_Z2, goOffline, @@ -60,6 +62,7 @@ describe('Maps API', () => { const response = await fetch(`${localBaseUrl}/maps/custom/info`) expect(response.status).toBe(200) const info = await response.json() + expect(Value.Check(MapInfoResponse, info)).toBe(true) expect(info).toHaveProperty('created') expect(info).toHaveProperty('size') expect(info).toHaveProperty('name') @@ -73,6 +76,7 @@ describe('Maps API', () => { const response = await fetch(`${localBaseUrl}/maps/fallback/info`) expect(response.status).toBe(200) const info = await response.json() + expect(Value.Check(MapInfoResponse, info)).toBe(true) expect(info).toHaveProperty('created') expect(info).toHaveProperty('size') expect(info).toHaveProperty('name') @@ -580,8 +584,9 @@ describe('Map Upload', () => { // Mock fs.createWriteStream to return a writable that errors on write, // simulating a disk-full scenario const originalCreateWriteStream = fs.createWriteStream - const spy = vi.spyOn(fs, 'createWriteStream').mockImplementation( - (...args: any[]) => { + const spy = vi + .spyOn(fs, 'createWriteStream') + .mockImplementation((...args: any[]) => { const stream = originalCreateWriteStream.apply(fs, args as any) stream._write = ( _chunk: any, @@ -591,8 +596,7 @@ describe('Map Upload', () => { callback(new Error('ENOSPC: no space left on device')) } return stream - }, - ) + }) t.onTestFinished(() => spy.mockRestore()) const fileBuffer = fs.readFileSync(OSM_BRIGHT_Z6) @@ -627,17 +631,15 @@ describe('Map Upload', () => { // Mock fs.createWriteStream to return a writable that writes successfully // but errors on close (_final), simulating a flush/sync failure const originalCreateWriteStream = fs.createWriteStream - const spy = vi.spyOn(fs, 'createWriteStream').mockImplementation( - (...args: any[]) => { + const spy = vi + .spyOn(fs, 'createWriteStream') + .mockImplementation((...args: any[]) => { const stream = originalCreateWriteStream.apply(fs, args as any) - stream._final = ( - callback: (error?: Error | null) => void, - ) => { + stream._final = (callback: (error?: Error | null) => void) => { callback(new Error('EIO: i/o error')) } return stream - }, - ) + }) t.onTestFinished(() => spy.mockRestore()) const fileBuffer = fs.readFileSync(OSM_BRIGHT_Z6)