batteryincluded 1.0.1 → 1.0.3

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
@@ -97,6 +97,11 @@ export default defineCodegenConfig({
97
97
  per_page: 100,
98
98
  },
99
99
  },
100
+ '/suggest': {
101
+ query: {
102
+ q: 'custom search term'
103
+ }
104
+ }
100
105
  })
101
106
  ```
102
107
 
@@ -104,10 +109,10 @@ For more information on the code generator and how to customize the probe config
104
109
 
105
110
  ## License
106
111
 
107
- Published under the [MIT License](https://github.com/freb97/autodisco/tree/main/LICENSE).
112
+ Published under the [MIT License](https://github.com/bussmann-io/batteryincluded-ts/tree/main/LICENSE).
108
113
 
109
- [github-actions-src]: https://github.com/freb97/batteryincluded-ts/actions/workflows/test.yml/badge.svg
110
- [github-actions-href]: https://github.com/freb97/batteryincluded-ts/actions
114
+ [github-actions-src]: https://github.com/bussmann-io/batteryincluded-ts/actions/workflows/test.yml/badge.svg
115
+ [github-actions-href]: https://github.com/bussmann-io/batteryincluded-ts/actions
111
116
 
112
117
  [npm-version-src]: https://img.shields.io/npm/v/batteryincluded/latest.svg?style=flat&colorA=18181B&colorB=31C553
113
118
  [npm-version-href]: https://npmjs.com/package/batteryincluded
@@ -115,5 +120,5 @@ Published under the [MIT License](https://github.com/freb97/autodisco/tree/main/
115
120
  [npm-last-update-src]: https://img.shields.io/npm/last-update/batteryincluded.svg?style=flat&colorA=18181B&colorB=31C553
116
121
  [npm-last-update-href]: https://npmjs.com/package/batteryincluded
117
122
 
118
- [license-src]: https://img.shields.io/github/license/freb97/batteryincluded-ts.svg?style=flat&colorA=18181B&colorB=31C553
119
- [license-href]: https://github.com/freb97/batteryincluded-ts/tree/main/LICENSE
123
+ [license-src]: https://img.shields.io/github/license/bussmann-io/batteryincluded-ts.svg?style=flat&colorA=18181B&colorB=31C553
124
+ [license-href]: https://github.com/bussmann-io/batteryincluded-ts/tree/main/LICENSE
@@ -1,17 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { buildBaseUrl, buildHeaders, createClient } from "../_chunks/client.mjs";
3
+ import process from "node:process";
4
+ import { defineCommand, runMain } from "citty";
5
+ import { config } from "dotenv";
3
6
  import { writeFile } from "node:fs/promises";
4
7
  import { join } from "node:path";
5
- import process from "node:process";
6
8
  import discover from "autodisco";
7
9
  import { loadConfig } from "c12";
8
- import { defineCommand, runMain } from "citty";
9
10
  import defu from "defu";
10
- import { config } from "dotenv";
11
- const { parsed } = config({ quiet: true });
12
- const env = parsed ?? process.env;
13
- const COLLECTION = Object.entries(env).find(([key]) => key.endsWith("BATTERYINCLUDED_COLLECTION"))?.[1];
14
- const API_KEY = Object.entries(env).find(([key]) => key.endsWith("BATTERYINCLUDED_API_KEY"))?.[1];
15
11
  function buildAugmentationFile() {
16
12
  return [
17
13
  "import type { paths as generatedPaths, components as generatedComponents } from './openapi/types'",
@@ -25,6 +21,51 @@ function buildAugmentationFile() {
25
21
  ""
26
22
  ].join("\n");
27
23
  }
24
+ async function codegen(args) {
25
+ if (!args.collection) throw new Error("Collection name is required. Please specify it using the --collection flag or set the BATTERYINCLUDED_COLLECTION environment variable.");
26
+ if (!args.apiKey) throw new Error("API key is required. Please specify it using the --api-key flag or set the BATTERYINCLUDED_API_KEY environment variable.");
27
+ const { config: resolved } = await loadConfig({
28
+ name: "batteryincluded",
29
+ cwd: process.cwd(),
30
+ rcFile: "batteryincluded-rc",
31
+ globalRc: false,
32
+ dotenv: false
33
+ });
34
+ let config = resolved ?? {};
35
+ const suggestQuery = args.suggestQuery ?? "a";
36
+ let recommendationId = args.recommendationId;
37
+ if (!recommendationId) recommendationId = await createClient({
38
+ collection: args.collection,
39
+ apiKey: args.apiKey
40
+ }).GET("/browse", { params: { query: { per_page: 1 } } }).then(({ data }) => data?.hits?.[0]?.document?.id);
41
+ if (!recommendationId) throw new Error("No document found in the collection to use for generating recommendation types. Please specify a document ID using the --recommendation-id flag or ensure that the collection contains at least one document.");
42
+ config = defu(config, {
43
+ "/browse": { query: {
44
+ page: 1,
45
+ per_page: 10
46
+ } },
47
+ "/highlights": {},
48
+ "/suggest": { query: { q: suggestQuery } },
49
+ "/recommendations": { query: { id: recommendationId } },
50
+ "/similar-search": { query: { q: suggestQuery } },
51
+ "/presets": {}
52
+ });
53
+ await discover({
54
+ baseUrl: buildBaseUrl(args.collection),
55
+ headers: buildHeaders(args.apiKey),
56
+ outputDir: args.outputDir,
57
+ generate: {
58
+ markdown: false,
59
+ openapi: { typescript: true }
60
+ },
61
+ probes: { get: { ...config } }
62
+ });
63
+ await writeFile(join(args.outputDir, "index.d.ts"), buildAugmentationFile(), "utf8");
64
+ }
65
+ const { parsed } = config({ quiet: true });
66
+ const env = parsed ?? process.env;
67
+ const COLLECTION = Object.entries(env).find(([key]) => key.endsWith("BATTERYINCLUDED_COLLECTION"))?.[1];
68
+ const API_KEY = Object.entries(env).find(([key]) => key.endsWith("BATTERYINCLUDED_API_KEY"))?.[1];
28
69
  runMain(defineCommand({
29
70
  meta: {
30
71
  name: "codegen",
@@ -60,46 +101,6 @@ runMain(defineCommand({
60
101
  required: false
61
102
  }
62
103
  },
63
- run: async ({ args }) => {
64
- if (!args.collection) throw new Error("Collection name is required. Please specify it using the --collection flag or set the BATTERYINCLUDED_COLLECTION environment variable.");
65
- if (!args.apiKey) throw new Error("API key is required. Please specify it using the --api-key flag or set the BATTERYINCLUDED_API_KEY environment variable.");
66
- const { config: resolved } = await loadConfig({
67
- name: "batteryincluded",
68
- cwd: process.cwd(),
69
- rcFile: "batteryincluded-rc",
70
- globalRc: false,
71
- dotenv: false
72
- });
73
- let config = resolved ?? {};
74
- const suggestQuery = args.suggestQuery ?? "a";
75
- let recommendationId = args.recommendationId;
76
- if (!recommendationId) recommendationId = await createClient({
77
- collection: args.collection,
78
- apiKey: args.apiKey
79
- }).GET("/browse", { params: { query: { per_page: 1 } } }).then(({ data }) => data?.hits?.[0]?.document?.id);
80
- if (!recommendationId) throw new Error("No document found in the collection to use for generating recommendation types. Please specify a document ID using the --recommendation-id flag or ensure that the collection contains at least one document.");
81
- config = defu(config, {
82
- "/browse": { query: {
83
- page: 1,
84
- per_page: 10
85
- } },
86
- "/highlights": {},
87
- "/suggest": { query: { q: suggestQuery } },
88
- "/recommendations": { query: { id: recommendationId } },
89
- "/similar-search": { query: { q: suggestQuery } },
90
- "/presets": {}
91
- });
92
- await discover({
93
- baseUrl: buildBaseUrl(args.collection),
94
- headers: buildHeaders(args.apiKey),
95
- outputDir: args.outputDir,
96
- generate: {
97
- markdown: false,
98
- openapi: { typescript: true }
99
- },
100
- probes: { get: { ...config } }
101
- });
102
- await writeFile(join(args.outputDir, "index.d.ts"), buildAugmentationFile(), "utf8");
103
- }
104
+ run: async ({ args }) => await codegen(args)
104
105
  }));
105
106
  export {};
package/dist/index.d.mts CHANGED
@@ -1,32 +1,185 @@
1
1
  import { ProbeConfig } from "autodisco";
2
+ /**
3
+ * Facet type representing the shape of a facet in the Browse response. It can be either a select facet or a range facet, depending on the type of the facet in the Browse response.
4
+ *
5
+ * @see SelectFacet
6
+ * @see RangeFacet
7
+ */
8
+ type Facet = Browse['facet_counts'][number];
9
+ /**
10
+ * Select filter facet from the Browse response with type 'select'.
11
+ * It represents a facet that allows users to select from a list of options (e.g., manufacturer, categories).
12
+ *
13
+ * @example
14
+ * const selectFacet: SelectFacet = {
15
+ * type: 'select',
16
+ * field_name: '_product_i18n.manufacturer',
17
+ * field_label: 'Brand',
18
+ * field_unit: '',
19
+ * counts: [
20
+ * {
21
+ * count: 123,
22
+ * value: 'Apple'
23
+ * },
24
+ * {
25
+ * count: 34,
26
+ * value: 'Samsung'
27
+ * }
28
+ * ],
29
+ * stats: {
30
+ * total_values: 373
31
+ * }
32
+ * }
33
+ */
34
+ type SelectFacet = Extract<Facet, {
35
+ type: 'select';
36
+ }>;
37
+ /**
38
+ * Range filter facet from the Browse response with type 'range'.
39
+ * It represents a facet that allows users to filter by a range of values (e.g., price).
40
+ *
41
+ * @example
42
+ * const rangeFacet: RangeFacet = {
43
+ * type: 'range',
44
+ * field_name: '_product.price',
45
+ * field_label: 'Price',
46
+ * field_unit: '',
47
+ * stats: {
48
+ * max: 10,
49
+ * min: 110,
50
+ * }
51
+ * }
52
+ */
53
+ type RangeFacet = Extract<Facet, {
54
+ type: 'range';
55
+ }>;
56
+ /**
57
+ * Filter type that represents the shape of filters used in API requests.
58
+ * It is an object where the keys are strings (representing the filter fields) and the values can be either numbers (for range filters) or arrays of strings (for select filters).
59
+ *
60
+ * @example
61
+ * const filter: Filter = {
62
+ * 'f[_product.price][from]': 10,
63
+ * 'f[_product.price][till]': 100,
64
+ * 'f[_product_i18n.manufacturer][]': ['Apple', 'Samsung'],
65
+ * }
66
+ */
67
+ interface Filter {
68
+ [key: string]: number | string[];
69
+ }
70
+ // OpenAPI paths and components to be augmented by the generated types
2
71
  interface paths {}
3
72
  interface components {}
73
+ /**
74
+ * Suggest query response type, representing the shape of the response returned by the API when performing a suggest query.
75
+ *
76
+ * @see https://www.postman.com/batteryincluded/core/request/ewmh1cc/suggest
77
+ */
4
78
  type Suggest = components['schemas']['GetApiV1CollectionsDocumentsSuggest'];
79
+ /**
80
+ * Browse query response type, representing the shape of the response returned by the API when performing a browse query.
81
+ *
82
+ * @see https://www.postman.com/batteryincluded/core/request/ywu49zw/browse
83
+ */
5
84
  type Browse = components['schemas']['GetApiV1CollectionsDocumentsBrowse'];
85
+ /**
86
+ * Highlights query response type, representing the shape of the response returned by the API when performing a highlights query.
87
+ *
88
+ * @see https://www.postman.com/batteryincluded/core/request/qdv63bc/highlights
89
+ */
6
90
  type Highlights = components['schemas']['GetApiV1CollectionsDocumentsHighlights'];
91
+ /**
92
+ * Recommendations query response type, representing the shape of the response returned by the API when performing a recommendations query.
93
+ *
94
+ * @see https://www.postman.com/batteryincluded/core/request/21t4zy8/recommendations
95
+ */
7
96
  type Recommendations = components['schemas']['GetApiV1CollectionsDocumentsRecommendations'];
8
- type SelectFacet = Extract<Browse['facet_counts'][number], {
9
- type: 'select';
10
- }>;
11
- type RangeFacet = Extract<Browse['facet_counts'][number], {
12
- type: 'range';
13
- }>;
14
- interface Filter {
15
- field: string;
16
- values: string[] | {
17
- min?: string;
18
- max?: string;
19
- };
97
+ /**
98
+ * Similar search query response type, representing the shape of the response returned by the API when performing a similar search query.
99
+ *
100
+ * @see https://www.postman.com/batteryincluded/core/request/mjujfc7/similar-search
101
+ */
102
+ type SimilarSearch = components['schemas']['GetApiV1CollectionsDocumentsSimilarSearch'];
103
+ /**
104
+ * Presets query response type, representing the shape of the response returned by the API when performing a presets query.
105
+ *
106
+ * @see https://www.postman.com/batteryincluded/core/request/dkv351x/presets
107
+ */
108
+ type Presets = components['schemas']['GetApiV1CollectionsDocumentsPresets'];
109
+ /**
110
+ * Configuration interface for the BatteryIncluded client.
111
+ */
112
+ interface BatteryIncludedClientConfig {
113
+ collection: string;
114
+ apiKey: string;
20
115
  }
116
+ /**
117
+ * Builds the base URL for the API endpoint based on the provided collection name.
118
+ *
119
+ * @param collection Name of the collection.
120
+ *
121
+ * @returns The base URL for the API endpoint.
122
+ */
21
123
  declare const buildBaseUrl: (collection: string) => string;
124
+ /**
125
+ * Builds the headers for the API request.
126
+ *
127
+ * @param apiKey API key for authentication.
128
+ *
129
+ * @returns An object containing the headers for the API request.
130
+ */
22
131
  declare const buildHeaders: (apiKey: string) => {
23
132
  'X-BI-API-KEY': string;
24
133
  };
25
- declare function createClient<customPaths extends object = paths>(config: {
26
- collection: string;
27
- apiKey: string;
28
- }): import("openapi-fetch").Client<customPaths, `${string}/${string}`>;
134
+ /**
135
+ * Creates an OpenAPI client for interacting with the BatteryIncluded API.
136
+ *
137
+ * @param config Configuration object containing the collection name and API key.
138
+ *
139
+ * @returns A typed OpenAPI client instance for making API requests.
140
+ */
141
+ declare function createClient<customPaths extends object = paths>(config: BatteryIncludedClientConfig): import("openapi-fetch").Client<customPaths, `${string}/${string}`>;
142
+ /**
143
+ * Defines the code generation configuration for the project.
144
+ *
145
+ * @param config A record mapping string keys to either a single ProbeConfig or an array of ProbeConfig objects.
146
+ *
147
+ * @returns The BatteryIncluded code generation configuration object.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * import { defineCodegenConfig } from 'batteryincluded'
152
+ *
153
+ * export default defineCodegenConfig({
154
+ * '/browse': {
155
+ * query: {
156
+ * page: 1,
157
+ * per_page: 20
158
+ * }
159
+ * },
160
+ * '/suggest': {
161
+ * query: {
162
+ * q: 'custom search term'
163
+ * }
164
+ * }
165
+ * })
166
+ * ```
167
+ */
29
168
  declare function defineCodegenConfig(config: Record<string, ProbeConfig | ProbeConfig[]>): Record<string, ProbeConfig | ProbeConfig[]>;
