Skip to content

Commit

Permalink
enhance: build some safety around assetMap reads
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelgerber committed Feb 4, 2025
1 parent ab3cc51 commit 8ce7d67
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 12 deletions.
1 change: 0 additions & 1 deletion baker/buildLocalArchivalBake.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ const copyPublicDir = async () => {
const ignoredFilesPattern = new RegExp(
IGNORED_FILES_PATTERNS.map((p) => p.source).join("|")
)
console.log(ignoredFilesPattern)
await fs.copy(publicDir, targetDir, {
overwrite: true,
filter: (src) => {
Expand Down
18 changes: 11 additions & 7 deletions packages/@ourworldindata/grapher/src/core/loadVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
AssetMap,
OwidVariableDataMetadataDimensions,
} from "@ourworldindata/types"
import { fetchWithRetry } from "@ourworldindata/utils"
import { fetchWithRetry, readFromAssetMap } from "@ourworldindata/utils"

export const getVariableDataRoute = (
dataApiUrl: string,
Expand All @@ -11,9 +11,11 @@ export const getVariableDataRoute = (
): string => {
if (dataApiUrl.includes("v1/indicators/")) {
const filename = `${variableId}.data.json`
if (assetMap?.[filename]) return assetMap[filename]
// fetching from Data API, e.g. https://api.ourworldindata.org/v1/indicators/123.data.json
return `${dataApiUrl}${filename}`
return readFromAssetMap(assetMap, {
path: filename,
// fetching from Data API, e.g. https://api.ourworldindata.org/v1/indicators/123.data.json
fallback: `${dataApiUrl}${filename}`,
})
} else {
throw new Error(`dataApiUrl format not supported: ${dataApiUrl}`)
}
Expand All @@ -26,9 +28,11 @@ export const getVariableMetadataRoute = (
): string => {
if (dataApiUrl.includes("v1/indicators/")) {
const filename = `${variableId}.metadata.json`
if (assetMap?.[filename]) return assetMap[filename]
// fetching from Data API, e.g. https://api.ourworldindata.org/v1/indicators/123.metadata.json
return `${dataApiUrl}${filename}`
return readFromAssetMap(assetMap, {
path: filename,
// fetching from Data API, e.g. https://api.ourworldindata.org/v1/indicators/123.metadata.json
fallback: `${dataApiUrl}${filename}`,
})
} else {
throw new Error(`dataApiUrl format not supported: ${dataApiUrl}`)
}
Expand Down
28 changes: 28 additions & 0 deletions packages/@ourworldindata/utils/src/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ import {
DimensionProperty,
GRAPHER_CHART_TYPES,
DbPlainTag,
AssetMap,
} from "@ourworldindata/types"
import { PointVector } from "./PointVector.js"
import * as React from "react"
Expand Down Expand Up @@ -2076,3 +2077,30 @@ export function isArrayDifferentFromReference<T>(
if (array.length !== referenceArray.length) return true
return difference(array, referenceArray).length > 0
}

// When reading from an asset map, we want a very particular behavior:
// If the asset map is entirely undefined, then we want to just fail silently and return the fallback.
// If the asset map is defined but the asset is not found, however, then we want to throw an error.
// This is to avoid invisible errors that'll lead to runtime errors or 404s.

export function readFromAssetMap(
assetMap: AssetMap | undefined,
{ path, fallback }: { path: string; fallback: string }
): string

export function readFromAssetMap(
assetMap: AssetMap | undefined,
{ path, fallback }: { path: string; fallback?: string }
): string | undefined

export function readFromAssetMap(
assetMap: AssetMap | undefined,
{ path, fallback }: { path: string; fallback?: string }
): string | undefined {
if (!assetMap) return fallback

const assetValue = assetMap[path]
if (assetValue === undefined)
throw new Error(`Entry for asset not found in asset map: ${path}`)
return assetValue
}
1 change: 1 addition & 0 deletions packages/@ourworldindata/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export {
lazy,
getParentVariableIdFromChartConfig,
isArrayDifferentFromReference,
readFromAssetMap,
} from "./Util.js"

export {
Expand Down
7 changes: 5 additions & 2 deletions site/detailsOnDemand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
AssetMap,
DetailDictionary,
fetchWithRetry,
readFromAssetMap,
} from "@ourworldindata/utils"
import { SiteAnalytics } from "./SiteAnalytics.js"

Expand All @@ -27,8 +28,10 @@ export async function runDetailsOnDemand({
}: {
runtimeAssetMap?: AssetMap
} = {}) {
const dodFetchUrl =
runtimeAssetMap?.["dods.json"] ?? `${BAKED_BASE_URL}/dods.json`
const dodFetchUrl = readFromAssetMap(runtimeAssetMap, {
path: "dods.json",
fallback: `${BAKED_BASE_URL}/dods.json`,
})

window.details = await fetchWithRetry(dodFetchUrl, {
method: "GET",
Expand Down
7 changes: 5 additions & 2 deletions site/viteUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from "../settings/serverSettings.js"
import { POLYFILL_URL } from "./SiteConstants.js"
import type { Manifest, ManifestChunk } from "vite"
import { sortBy } from "@ourworldindata/utils"
import { readFromAssetMap, sortBy } from "@ourworldindata/utils"
import urljoin from "url-join"
import { AssetMap } from "@ourworldindata/types"

Expand Down Expand Up @@ -111,7 +111,10 @@ export const createTagsForManifestEntry = (
throw new Error(`Could not find manifest entry for ${entry}`)

const assetKey = manifestEntry?.file ?? entry
const assetUrl = assetMap?.[assetKey] ?? urljoin(assetBaseUrl, assetKey)
const assetUrl = readFromAssetMap(assetMap, {
path: assetKey,
fallback: urljoin(assetBaseUrl, assetKey),
})

if (entry.endsWith(".css")) {
assets = [
Expand Down

0 comments on commit 8ce7d67

Please sign in to comment.