@comapeo/core 1.0.1 → 2.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.
Files changed (75) hide show
  1. package/dist/blob-store/index.d.ts +1 -1
  2. package/dist/config-import.d.ts.map +1 -1
  3. package/dist/core-manager/core-index.d.ts +1 -1
  4. package/dist/core-manager/core-index.d.ts.map +1 -1
  5. package/dist/core-manager/index.d.ts +1 -0
  6. package/dist/core-manager/index.d.ts.map +1 -1
  7. package/dist/fastify-controller.d.ts.map +1 -1
  8. package/dist/fastify-plugins/{maps/index.d.ts → maps.d.ts} +8 -8
  9. package/dist/fastify-plugins/maps.d.ts.map +1 -0
  10. package/dist/fastify-plugins/utils.d.ts +4 -0
  11. package/dist/fastify-plugins/utils.d.ts.map +1 -1
  12. package/dist/index.d.ts +1 -3
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/lib/hashmap.d.ts +2 -2
  15. package/dist/lib/hashmap.d.ts.map +1 -1
  16. package/dist/lib/key-by.d.ts +15 -0
  17. package/dist/lib/key-by.d.ts.map +1 -0
  18. package/dist/lib/noise-secret-stream-helpers.d.ts.map +1 -1
  19. package/dist/local-peers.d.ts +3 -2
  20. package/dist/local-peers.d.ts.map +1 -1
  21. package/dist/logger.d.ts +12 -9
  22. package/dist/logger.d.ts.map +1 -1
  23. package/dist/mapeo-manager.d.ts +9 -1
  24. package/dist/mapeo-manager.d.ts.map +1 -1
  25. package/dist/mapeo-project.d.ts.map +1 -1
  26. package/dist/member-api.d.ts +3 -1
  27. package/dist/member-api.d.ts.map +1 -1
  28. package/dist/roles.d.ts.map +1 -1
  29. package/dist/schema/utils.d.ts.map +1 -1
  30. package/dist/sync/core-sync-state.d.ts +10 -3
  31. package/dist/sync/core-sync-state.d.ts.map +1 -1
  32. package/dist/sync/namespace-sync-state.d.ts +8 -12
  33. package/dist/sync/namespace-sync-state.d.ts.map +1 -1
  34. package/dist/sync/peer-sync-controller.d.ts.map +1 -1
  35. package/dist/sync/sync-api.d.ts.map +1 -1
  36. package/dist/sync/sync-state.d.ts +7 -1
  37. package/dist/sync/sync-state.d.ts.map +1 -1
  38. package/dist/translation-api.d.ts +1 -3
  39. package/dist/translation-api.d.ts.map +1 -1
  40. package/dist/types.d.ts +1 -1
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/utils.d.ts +0 -13
  43. package/dist/utils.d.ts.map +1 -1
  44. package/package.json +12 -11
  45. package/src/core-manager/index.js +13 -10
  46. package/src/datastore/README.md +2 -2
  47. package/src/datatype/README.md +1 -1
  48. package/src/fastify-controller.js +7 -1
  49. package/src/fastify-plugins/maps.js +122 -0
  50. package/src/fastify-plugins/utils.js +6 -0
  51. package/src/index-writer/index.js +1 -1
  52. package/src/index.js +1 -3
  53. package/src/lib/hashmap.js +1 -1
  54. package/src/lib/key-by.js +24 -0
  55. package/src/local-peers.js +2 -1
  56. package/src/logger.js +52 -16
  57. package/src/mapeo-manager.js +36 -2
  58. package/src/mapeo-project.js +0 -2
  59. package/src/member-api.js +12 -5
  60. package/src/sync/core-sync-state.js +35 -7
  61. package/src/sync/namespace-sync-state.js +26 -24
  62. package/src/sync/peer-sync-controller.js +44 -37
  63. package/src/sync/sync-api.js +9 -6
  64. package/src/sync/sync-state.js +12 -1
  65. package/src/translation-api.js +1 -4
  66. package/src/types.ts +0 -1
  67. package/src/utils.js +0 -25
  68. package/dist/fastify-plugins/maps/index.d.ts.map +0 -1
  69. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts +0 -12
  70. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts.map +0 -1
  71. package/dist/fastify-plugins/maps/static-maps.d.ts +0 -11
  72. package/dist/fastify-plugins/maps/static-maps.d.ts.map +0 -1
  73. package/src/fastify-plugins/maps/index.js +0 -173
  74. package/src/fastify-plugins/maps/offline-fallback-map.js +0 -114
  75. package/src/fastify-plugins/maps/static-maps.js +0 -271