30
- declare function queryToFilters(query: URLSearchParams, labelMap?: Record<string, string>): Filter[];
31
- declare function filtersToQuery(filters: Filter[], labelMap?: Record<string, string>): URLSearchParams;
32
- export { type Browse, type Filter, type Highlights, type RangeFacet, type Recommendations, type SelectFacet, type Suggest, buildBaseUrl, buildHeaders, type components, createClient, defineCodegenConfig, filtersToQuery, type paths, queryToFilters };
169
+ /**
170
+ * Transforms a given filter object into URLSearchParams format.
171
+ *
172
+ * @param filter BatteryIncluded filter object.
173
+ *
174
+ * @returns URLSearchParams object containing the filter parameters.
175
+ */
176
+ declare function filterToSearchParams(filter: Filter): URLSearchParams;
177
+ /**
178
+ * Transforms given URLSearchParams into a filter object.
179
+ *
180
+ * @param searchParams URLSearchParams object containing the filter parameters.
181
+ *
182
+ * @returns BatteryIncluded filter object.
183
+ */
184
+ declare function searchParamsToFilter(searchParams: URLSearchParams): Filter;
185
+ export { BatteryIncludedClientConfig, type Browse, type Facet, type Filter, type Highlights, type Presets, type RangeFacet, type Recommendations, type SelectFacet, type SimilarSearch, type Suggest, buildBaseUrl, buildHeaders, type components, createClient, defineCodegenConfig, filterToSearchParams, type paths, searchParamsToFilter };
package/dist/index.mjs CHANGED
@@ -2,38 +2,21 @@ import { buildBaseUrl, buildHeaders, createClient } from "./_chunks/client.mjs";
2
2
  function defineCodegenConfig(config) {
3
3
  return config;
4
4
  }
