@biblioteksentralen/bmdb-search 0.0.0-beta.6 → 0.0.0-beta.8

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/README.md CHANGED
@@ -6,8 +6,7 @@ TypeScript client for searching Bibliotekenes metadatabrønn (BMDB) using [opena
6
6
 
7
7
  ### Client identification policy
8
8
 
9
- The API does not require authentication, but clients should identify themselves using a descriptive
10
- name and a contact address in the `clientIdentifier` string. We will only contact you about usage of the API.
9
+ Clients should identify themselves using a descriptive name and a contact address in the `clientIdentifier` string. We will only contact you about usage of the API.
11
10
 
12
11
  ## Usage examples
13
12
 
@@ -16,54 +15,29 @@ name and a contact address in the `clientIdentifier` string. We will only contac
16
15
  ```typescript
17
16
  import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search";
18
17
 
19
- const bmdbSearchClient = createBmdbFetchClient({ clientIdentifier: "client-unique-description" });
18
+ const bmdbSearchClient = createBmdbFetchClient({
19
+ clientIdentifier: "client-unique-description",
20
+ host: "https://search.data.bs.no",
21
+ });
22
+
20
23
  const { data, error } = await bmdbSearchClient.GET("/works/search", { params: { query: { query: "test" } } });
21
24
  ```
22
25
 
23
26
  The arguments and response are fully typed.
24
27
 
25
- ### Usage with tanstack-query, openapi-react-query and next.js
28
+ ### Usage with tanstack-query, openapi-react-query and React hooks
26
29
 
27
30
  Using [tanstack](https://tanstack.com/query/latest) for fetching with state management and [openapi-react-query](https://openapi-ts.dev/openapi-react-query/) for typing.
28
31
 
29
- Add a rewrite in the next.js config file to be able to use the frontend host without violating the content service policy:
30
-
31
- ```typescript
32
- // next.config.js or similar
33
- const searchApiHost = "https://search.data.bs.no";
34
-
35
- const config = {
36
- // ... other config ...
37
- rewrites() {
38
- return [
39
- {
40
- source: "/bmdb/api/:path*",
41
- destination: `${searchApiHost}/bmdb/api/:path*`,
42
- },
43
- ];
44
- },
45
- };
46
- ```
47
-
48
- If necessary, skip in middleware to exempt the API paths from internationalization etc:
49
-
50
- ```typescript
51
- // middleware.ts
52
- export const config = {
53
- matcher: [
54
- // ...other
55
- "/((?!|bmdb/api|_next/static).*)",
56
- ],
57
- };
58
- ```
59
-
60
- Create hooks and fetch data:
61
-
62
32
  ```typescript
63
33
  import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search";
64
34
  import createReactQueryClient from "openapi-react-query";
65
35
 
66
- const bmdbSearchClient = createBmdbFetchClient({ clientIdentifier: "client-unique-description" });
36
+ const bmdbSearchClient = createBmdbFetchClient({
37
+ clientIdentifier: "client-unique-description",
38
+ host: "https://search.data.bs.no"
39
+ });
40
+
67
41
  const { useQuery } = createReactQueryClient(bmdbSearchClient);
68
42
 
69
43
  const Component = () => {
package/dist/index.cjs CHANGED
@@ -19,10 +19,16 @@ var formatSingleTitle = ({ mainTitle, subtitle, partNumber, partTitle }, options
19
19
  var formatUniformTitleMusic = ({ form, instrumentation, serialNumber, opusNumber, thematicCatalogueNumber, part, key, arrangement }) => form + (instrumentation ? ` ${instrumentation}` : "") + (serialNumber ? `, ${serialNumber}` : "") + (opusNumber ? `, ${opusNumber}` : "") + (thematicCatalogueNumber ? `, ${thematicCatalogueNumber}` : "") + (part ? `, ${part}` : "") + (key ? `, ${key}` : "") + (arrangement ? `, ${arrangement}` : "");
20
20
  var createBmdbFetchClient = ({
21
21
  clientIdentifier,
22
+ host,
22
23
  version = "v1",
23
24
  ...options
24
25
  }) => {
25
- const baseUrl = `${options.baseUrl?.replace(/(.*)\/$/, "$1") ?? ""}/bmdb/api/${version}/`;
26
+ try {
27
+ new URL(host);
28
+ } catch {
29
+ throw new Error(`Invalid host URL: ${host}. The URL must be fully qualified with protocol.`);
30
+ }
31
+ const baseUrl = `${host.replace(/(.*)\/$/, "$1")}/bmdb/api/${version}/`;
26
32
  const client = createFetchClient__default.default({
27
33
  baseUrl,
28
34
  querySerializer: { array: { style: "form", explode: false } },
package/dist/index.d.cts CHANGED
@@ -26,6 +26,27 @@ interface paths {
26
26
  patch?: never;
27
27
  trace?: never;
28
28
  };
29
+ "/entities/search": {
30
+ parameters: {
31
+ query?: never;
32
+ header?: never;
33
+ path?: never;
34
+ cookie?: never;
35
+ };
36
+ /**
37
+ * Search entities
38
+ * @description Endpoint for searching BMDB entites. Implemented: agents.
39
+ *
40
+ */
41
+ get: operations["searchEntities"];
42
+ put?: never;
43
+ post?: never;
44
+ delete?: never;
45
+ options?: never;
46
+ head?: never;
47
+ patch?: never;
48
+ trace?: never;
49
+ };
29
50
  }
30
51
  interface components {
31
52
  schemas: {
@@ -1084,6 +1105,52 @@ interface components {
1084
1105
  advancedQueryErrors?: components["schemas"]["AdvanvedQueryError"][];
1085
1106
  sorting: components["schemas"]["WorkSort"];
1086
1107
  };
1108
+ /**
1109
+ * @description Facet type, this is the value given to the search facet parameter. The facet should always exists in as a corresponding filter.
1110
+ *
1111
+ * @enum {string}
1112
+ */
1113
+ EntityFacetType: "agent.nationality";
1114
+ /**
1115
+ * @description Sorting type, this is the value given to the search facet parameter.
1116
+ *
1117
+ * @enum {string}
1118
+ */
1119
+ EntitySort: "relevance.desc" | "updateTime.desc" | "updateTime.asc";
1120
+ EntityFilter: {
1121
+ /** @enum {string} */
1122
+ "type"?: "agent" | "place";
1123
+ "identifier"?: string;
1124
+ "agent.id"?: string;
1125
+ "agent.noraf_id"?: string;
1126
+ "agent.bokbasen_id"?: string;
1127
+ "agent.isni_id"?: string;
1128
+ };
1129
+ EntityFacet: {
1130
+ type: components["schemas"]["EntityFacetType"];
1131
+ /** @description A displayable (human readable) facet name. */
1132
+ name?: string;
1133
+ terms: components["schemas"]["FacetTerm"][];
1134
+ };
1135
+ GetEntitySearch200Response: {
1136
+ /** @description The total number of results in the whole search result. */
1137
+ total?: number;
1138
+ results: {
1139
+ entity?: components["schemas"]["Person"] | components["schemas"]["CollectiveAgent"] | components["schemas"]["Place"];
1140
+ }[];
1141
+ /** @description If this is false, we haven't reached the end of the search result yet, if it's false we have, and if it's missing or null we don't know. */
1142
+ endOfResults: boolean;
1143
+ /** @description This array contains the requested facets, and their terms. Each facet type should only appear once in the array. */
1144
+ facets?: components["schemas"]["EntityFacet"][];
1145
+ /**
1146
+ * @description Indicates what kind of search was performed, based on parsed input query.
1147
+ * @enum {string}
1148
+ */
1149
+ queryType?: "empty" | "standard" | "advanced";
1150
+ /** @description Parsing errors from advanced query. When they occur, the request is treated as a standard search. */
1151
+ advancedQueryErrors?: components["schemas"]["AdvanvedQueryError"][];
1152
+ sorting: components["schemas"]["EntitySort"];
1153
+ };
1087
1154
  };
1088
1155
  responses: never;
1089
1156
  parameters: never;
@@ -1102,10 +1169,10 @@ interface operations {
1102
1169
  * This is important to consider in any product design.
1103
1170
  * */
1104
1171
  size?: number;
1105
- /** @description Page number (deafult 1). */
1172
+ /** @description Page number (default 1). */
1106
1173
  page?: number;
1107
1174
  facet?: components["schemas"]["WorkFacetType"][];
1108
- /** @description Retun this number of facet terms for each requested facet (deafult 10). */
1175
+ /** @description Retun this number of facet terms for each requested facet (default 10). */
1109
1176
  facet_terms_size?: number;
1110
1177
  /** @description Sorting */
1111
1178
  sort?: components["schemas"]["WorkSort"];
@@ -1131,6 +1198,45 @@ interface operations {
1131
1198
  };
1132
1199
  };
1133
1200
  };
1201
+ searchEntities: {
1202
+ parameters: {
1203
+ query?: {
1204
+ /** @description The search query. */
1205
+ query?: string;
1206
+ /** @description Page size (default 10).
1207
+ * It's important to be aware that, the page size here is only a preferred page size, the result set can be both small and greater, depending on the implementation from the LMS provider.
1208
+ * This is important to consider in any product design.
1209
+ * */
1210
+ size?: number;
1211
+ /** @description Page number (default 1). */
1212
+ page?: number;
1213
+ facet?: components["schemas"]["EntityFacetType"][];
1214
+ /** @description Retun this number of facet terms for each requested facet (default 10). */
1215
+ facet_terms_size?: number;
1216
+ /** @description Sorting */
1217
+ sort?: components["schemas"]["EntitySort"];
1218
+ /** @description Each filter accepts multiple comma-separated values that are OR'ed together.
1219
+ * The filters themselves are AND'ed together.
1220
+ * */
1221
+ filter?: components["schemas"]["EntityFilter"];
1222
+ };
1223
+ header?: never;
1224
+ path?: never;
1225
+ cookie?: never;
1226
+ };
1227
+ requestBody?: never;
1228
+ responses: {
1229
+ /** @description List of entities */
1230
+ 200: {
1231
+ headers: {
1232
+ [name: string]: unknown;
1233
+ };
1234
+ content: {
1235
+ "application/json": components["schemas"]["GetEntitySearch200Response"];
1236
+ };
1237
+ };
1238
+ };
1239
+ };
1134
1240
  }
1135
1241
 
1136
1242
  type BmdbApiSchemas$1 = components["schemas"];
@@ -1151,10 +1257,11 @@ type BmdbApiPaths = paths;
1151
1257
 
1152
1258
  type BmdbSearchClientOptions = ClientOptions & {
1153
1259
  clientIdentifier: string;
1260
+ host: string;
1154
1261
  version?: "v1";
1155
1262
  };
1156
1263
  type BmdbSearchClient = Client<BmdbApiPaths>;
1157
- declare const createBmdbFetchClient: ({ clientIdentifier, version, ...options }: BmdbSearchClientOptions) => BmdbSearchClient;
1264
+ declare const createBmdbFetchClient: ({ clientIdentifier, host, version, ...options }: BmdbSearchClientOptions) => BmdbSearchClient;
1158
1265
 
1159
1266
  type BmdbWork = BmdbApiSchemas["Work"];
1160
1267
  type BmdbExpression = BmdbApiSchemas["Expression"];
package/dist/index.d.ts CHANGED
@@ -26,6 +26,27 @@ interface paths {
26
26
  patch?: never;
27
27
  trace?: never;
28
28
  };
29
+ "/entities/search": {
30
+ parameters: {
31
+ query?: never;
32
+ header?: never;
33
+ path?: never;
34
+ cookie?: never;
35
+ };
36
+ /**
37
+ * Search entities
38
+ * @description Endpoint for searching BMDB entites. Implemented: agents.
39
+ *
40
+ */
41
+ get: operations["searchEntities"];
42
+ put?: never;
43
+ post?: never;
44
+ delete?: never;
45
+ options?: never;
46
+ head?: never;
47
+ patch?: never;
48
+ trace?: never;
49
+ };
29
50
  }
30
51
  interface components {
31
52
  schemas: {
@@ -1084,6 +1105,52 @@ interface components {
1084
1105
  advancedQueryErrors?: components["schemas"]["AdvanvedQueryError"][];
1085
1106
  sorting: components["schemas"]["WorkSort"];
1086
1107
  };
1108
+ /**
1109
+ * @description Facet type, this is the value given to the search facet parameter. The facet should always exists in as a corresponding filter.
1110
+ *
1111
+ * @enum {string}
1112
+ */
1113
+ EntityFacetType: "agent.nationality";
1114
+ /**
1115
+ * @description Sorting type, this is the value given to the search facet parameter.
1116
+ *
1117
+ * @enum {string}
1118
+ */
1119
+ EntitySort: "relevance.desc" | "updateTime.desc" | "updateTime.asc";
1120
+ EntityFilter: {
1121
+ /** @enum {string} */
1122
+ "type"?: "agent" | "place";
1123
+ "identifier"?: string;
1124
+ "agent.id"?: string;
1125
+ "agent.noraf_id"?: string;
1126
+ "agent.bokbasen_id"?: string;
1127
+ "agent.isni_id"?: string;
1128
+ };
1129
+ EntityFacet: {
1130
+ type: components["schemas"]["EntityFacetType"];
1131
+ /** @description A displayable (human readable) facet name. */
1132
+ name?: string;
1133
+ terms: components["schemas"]["FacetTerm"][];
1134
+ };
1135
+ GetEntitySearch200Response: {
1136
+ /** @description The total number of results in the whole search result. */
1137
+ total?: number;
1138
+ results: {
1139
+ entity?: components["schemas"]["Person"] | components["schemas"]["CollectiveAgent"] | components["schemas"]["Place"];
1140
+ }[];
1141
+ /** @description If this is false, we haven't reached the end of the search result yet, if it's false we have, and if it's missing or null we don't know. */
1142
+ endOfResults: boolean;
1143
+ /** @description This array contains the requested facets, and their terms. Each facet type should only appear once in the array. */
1144
+ facets?: components["schemas"]["EntityFacet"][];
1145
+ /**
1146
+ * @description Indicates what kind of search was performed, based on parsed input query.
1147
+ * @enum {string}
1148
+ */
1149
+ queryType?: "empty" | "standard" | "advanced";
1150
+ /** @description Parsing errors from advanced query. When they occur, the request is treated as a standard search. */
1151
+ advancedQueryErrors?: components["schemas"]["AdvanvedQueryError"][];
1152
+ sorting: components["schemas"]["EntitySort"];
1153
+ };
1087
1154
  };
1088
1155
  responses: never;
1089
1156
  parameters: never;
@@ -1102,10 +1169,10 @@ interface operations {
1102
1169
  * This is important to consider in any product design.
1103
1170
  * */
1104
1171
  size?: number;
1105
- /** @description Page number (deafult 1). */
1172
+ /** @description Page number (default 1). */
1106
1173
  page?: number;
1107
1174
  facet?: components["schemas"]["WorkFacetType"][];
1108
- /** @description Retun this number of facet terms for each requested facet (deafult 10). */
1175
+ /** @description Retun this number of facet terms for each requested facet (default 10). */
1109
1176
  facet_terms_size?: number;
1110
1177
  /** @description Sorting */
1111
1178
  sort?: components["schemas"]["WorkSort"];
@@ -1131,6 +1198,45 @@ interface operations {
1131
1198
  };
1132
1199
  };
1133
1200
  };
1201
+ searchEntities: {
1202
+ parameters: {
1203
+ query?: {
1204
+ /** @description The search query. */
1205
+ query?: string;
1206
+ /** @description Page size (default 10).
1207
+ * It's important to be aware that, the page size here is only a preferred page size, the result set can be both small and greater, depending on the implementation from the LMS provider.
1208
+ * This is important to consider in any product design.
1209
+ * */
1210
+ size?: number;
1211
+ /** @description Page number (default 1). */
1212
+ page?: number;
1213
+ facet?: components["schemas"]["EntityFacetType"][];
1214
+ /** @description Retun this number of facet terms for each requested facet (default 10). */
1215
+ facet_terms_size?: number;
1216
+ /** @description Sorting */
1217
+ sort?: components["schemas"]["EntitySort"];
1218
+ /** @description Each filter accepts multiple comma-separated values that are OR'ed together.
1219
+ * The filters themselves are AND'ed together.
1220
+ * */
1221
+ filter?: components["schemas"]["EntityFilter"];
1222
+ };
1223
+ header?: never;
1224
+ path?: never;
1225
+ cookie?: never;
1226
+ };
1227
+ requestBody?: never;
1228
+ responses: {
1229
+ /** @description List of entities */
1230
+ 200: {
1231
+ headers: {
1232
+ [name: string]: unknown;
1233
+ };
1234
+ content: {
1235
+ "application/json": components["schemas"]["GetEntitySearch200Response"];
1236
+ };
1237
+ };
1238
+ };
1239
+ };
1134
1240
  }
1135
1241
 
1136
1242
  type BmdbApiSchemas$1 = components["schemas"];
@@ -1151,10 +1257,11 @@ type BmdbApiPaths = paths;
1151
1257
 
1152
1258
  type BmdbSearchClientOptions = ClientOptions & {
1153
1259
  clientIdentifier: string;
1260
+ host: string;
1154
1261
  version?: "v1";
1155
1262
  };
1156
1263
  type BmdbSearchClient = Client<BmdbApiPaths>;
1157
- declare const createBmdbFetchClient: ({ clientIdentifier, version, ...options }: BmdbSearchClientOptions) => BmdbSearchClient;
1264
+ declare const createBmdbFetchClient: ({ clientIdentifier, host, version, ...options }: BmdbSearchClientOptions) => BmdbSearchClient;
1158
1265
 
1159
1266
  type BmdbWork = BmdbApiSchemas["Work"];
1160
1267
  type BmdbExpression = BmdbApiSchemas["Expression"];
package/dist/index.js CHANGED
@@ -13,10 +13,16 @@ var formatSingleTitle = ({ mainTitle, subtitle, partNumber, partTitle }, options
13
13
  var formatUniformTitleMusic = ({ form, instrumentation, serialNumber, opusNumber, thematicCatalogueNumber, part, key, arrangement }) => form + (instrumentation ? ` ${instrumentation}` : "") + (serialNumber ? `, ${serialNumber}` : "") + (opusNumber ? `, ${opusNumber}` : "") + (thematicCatalogueNumber ? `, ${thematicCatalogueNumber}` : "") + (part ? `, ${part}` : "") + (key ? `, ${key}` : "") + (arrangement ? `, ${arrangement}` : "");
14
14
  var createBmdbFetchClient = ({
15
15
  clientIdentifier,
16
+ host,
16
17
  version = "v1",
17
18
  ...options
18
19
  }) => {
19
- const baseUrl = `${options.baseUrl?.replace(/(.*)\/$/, "$1") ?? ""}/bmdb/api/${version}/`;
20
+ try {
21
+ new URL(host);
22
+ } catch {
23
+ throw new Error(`Invalid host URL: ${host}. The URL must be fully qualified with protocol.`);
24
+ }
25
+ const baseUrl = `${host.replace(/(.*)\/$/, "$1")}/bmdb/api/${version}/`;
20
26
  const client = createFetchClient({
21
27
  baseUrl,
22
28
  querySerializer: { array: { style: "form", explode: false } },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biblioteksentralen/bmdb-search",
3
- "version": "0.0.0-beta.6",
3
+ "version": "0.0.0-beta.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Client for searching Bibliotekenes metadatabrønn (BMDB)",