@@ -1,173 +0,0 @@
1
- import fp from 'fastify-plugin'
2
- import { Type as T } from '@sinclair/typebox'
3
- import { fetch } from 'undici'
4
-
5
- import {
6
- NotFoundError,
7
- createStyleJsonResponseHeaders,
8
- getFastifyServerAddress,
9
- } from '../utils.js'
10
- import { PLUGIN_NAME as MAPEO_STATIC_MAPS } from './static-maps.js'
11
- import { PLUGIN_NAME as MAPEO_OFFLINE_FALLBACK } from './offline-fallback-map.js'
12
-
13
- export const PLUGIN_NAME = 'mapeo-maps'
14
- export const DEFAULT_MAPBOX_STYLE_URL =
15
- 'https://api.mapbox.com/styles/v1/mapbox/outdoors-v12'
16
-
17
- const MAP_PROVIDER_API_KEY_QUERY_PARAM_BY_HOSTNAME = new Map([
18
- // Mapbox expects `access_token`: https://docs.mapbox.com/api/maps/styles/
19
- ['api.mapbox.com', 'access_token'],
20
- // Protomaps expects `key` (no docs link yet)
21
- ['api.protomaps.com', 'key'],
22
- // MapTiler expects `key`: https://docs.maptiler.com/cloud/api/maps/
23
- ['api.maptiler.com', 'key'],
24
- // Stadia expects `api_key`: https://docs.stadiamaps.com/themes/
25
- ['tiles.stadiamaps.com', 'api_key'],
26
- // ArcGIS expects `token`: https://developers.arcgis.com/documentation/mapping-apis-and-services/security/api-keys/
27
- ['basemapstyles-api.arcgis.com', 'token'],
28
- ])
29
-
30
- export const plugin = fp(mapsPlugin, {
31
- fastify: '4.x',
32
- name: PLUGIN_NAME,
33
- decorators: { fastify: ['mapeoStaticMaps', 'mapeoFallbackMap'] },
34
- dependencies: [MAPEO_STATIC_MAPS, MAPEO_OFFLINE_FALLBACK],
35
- })
36
-
37
- /**
38
- * @typedef {object} MapsPluginOpts
39
- * @property {string} [prefix]
40
- * @property {string} [defaultOnlineStyleUrl]
41
- */
42
-
43
- /**
44
- * @typedef {object} MapsPluginContext
45
- * @property {() => Promise<string>} getStyleJsonUrl
46
- */
47
-
48
- /** @type {import('fastify').FastifyPluginAsync<MapsPluginOpts>} */
49
- async function mapsPlugin(fastify, opts) {
50
- fastify.decorate('mapeoMaps', {
51
- async getStyleJsonUrl() {
52
- const base = await getFastifyServerAddress(fastify.server, {
53
- timeout: 5000,
54
- })
55
-
56
- return new URL(`${opts.prefix || ''}/style.json`, base).href
57
- },
58
- })
59
- fastify.register(routes, {
60
- prefix: opts.prefix,
61
- defaultOnlineStyleUrl: opts.defaultOnlineStyleUrl,
62
- })
63
- }
64
-
65
- const GetStyleJsonQueryStringSchema = T.Object({
66
- key: T.Optional(T.String()),
67
- })
68
-
69
- /** @type {import('fastify').FastifyPluginAsync<MapsPluginOpts, import('fastify').RawServerDefault, import('@fastify/type-provider-typebox').TypeBoxTypeProvider>} */
70
- async function routes(fastify, opts) {
71
- const { defaultOnlineStyleUrl = DEFAULT_MAPBOX_STYLE_URL } = opts
72
-
73
- fastify.get(
74
- '/style.json',
75
- { schema: { querystring: GetStyleJsonQueryStringSchema } },
76
- async (req, rep) => {
77
- const serverAddress = await getFastifyServerAddress(req.server.server)
78
-
79
- // 1. Attempt to get "default" local static map's style.json
80
- {
81
- const styleId = 'default'
82
-
83
- const results = await Promise.all([
84
- fastify.mapeoStaticMaps.getStyleJsonStats(styleId),
85
- fastify.mapeoStaticMaps.getResolvedStyleJson(styleId, serverAddress),
86
- ]).catch(() => {
87
- fastify.log.warn('Cannot read default static map')
88
- return null
89
- })
90
-
91
- if (results) {
92
- const [stats, styleJson] = results
93
- rep.headers(createStyleJsonResponseHeaders(stats.mtime))
94
- return styleJson
95
- }
96
- }
97
-
98
- // 2. Attempt to get a default style.json from online source
99
- {
100
- const { key } = req.query
101
-
102
- const upstreamUrlObj = new URL(defaultOnlineStyleUrl)
103
- const { hostname } = upstreamUrlObj
104
-
105
- if (key) {
106
- const paramToUpsert =
107
- MAP_PROVIDER_API_KEY_QUERY_PARAM_BY_HOSTNAME.get(hostname)
108
-
109
- if (paramToUpsert) {
110
- // Note that even if the search param of interest already exists in the url
111
- // it is overwritten by the key provided in the request's search params
112
- upstreamUrlObj.searchParams.set(paramToUpsert, key)
113
- } else {
114
- fastify.log.warn(
115
- `Provided API key will not be applied to unrecognized provider: ${hostname}`
116
- )
117
- }
118
- }
119
-
120
- try {
121
- const upstreamResponse = await fetch(upstreamUrlObj.href, {
122
- signal: AbortSignal.timeout(30_000),
123
- })
124
-
125
- if (upstreamResponse.ok) {
126
- // Set up headers to forward
127
- for (const [name, value] of upstreamResponse.headers) {
128
- // Only forward headers related to caching
129
- // https://www.rfc-editor.org/rfc/rfc9111#name-field-definitions
130
- // e.g. usage from map renderer: https://github.com/maplibre/maplibre-gl-js/blob/26a7a6c2c142ef2e26db89f5fdf2338769494902/src/util/ajax.ts#L205
131
- if (
132
- ['age', 'cache-control', 'expires'].includes(name.toLowerCase())
133
- ) {
134
- rep.header(name, value)
135
- }
136
- }
137
- // Some upstream providers will not set the 'application/json' content-type header despite the body being JSON e.g. Protomaps
138
- // TODO: Should we forward the upstream 'content-type' header?
139
- // We kind of assume that a Style Spec-compatible JSON payload will always be used by a provider
140
- // Technically, there could be cases where a provider doesn't use the Mapbox Style Spec and has their own format,
141
- // which may be delivered as some other content type
142
- rep.header('content-type', 'application/json; charset=utf-8')
143
- return upstreamResponse.json()
144
- } else {
145
- fastify.log.warn(
146
- `Upstream style.json request returned non-2xx status: ${upstreamResponse.status} ${upstreamResponse.statusText}`
147
- )
148
- }
149
- } catch (err) {
150
- fastify.log.warn('Failed to make upstream style.json request', err)
151
- }
152
- }
153
-
154
- // 3. Provide offline fallback map's style.json
155
- {
156
- let results = null
157
-
158
- try {
159
- results = await Promise.all([
160
- fastify.mapeoFallbackMap.getStyleJsonStats(),
161
- fastify.mapeoFallbackMap.getResolvedStyleJson(serverAddress),
162
- ])
163
- } catch (err) {
164
- throw new NotFoundError(`id = fallback, style.json`)
165
- }
166
-
167
- const [stats, styleJson] = results
168
- rep.headers(createStyleJsonResponseHeaders(stats.mtime))
169
- return styleJson
170
- }
171
- }
172
- )
173
- }
@@ -1,114 +0,0 @@
1
- import path from 'path'
2
- import fs from 'fs/promises'
3
- import FastifyStatic from '@fastify/static'
4
- import fp from 'fastify-plugin'
5
-
6
- import {
7
- NotFoundError,
8
- createStyleJsonResponseHeaders,
9
- getFastifyServerAddress,
10
- } from '../utils.js'
11
-
12
- export const PLUGIN_NAME = 'mapeo-static-maps'
13
-
14
- export const plugin = fp(offlineFallbackMapPlugin, {
15
- fastify: '4.x',
16
- name: PLUGIN_NAME,
17
- })
18
-
19
- /**
20
- * @typedef {object} OfflineFallbackMapPluginOpts
21
- * @property {string} [prefix]
22
- * @property {string} styleJsonPath
23
- * @property {string} sourcesDir
24
- */
25
-
26
- /**
27
- * @typedef {object} FallbackMapPluginDecorator
28
- * @property {(serverAddress: string) => Promise<any>} getResolvedStyleJson
29
- * @property {() => Promise<import('node:fs').Stats>} getStyleJsonStats
30
- */
31
-
32
- /** @type {import('fastify').FastifyPluginAsync<OfflineFallbackMapPluginOpts>} */
33
- async function offlineFallbackMapPlugin(fastify, opts) {
34
- const { styleJsonPath, sourcesDir } = opts
35
-
36
- fastify.decorate(
37
- 'mapeoFallbackMap',
38
- /** @type {FallbackMapPluginDecorator} */
39
- ({
40
- async getResolvedStyleJson(serverAddress) {
41
- const rawStyleJson = await fs.readFile(styleJsonPath, 'utf-8')
42
- const styleJson = JSON.parse(rawStyleJson)
43
-
44
- const sources = styleJson.sources || {}
45
-
46
- const sourcesDirFiles = await fs.readdir(sourcesDir, {
47
- withFileTypes: true,
48
- })
49
-
50
- for (const file of sourcesDirFiles) {
51
- if (!file.isFile()) continue
52
-
53
- if (file.name === 'style.json') continue
54
-
55
- const extension = path.extname(file.name).toLowerCase()
56
- if (!(extension === '.json' || extension === '.geojson')) continue
57
-
58
- const sourceName = path.basename(file.name, extension) + '-source'
59
-
60
- sources[sourceName] = {
61
- type: 'geojson',
62
- data: new URL(`${opts.prefix || ''}/${file.name}`, serverAddress)
63
- .href,
64
- }
65
- }
66
-
67
- styleJson.sources = sources
68
-
69
- return styleJson
70
- },
71
- getStyleJsonStats() {
72
- return fs.stat(styleJsonPath)
73
- },
74
- })
75
- )
76
-
77
- fastify.register(routes, {
78
- prefix: opts.prefix,
79
- styleJsonPath: opts.styleJsonPath,
80
- sourcesDir: opts.sourcesDir,
81
- })
82
- }
83
-
84
- /** @type {import('fastify').FastifyPluginAsync<OfflineFallbackMapPluginOpts, import('fastify').RawServerDefault, import('@fastify/type-provider-typebox').TypeBoxTypeProvider>} */
85
- async function routes(fastify, opts) {
86
- const { sourcesDir } = opts
87
-
88
- fastify.register(FastifyStatic, {
89
- root: sourcesDir,
90
- decorateReply: false,
91
- })
92
-
93
- fastify.get('/style.json', async (req, rep) => {
94
- const serverAddress = await getFastifyServerAddress(req.server.server)
95
-
96
- let stats, styleJson
97
-
98
- try {
99
- const results = await Promise.all([
100
- fastify.mapeoFallbackMap.getStyleJsonStats(),
101
- fastify.mapeoFallbackMap.getResolvedStyleJson(serverAddress),
102
- ])
103
-
104
- stats = results[0]
105
- styleJson = results[1]
106
- } catch (err) {
107
- throw new NotFoundError(`id = fallback, style.json`)
108
- }
109
-
110
- rep.headers(createStyleJsonResponseHeaders(stats.mtime))
111
-
112
- return styleJson
113
- })
114
- }
@@ -1,271 +0,0 @@
1
- import path from 'path'
2
- import fs from 'fs/promises'
3
- import FastifyStatic from '@fastify/static'
4
- import fp from 'fastify-plugin'
5
- import { Type as T } from '@sinclair/typebox'
6
- import asar from '@electron/asar'
7
- import { Mime } from 'mime/lite'
8
- import standardTypes from 'mime/types/standard.js'
9
-
10
- import {
11
- NotFoundError,
12
- createStyleJsonResponseHeaders,
13
- getFastifyServerAddress,
14
- } from '../utils.js'
15
-
16
- export const PLUGIN_NAME = 'mapeo-static-maps'
17
-
18
- export const plugin = fp(staticMapsPlugin, {
19
- fastify: '4.x',
20
- name: PLUGIN_NAME,
21
- })
22
-
23
- /**
24
- * @typedef {object} StaticMapsPluginOpts
25
- * @property {string} [prefix]
26
- * @property {string} staticRootDir
27
- */
28
-
29
- /**
30
- * @typedef {object} StaticMapsPluginDecorator
31
- * @property {(styleId: string, serverAddress: string) => Promise<string>} getResolvedStyleJson
32
- * @property {(styleId: string) => Promise<import('node:fs').Stats>} getStyleJsonStats
33
- */
34
-
35
- /** @type {import('fastify').FastifyPluginAsync<StaticMapsPluginOpts>} */
36
- async function staticMapsPlugin(fastify, opts) {
37
- fastify.decorate('mapeoStaticMaps', {
38
- async getResolvedStyleJson(styleId, serverAddress) {
39
- const filePath = path.join(opts.staticRootDir, styleId, 'style.json')
40
-
41
- const data = await fs.readFile(filePath, 'utf-8')
42
-
43
- return data.replace(
44
- /\{host\}/gm,
45
- new URL(`${opts.prefix || ''}/${styleId}`, serverAddress).href
46
- )
47
- },
48
- async getStyleJsonStats(styleId) {
49
- const filePath = path.join(opts.staticRootDir, styleId, 'style.json')
50
- const stats = await fs.stat(filePath)
51
- return stats
52
- },
53
- })
54
-
55
- fastify.register(routes, {
56
- prefix: opts.prefix,
57
- staticRootDir: opts.staticRootDir,
58
- })
59
- }
60
-
61
- const GetStaticMapTileParamsSchema = T.Object({
62
- styleId: T.String(),
63
- tileId: T.String(),
64
- z: T.Number(),
65
- y: T.Number(),
66
- x: T.Number(),
67
- ext: T.Optional(T.String()),
68
- })
69
-
70
- const ListStaticMapsReplySchema = T.Array(
71
- T.Object({
72
- id: T.String(),
73
- name: T.Union([T.String(), T.Null()]),
74
- styleUrl: T.String(),
75
- })
76
- )
77
-
78
- const GetStyleJsonParamsSchema = T.Object({
79
- styleId: T.String(),
80
- })
81
-
82
- /** @type {import('fastify').FastifyPluginAsync<StaticMapsPluginOpts, import('fastify').RawServerDefault, import('@fastify/type-provider-typebox').TypeBoxTypeProvider>} */
83
- async function routes(fastify, opts) {
84
- const { staticRootDir } = opts
85
-
86
- /**
87
- * @param {import('fastify').FastifyRequest<{Params: import('@sinclair/typebox').Static<typeof GetStaticMapTileParamsSchema>}>} req
88
- * @param {import('fastify').FastifyReply} rep
89
- */
90
- async function handleStyleTileGet(req, rep) {
91
- const result = getStyleTileInfo(staticRootDir, req.params)
92
-
93
- if (!result) {
94
- const { tileId, z, x, y, ext } = req.params
95
- throw new NotFoundError(
96
- `Tileset id = ${tileId}, ext=${ext}, [${z}, ${x}, ${y}]`
97
- )
98
- }
99
-
100
- const { data, mimeType } = result
101
-
102
- if (mimeType) {
103
- rep.header('Content-Type', mimeType)
104
- }
105
-
106
- rep.send(data)
107
- }
108
-
109
- // Serve static files
110
- fastify.register(FastifyStatic, {
111
- root: staticRootDir,
112
- setHeaders: (res, path) => {
113
- if (path.toLowerCase().endsWith('.pbf')) {
114
- res.setHeader('Content-Type', 'application/x-protobuf')
115
- }
116
- },
117
- })
118
-
119
- /// List static maps
120
- fastify.get(
121
- '/',
122
- { schema: { response: { 200: ListStaticMapsReplySchema } } },
123
- async (req) => {
124
- const styleDirFiles = await fs.readdir(staticRootDir)
125
-
126
- const serverAddress = await getFastifyServerAddress(req.server.server)
127
-
128
- const result = (
129
- await Promise.all(
130
- styleDirFiles.map(async (filename) => {
131
- const stat = await fs.stat(path.join(staticRootDir, filename))
132
- if (!stat.isDirectory()) return null
133
-
134
- let styleJson
135
-
136
- try {
137
- const styleJsonContent = await fs.readFile(
138
- path.join(staticRootDir, filename, 'style.json'),
139
- 'utf-8'
140
- )
141
-
142
- styleJson = JSON.parse(styleJsonContent)
143
- } catch (err) {
144
- return null
145
- }
146
-
147
- return {
148
- id: filename,
149
- name: typeof styleJson.name === 'string' ? styleJson.name : null,
150
- styleUrl: new URL(
151
- `${req.server.prefix || ''}/${filename}/style.json`,
152
- serverAddress
153
- ).href,
154
- }
155
- })
156
- )
157
- ).filter(
158
- /**
159
- * @template {import('@sinclair/typebox').Static<typeof ListStaticMapsReplySchema>[number] | null} V
160
- * @param {V} v
161
- * @returns {v is NonNullable<V>}
162
- */
163
- (v) => v !== null
164
- )
165
-
166
- return result
167
- }
168
- )
169
-
170
- /// Get a map's style.json
171
- fastify.get(
172
- `/:styleId/style.json`,
173
- { schema: { params: GetStyleJsonParamsSchema } },
174
- async (req, rep) => {
175
- const { styleId } = req.params
176
-
177
- const serverAddress = await getFastifyServerAddress(req.server.server)
178
-
179
- let stats, styleJson
180
-
181
- try {
182
- const results = await Promise.all([
183
- fastify.mapeoStaticMaps.getStyleJsonStats(styleId),
184
- fastify.mapeoStaticMaps.getResolvedStyleJson(styleId, serverAddress),
185
- ])
186
-
187
- stats = results[0]
188
- styleJson = results[1]
189
- } catch (err) {
190
- throw new NotFoundError(`id = ${styleId}, style.json`)
191
- }
192
-
193
- rep.headers(createStyleJsonResponseHeaders(stats.mtime))
194
-
195
- return styleJson
196
- }
197
- )
198
-
199
- // Get a tile (extension specified)
200
- fastify.get(
201
- `/:styleId/tiles/:tileId/:z/:x/:y.:ext`,
202
- { schema: { params: GetStaticMapTileParamsSchema } },
203
- handleStyleTileGet
204
- )
205
- // Get a tile (extension not specified)
206
- fastify.get(
207
- `/:styleId/tiles/:tileId/:z/:x/:y`,
208
- { schema: { params: GetStaticMapTileParamsSchema } },
209
- handleStyleTileGet
210
- )
211
- }
212
-
213
- /**
214
- * @param {string} archive
215
- * @param {string} filename
216
- */
217
- function extractAsarFile(archive, filename) {
218
- try {
219
- return asar.extractFile(archive, filename)
220
- } catch (err) {
221
- return undefined
222
- }
223
- }
224
-
225
- const mime = new Mime(standardTypes, { 'application/x-protobuf': ['pbf'] })
226
-
227
- /**
228
- * @param {string} baseDirectory
229
- * @param {import('@sinclair/typebox').Static<typeof GetStaticMapTileParamsSchema>} params
230
- * @returns {null | { data: Buffer, mimeType: string | null }}
231
- */
232
- function getStyleTileInfo(baseDirectory, params) {
233
- const { styleId, tileId, z, x, y } = params
234
- let { ext } = params
235
-
236
- // TODO: If necessary, need to flip the y value first if the TileJSON source is TMS scheme
237
- // Doing this will depend on if we decide that the asar directory structure should only follow XYZ or if it should align with corresponding tilejson spec
238
-
239
- const fileBasename = path.join(z.toString(), x.toString(), y.toString())
240
- const asarPath = path.join(baseDirectory, styleId, 'tiles', tileId + '.asar')
241
-
242
- /** @type {Buffer | undefined} */
243
- let data
244
-
245
- if (ext) {
246
- data = extractAsarFile(asarPath, fileBasename + '.' + ext)
247
- } else {
248
- // Try common extensions
249
- const extensions = ['png', 'jpg', 'jpeg']
250
-
251
- for (const e of extensions) {
252
- data = extractAsarFile(asarPath, fileBasename + '.' + e)
253
-
254
- // Match found, use the corresponding extension moving forward
255
- if (data) {
256
- ext = e
257
- break
258
- }
259
- }
260
- }
261
-
262
- // extension check isn't fully necessary since the buffer will only exist if the extension exists
263
- // but useful to check for types reasons
264
- if (!data || !ext) {
265
- return null
266
- }
267
-
268
- const mimeType = mime.getType(ext)
269
-
270
- return { data, mimeType }
271
- }