5
- function fieldToLabel(field, labelMap) {
6
- return labelMap[field] ?? field;
7
- }
8
- function labelToField(label, labelMap) {
9
- const entry = Object.entries(labelMap).find(([, value]) => value === label);
10
- return entry ? entry[0] : label;
11
- }
12
- function queryToFilters(query, labelMap = {}) {
13
- const filters = [];
14
- try {
15
- const filtersJson = query.get("filters");
16
- if (filtersJson) {
17
- const filtersObj = JSON.parse(filtersJson);
18
- Object.entries(filtersObj).forEach(([field, values]) => {
19
- filters.push({
20
- field: fieldToLabel(field, labelMap),
21
- values
22
- });
23
- });
24
- }
25
- } catch (error) {
26
- console.error("Failed to parse filters from query:", error);
5
+ function filterToSearchParams(filter) {
6
+ const searchParams = new URLSearchParams();
7
+ for (const key in filter) {
8
+ const value = filter[key];
9
+ if (Array.isArray(value)) value.forEach((v) => searchParams.append(key, v));
10
+ else if (value) searchParams.append(key, value.toString());
27
11
  }
28
- return filters;
12
+ return searchParams;
29
13
  }
30
- function filtersToQuery(filters, labelMap = {}) {
31
- const query = new URLSearchParams();
32
- const filtersObj = {};
33
- filters.forEach(({ field, values }) => {
34
- filtersObj[labelToField(field, labelMap)] = values;
35
- });
36
- if (Object.keys(filtersObj).length > 0) query.set("filters", JSON.stringify(filtersObj));
37
- return query;
14
+ function searchParamsToFilter(searchParams) {
15
+ const filter = {};
16
+ for (const [key, value] of searchParams.entries()) if (key.endsWith("[]")) {
17
+ if (!filter[key]) filter[key] = [];
18
+ filter[key].push(value);
19
+ } else filter[key] = Number(value);
20
+ return filter;
38
21
  }
39
- export { buildBaseUrl, buildHeaders, createClient, defineCodegenConfig, filtersToQuery, queryToFilters };
22
+ export { buildBaseUrl, buildHeaders, createClient, defineCodegenConfig, filterToSearchParams, searchParamsToFilter };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "batteryincluded",
3
3
  "type": "module",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "description": "A TypeScript client for the BatteryIncluded API",
6
6
  "author": "Frederik Bußmann <frederik@bussmann.io>",
7
7
  "license": "MIT",
8
- "repository": "freb97/batteryincluded-ts",
8
+ "repository": "bussmann-io/batteryincluded-ts",
9
+ "keywords": ["batteryincluded", "api", "sdk", "typescript", "e-commerce", "ai", "search"],
9
10
  "exports": {
10
11
  ".": "./dist/index.mjs"
11
12
  },
@@ -21,22 +22,24 @@
21
22
  "lint": "eslint .",
22
23
  "lint:fix": "eslint . --fix",
23
24
  "prepack": "bun run build",
24
- "release": "bun test && npm publish && git push --follow-tags",
25
- "typecheck": "tsc --noEmit"
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "vitest run"
26
27
  },
27
28
  "dependencies": {
28
29
  "autodisco": "^2.0.5",
29
- "c12": "^4.0.0-beta.5",
30
+ "c12": "^3.3.4",
30
31
  "citty": "^0.2.2",
31
32
  "defu": "^6.1.7",
32
33
  "dotenv": "^17.4.2",
33
34
  "openapi-fetch": "^0.17.0"
34
35
  },
35
36
  "devDependencies": {
36
- "@antfu/eslint-config": "^9.0.0",
37
- "@types/node": "^24",
38
- "eslint": "^10.4.1",
39
- "obuild": "^0.4.34",
40
- "typescript": "^6.0.3"
37
+ "@antfu/eslint-config": "^9.1.0",
38
+ "@types/node": "^24.12.4",
39
+ "eslint": "^10.6.0",
40
+ "msw": "^2.14.6",
41
+ "obuild": "^0.4.37",
42
+ "typescript": "^6.0.3",
43
+ "vitest": "^4.1.9"
41
44
  }
42
45
  }