@refkit/provider-met 0.4.0 → 0.4.1
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.js +6 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
offsetForPage
|
|
10
10
|
} from "@refkit/core";
|
|
11
11
|
var BASE = "https://collectionapi.metmuseum.org/public/collection/v1";
|
|
12
|
+
var SEARCH = "https://collectionapi.metmuseum.org/public/collection/v1.1/search";
|
|
12
13
|
function toReference(o) {
|
|
13
14
|
if (!o.isPublicDomain) return null;
|
|
14
15
|
const image = o.primaryImage || o.primaryImageSmall;
|
|
@@ -42,9 +43,12 @@ function met(config = {}) {
|
|
|
42
43
|
description: "Open Access artworks from the Metropolitan Museum of Art",
|
|
43
44
|
capabilities: { controls: ["page"] },
|
|
44
45
|
async search(q, ctx) {
|
|
45
|
-
const
|
|
46
|
+
const n = Math.min(config.maxObjects ?? q.limit ?? 12, 30);
|
|
47
|
+
const searchUrl = new URL(SEARCH);
|
|
46
48
|
searchUrl.searchParams.set("q", q.text);
|
|
47
49
|
searchUrl.searchParams.set("hasImages", "true");
|
|
50
|
+
searchUrl.searchParams.set("offset", String(offsetForPage(q.controls?.page, n) ?? 0));
|
|
51
|
+
searchUrl.searchParams.set("limit", String(n));
|
|
48
52
|
const opts = q.providerOptions;
|
|
49
53
|
setIfBoolean(searchUrl, "isHighlight", opts?.isHighlight);
|
|
50
54
|
setIfBoolean(searchUrl, "title", opts?.title);
|
|
@@ -59,9 +63,7 @@ function met(config = {}) {
|
|
|
59
63
|
const res = await ctx.fetch(searchUrl.toString(), { signal: ctx.signal });
|
|
60
64
|
const { objectIDs } = await okJson(res, "met search");
|
|
61
65
|
if (!objectIDs || objectIDs.length === 0) return [];
|
|
62
|
-
const
|
|
63
|
-
const from = offsetForPage(q.controls?.page, n) ?? 0;
|
|
64
|
-
const objects = await Promise.all(objectIDs.slice(from, from + n).map(async (id) => {
|
|
66
|
+
const objects = await Promise.all(objectIDs.slice(0, n).map(async (id) => {
|
|
65
67
|
try {
|
|
66
68
|
const r = await ctx.fetch(`${BASE}/objects/${id}`, { signal: ctx.signal });
|
|
67
69
|
if (!r.ok) return null;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n defineProvider, okJson, plainText, setIfBoolean, setIfInt, setIfString,\n type EmittedReference, type RightsRecord, type NormalizedQuery, type ProviderContext,\n offsetForPage,\n} from '@refkit/core'\n\nexport interface MetConfig {\n /** Max objects fetched per search. The Met search returns only IDs, so each\n * result costs one extra call — this bounds that N+1 fan-out. Default 12. */\n maxObjects?: number\n}\n\nexport interface MetSearchOptions {\n isHighlight?: boolean\n title?: boolean\n tags?: boolean\n departmentId?: number\n isOnView?: boolean\n artistOrCulture?: boolean\n medium?: string\n geoLocation?: string\n dateBegin?: number\n dateEnd?: number\n}\n\nconst BASE = 'https://collectionapi.metmuseum.org/public/collection/v1'\n\ninterface MetSearchResponse { total: number; objectIDs: number[] | null }\ninterface MetObject {\n objectID: number\n isPublicDomain: boolean\n primaryImage: string\n primaryImageSmall: string\n title: string\n artistDisplayName: string\n objectURL: string\n objectName: string\n medium: string\n culture?: string\n period?: string\n classification?: string\n tags?: Array<{ term: string }> | null\n}\n\nfunction toReference(o: MetObject): EmittedReference | null {\n // The Met releases open-access (public-domain) images under CC0. Copyrighted\n // works return an empty primaryImage — nothing usable to surface.\n if (!o.isPublicDomain) return null\n const image = o.primaryImage || o.primaryImageSmall\n if (!image) return null\n const rights: RightsRecord = {\n license: 'CC0-1.0',\n author: o.artistDisplayName || undefined,\n rehostPolicy: 'cache-allowed',\n raw: { sourceTerms: 'https://www.metmuseum.org/information/terms-and-conditions', sourceUrl: o.objectURL },\n }\n // The Met has no caption field; objectName/medium/culture/period are the descriptive\n // facets it does return, and reading as one line is what the reranker scores. Some\n // `medium` values run long and carry line breaks, so normalize through plainText.\n const description = plainText([o.objectName, o.medium, o.culture, o.period].filter(Boolean).join('. '))\n const tags = [o.classification, ...(o.tags ?? []).map(t => t.term)].filter((t): t is string => !!t)\n return {\n modality: 'image',\n kind: 'artwork',\n title: o.title || undefined,\n ...(description ? { description } : {}),\n ...(tags.length > 0 ? { tags } : {}),\n sourceUrl: o.objectURL,\n rights,\n ...(o.primaryImageSmall ? { thumbnail: { url: o.primaryImageSmall } } : {}),\n preview: { url: image, mediaType: 'image/jpeg' },\n raw: o,\n }\n}\n\nexport function met(config: MetConfig = {}) {\n return defineProvider({\n id: 'met',\n modalities: ['image'],\n kinds: ['artwork'],\n description: 'Open Access artworks from the Metropolitan Museum of Art',\n capabilities: { controls: ['page'] },\n async search(q: NormalizedQuery, ctx: ProviderContext): Promise<EmittedReference[]> {\n const searchUrl = new URL(
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n defineProvider, okJson, plainText, setIfBoolean, setIfInt, setIfString,\n type EmittedReference, type RightsRecord, type NormalizedQuery, type ProviderContext,\n offsetForPage,\n} from '@refkit/core'\n\nexport interface MetConfig {\n /** Max objects fetched per search. The Met search returns only IDs, so each\n * result costs one extra call — this bounds that N+1 fan-out. Default 12. */\n maxObjects?: number\n}\n\nexport interface MetSearchOptions {\n isHighlight?: boolean\n title?: boolean\n tags?: boolean\n departmentId?: number\n isOnView?: boolean\n artistOrCulture?: boolean\n medium?: string\n geoLocation?: string\n dateBegin?: number\n dateEnd?: number\n}\n\nconst BASE = 'https://collectionapi.metmuseum.org/public/collection/v1'\n// /v1/search (every matching id in one response) was retired on 2026-10-01 and now answers\n// 410. /v1.1/search takes the same filters plus offset/limit and returns one page of ids;\n// upstream caps limit at 500 and serves only the first 10,000 results of a query.\nconst SEARCH = 'https://collectionapi.metmuseum.org/public/collection/v1.1/search'\n\ninterface MetSearchResponse { total: number; objectIDs: number[] | null }\ninterface MetObject {\n objectID: number\n isPublicDomain: boolean\n primaryImage: string\n primaryImageSmall: string\n title: string\n artistDisplayName: string\n objectURL: string\n objectName: string\n medium: string\n culture?: string\n period?: string\n classification?: string\n tags?: Array<{ term: string }> | null\n}\n\nfunction toReference(o: MetObject): EmittedReference | null {\n // The Met releases open-access (public-domain) images under CC0. Copyrighted\n // works return an empty primaryImage — nothing usable to surface.\n if (!o.isPublicDomain) return null\n const image = o.primaryImage || o.primaryImageSmall\n if (!image) return null\n const rights: RightsRecord = {\n license: 'CC0-1.0',\n author: o.artistDisplayName || undefined,\n rehostPolicy: 'cache-allowed',\n raw: { sourceTerms: 'https://www.metmuseum.org/information/terms-and-conditions', sourceUrl: o.objectURL },\n }\n // The Met has no caption field; objectName/medium/culture/period are the descriptive\n // facets it does return, and reading as one line is what the reranker scores. Some\n // `medium` values run long and carry line breaks, so normalize through plainText.\n const description = plainText([o.objectName, o.medium, o.culture, o.period].filter(Boolean).join('. '))\n const tags = [o.classification, ...(o.tags ?? []).map(t => t.term)].filter((t): t is string => !!t)\n return {\n modality: 'image',\n kind: 'artwork',\n title: o.title || undefined,\n ...(description ? { description } : {}),\n ...(tags.length > 0 ? { tags } : {}),\n sourceUrl: o.objectURL,\n rights,\n ...(o.primaryImageSmall ? { thumbnail: { url: o.primaryImageSmall } } : {}),\n preview: { url: image, mediaType: 'image/jpeg' },\n raw: o,\n }\n}\n\nexport function met(config: MetConfig = {}) {\n return defineProvider({\n id: 'met',\n modalities: ['image'],\n kinds: ['artwork'],\n description: 'Open Access artworks from the Metropolitan Museum of Art',\n capabilities: { controls: ['page'] },\n async search(q: NormalizedQuery, ctx: ProviderContext): Promise<EmittedReference[]> {\n const n = Math.min(config.maxObjects ?? q.limit ?? 12, 30)\n const searchUrl = new URL(SEARCH)\n searchUrl.searchParams.set('q', q.text)\n searchUrl.searchParams.set('hasImages', 'true')\n searchUrl.searchParams.set('offset', String(offsetForPage(q.controls?.page, n) ?? 0))\n searchUrl.searchParams.set('limit', String(n))\n const opts = q.providerOptions as MetSearchOptions | undefined\n setIfBoolean(searchUrl, 'isHighlight', opts?.isHighlight)\n setIfBoolean(searchUrl, 'title', opts?.title)\n setIfBoolean(searchUrl, 'tags', opts?.tags)\n setIfInt(searchUrl, 'departmentId', opts?.departmentId)\n setIfBoolean(searchUrl, 'isOnView', opts?.isOnView)\n setIfBoolean(searchUrl, 'artistOrCulture', opts?.artistOrCulture)\n setIfString(searchUrl, 'medium', opts?.medium)\n setIfString(searchUrl, 'geoLocation', opts?.geoLocation)\n setIfInt(searchUrl, 'dateBegin', opts?.dateBegin)\n setIfInt(searchUrl, 'dateEnd', opts?.dateEnd)\n const res = await ctx.fetch(searchUrl.toString(), { signal: ctx.signal })\n const { objectIDs } = await okJson<MetSearchResponse>(res, 'met search')\n if (!objectIDs || objectIDs.length === 0) return []\n // objectIDs is already the requested page; the slice only bounds the N+1 object fan-out\n const objects = await Promise.all(objectIDs.slice(0, n).map(async (id) => {\n try {\n const r = await ctx.fetch(`${BASE}/objects/${id}`, { signal: ctx.signal })\n if (!r.ok) return null\n return (await r.json()) as MetObject\n } catch {\n return null // one bad object fetch must not drop the whole batch\n }\n }))\n return objects\n .map((o) => (o ? toReference(o) : null))\n .filter((r): r is EmittedReference => r !== null)\n },\n })\n}\n"],"mappings":"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","names":[]}
|