mindee 5.0.1 → 5.1.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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
- # CHANGELOG
1
+ # Mindee Node.js API Library Changelog
2
+
3
+
4
+ ## v5.1.0 - 2026-03-02
5
+ ### Changes
6
+ * :sparkles: add to job information
7
+ ### Fixes
8
+ * :bug: fix for printing crop results
9
+ * :bug: proper init of webhook payload
10
+
11
+
12
+ ## v5.0.2 - 2026-02-27
13
+ ### Changes
14
+ * :bug: always use the provided result URL
15
+
2
16
 
3
17
  ## v5.0.1 - 2026-02-24
4
18
  ### Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mindee",
3
- "version": "5.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "Mindee Client Library for Node.js",
5
5
  "author": {
6
6
  "name": "Mindee",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/mocha": "^10.0.10",
64
- "@types/node": "^20.19.33",
64
+ "@types/node": "^20.19.35",
65
65
  "@types/tmp": "^0.2.6",
66
66
  "@typescript-eslint/eslint-plugin": "^8.56.1",
67
67
  "@typescript-eslint/parser": "^8.56.1",
@@ -37,6 +37,7 @@ export class Polygon extends Array {
37
37
  return isPointInY(point, yCoords.min, yCoords.max);
38
38
  }
39
39
  toString() {
40
- return this.map((point) => `(${point})`).join(", ");
40
+ const points = this.map((point) => `(${point})`).join(", ");
41
+ return `(${points})`;
41
42
  }
42
43
  }
@@ -2,8 +2,8 @@ import { Dispatcher, FormData } from "undici";
2
2
  import { InputSource, PageOptions } from "../input/index.js";
3
3
  export declare const TIMEOUT_SECS_DEFAULT: number;
4
4
  export interface RequestOptions {
5
- hostname: string;
6
- path: string;
5
+ hostname?: string;
6
+ path?: string;
7
7
  method: any;
8
8
  timeoutSecs: number;
9
9
  headers: any;
@@ -25,6 +25,7 @@ export declare function cutDocPages(inputDoc: InputSource, pageOptions: PageOpti
25
25
  * Reads a response from the API and processes it.
26
26
  * @param dispatcher custom dispatcher to use for the request.
27
27
  * @param options options related to the request itself.
28
+ * @param url override the URL of the request.
28
29
  * @returns the processed request.
29
30
  */
30
- export declare function sendRequestAndReadResponse(dispatcher: Dispatcher, options: RequestOptions): Promise<BaseHttpResponse>;
31
+ export declare function sendRequestAndReadResponse(dispatcher: Dispatcher, options: RequestOptions, url?: string): Promise<BaseHttpResponse>;
@@ -16,11 +16,11 @@ export async function cutDocPages(inputDoc, pageOptions) {
16
16
  * Reads a response from the API and processes it.
17
17
  * @param dispatcher custom dispatcher to use for the request.
18
18
  * @param options options related to the request itself.
19
+ * @param url override the URL of the request.
19
20
  * @returns the processed request.
20
21
  */
21
- export async function sendRequestAndReadResponse(dispatcher, options) {
22
- const url = `https://${options.hostname}${options.path}`;
23
- logger.debug(`${options.method}: ${url}`);
22
+ export async function sendRequestAndReadResponse(dispatcher, options, url) {
23
+ url ?? (url = `https://${options.hostname}${options.path}`);
24
24
  const response = await request(url, {
25
25
  method: options.method,
26
26
  headers: options.headers,
@@ -6,8 +6,6 @@ import { PollingOptions, PollingOptionsConstructor } from "./clientOptions/index
6
6
  import { BaseProduct } from "../v2/product/baseProduct.js";
7
7
  /**
8
8
  * Options for the V2 Mindee Client.
9
- *
10
- * @category ClientV2
11
9
  * @example
12
10
  * const client = new MindeeClientV2({
13
11
  * apiKey: "YOUR_API_KEY",
@@ -25,8 +23,6 @@ export interface ClientOptions {
25
23
  }
26
24
  /**
27
25
  * Mindee Client V2 class that centralizes most basic operations.
28
- *
29
- * @category ClientV2
30
26
  */
31
27
  export declare class Client {
32
28
  /** Mindee V2 API handler. */
@@ -42,7 +38,6 @@ export declare class Client {
42
38
  * @param product the product to retrieve.
43
39
  * @param inferenceId id of the queue to poll.
44
40
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
45
- * @category Asynchronous
46
41
  * @returns a `Promise` containing the inference.
47
42
  */
48
43
  getResult<P extends typeof BaseProduct>(product: P, inferenceId: string): Promise<InstanceType<P["responseClass"]>>;
@@ -52,7 +47,6 @@ export declare class Client {
52
47
  *
53
48
  * @param jobId id of the queue to poll.
54
49
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
55
- * @category Asynchronous
56
50
  * @returns a `Promise` containing a `Job`, which also contains a `Document` if the
57
51
  * parsing is complete.
58
52
  */
@@ -67,7 +61,6 @@ export declare class Client {
67
61
  *
68
62
  * @param pollingOptions options for the polling loop, see {@link PollingOptions}.
69
63
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
70
- * @category Synchronous
71
64
  * @returns a `Promise` containing parsing results.
72
65
  */
73
66
  enqueueAndGetResult<P extends typeof BaseProduct>(product: P, inputSource: InputSource, params: InstanceType<P["parametersClass"]> | ConstructorParameters<P["parametersClass"]>[0], pollingOptions?: PollingOptionsConstructor): Promise<InstanceType<P["responseClass"]>>;
@@ -76,5 +69,5 @@ export declare class Client {
76
69
  * until the maximum number of tries is reached.
77
70
  * @protected
78
71
  */
79
- protected pollForResult<P extends typeof BaseProduct>(product: typeof BaseProduct, pollingOptions: PollingOptions, queueId: string): Promise<InstanceType<P["responseClass"]>>;
72
+ protected pollForResult<P extends typeof BaseProduct>(product: typeof BaseProduct, pollingOptions: PollingOptions, jobId: string): Promise<InstanceType<P["responseClass"]>>;
80
73
  }
package/src/v2/client.js CHANGED
@@ -7,8 +7,6 @@ import { MindeeHttpErrorV2 } from "./http/errors.js";
7
7
  import { PollingOptions } from "./clientOptions/index.js";
8
8
  /**
9
9
  * Mindee Client V2 class that centralizes most basic operations.
10
- *
11
- * @category ClientV2
12
10
  */
13
11
  export class Client {
14
12
  /**
@@ -49,12 +47,11 @@ export class Client {
49
47
  * @param product the product to retrieve.
50
48
  * @param inferenceId id of the queue to poll.
51
49
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
52
- * @category Asynchronous
53
50
  * @returns a `Promise` containing the inference.
54
51
  */
55
52
  async getResult(product, inferenceId) {
56
53
  logger.debug(`Attempting to get inference with ID: ${inferenceId} using response type: ${product.name}`);
57
- return await this.mindeeApi.getProductResult(product, inferenceId);
54
+ return await this.mindeeApi.getProductResultById(product, inferenceId);
58
55
  }
59
56
  /**
60
57
  * Get the processing status of a previously enqueued request.
@@ -62,7 +59,6 @@ export class Client {
62
59
  *
63
60
  * @param jobId id of the queue to poll.
64
61
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
65
- * @category Asynchronous
66
62
  * @returns a `Promise` containing a `Job`, which also contains a `Document` if the
67
63
  * parsing is complete.
68
64
  */
@@ -79,7 +75,6 @@ export class Client {
79
75
  *
80
76
  * @param pollingOptions options for the polling loop, see {@link PollingOptions}.
81
77
  * @typeParam T an extension of an `Inference`. Can be omitted as it will be inferred from the `productClass`.
82
- * @category Synchronous
83
78
  * @returns a `Promise` containing parsing results.
84
79
  */
85
80
  async enqueueAndGetResult(product, inputSource, params, pollingOptions) {
@@ -93,15 +88,15 @@ export class Client {
93
88
  * until the maximum number of tries is reached.
94
89
  * @protected
95
90
  */
96
- async pollForResult(product, pollingOptions, queueId) {
91
+ async pollForResult(product, pollingOptions, jobId) {
97
92
  logger.debug(`Waiting ${pollingOptions.initialDelaySec} seconds before polling.`);
98
93
  await setTimeout(pollingOptions.initialDelaySec * 1000, undefined, pollingOptions.initialTimerOptions);
99
- logger.debug(`Start polling for inference using job ID: ${queueId}.`);
94
+ logger.debug(`Start polling for inference using job ID: ${jobId}.`);
100
95
  let retryCounter = 1;
101
96
  let pollResults;
102
97
  while (retryCounter < pollingOptions.maxRetries + 1) {
103
98
  logger.debug(`Attempt ${retryCounter} of ${pollingOptions.maxRetries}`);
104
- pollResults = await this.getJob(queueId);
99
+ pollResults = await this.getJob(jobId);
105
100
  const error = pollResults.job.error;
106
101
  if (error) {
107
102
  throw new MindeeHttpErrorV2(error);
@@ -111,7 +106,10 @@ export class Client {
111
106
  break;
112
107
  }
113
108
  if (pollResults.job.status === "Processed") {
114
- return this.getResult(product, pollResults.job.id);
109
+ if (!pollResults.job.resultUrl) {
110
+ throw new MindeeError("The result URL is undefined. This is a server error, try again later or contact support.");
111
+ }
112
+ return this.mindeeApi.getProductResultByUrl(product, pollResults.job.resultUrl);
115
113
  }
116
114
  await setTimeout(pollingOptions.delaySec * 1000, undefined, pollingOptions.recurringTimerOptions);
117
115
  retryCounter++;
@@ -1,4 +1,7 @@
1
1
  import { BaseSettings, MindeeApiConstructorProps } from "../../http/baseSettings.js";
2
+ /**
3
+ * Settings for the V2 API.
4
+ */
2
5
  export declare class ApiSettings extends BaseSettings {
3
6
  baseHeaders: Record<string, string>;
4
7
  constructor({ apiKey, dispatcher, }: MindeeApiConstructorProps);
@@ -4,6 +4,9 @@ import { MindeeConfigurationError } from "../../errors/index.js";
4
4
  const API_V2_KEY_ENVVAR_NAME = "MINDEE_V2_API_KEY";
5
5
  const API_V2_HOST_ENVVAR_NAME = "MINDEE_V2_API_HOST";
6
6
  const DEFAULT_MINDEE_API_HOST = "api-v2.mindee.net";
7
+ /**
8
+ * Settings for the V2 API.
9
+ */
7
10
  export class ApiSettings extends BaseSettings {
8
11
  constructor({ apiKey, dispatcher, }) {
9
12
  super(apiKey, dispatcher);
@@ -4,35 +4,43 @@ import { BaseParameters } from "../../v2/index.js";
4
4
  import { JobResponse } from "../../v2/parsing/index.js";
5
5
  import { InputSource } from "../../input/index.js";
6
6
  import { BaseProduct } from "../../v2/product/baseProduct.js";
7
+ /**
8
+ * Mindee V2 API handler.
9
+ */
7
10
  export declare class MindeeApiV2 {
8
11
  #private;
9
12
  settings: ApiSettings;
10
13
  constructor(dispatcher?: Dispatcher, apiKey?: string);
11
14
  /**
12
- * Sends a file to the extraction inference queue.
15
+ * Sends a file to the product inference queue.
13
16
  * @param product product to enqueue.
14
17
  * @param inputSource Local file loaded as an input.
15
18
  * @param params {ExtractionParameters} parameters relating to the enqueueing options.
16
- * @category V2
17
- * @throws Error if the server's response contains one.
19
+ * @throws Error if the server's response contains an error.
18
20
  * @returns a `Promise` containing a job response.
19
21
  */
20
22
  enqueueProduct(product: typeof BaseProduct, inputSource: InputSource, params: BaseParameters): Promise<JobResponse>;
21
23
  /**
22
- * Requests the results of a queued document from the API.
23
- * Throws an error if the server's response contains one.
24
- * @param jobId The document's ID in the queue.
25
- * @category Asynchronous
26
- * @returns a `Promise` containing information on the queue.
24
+ * Get the specified Job.
25
+ * Throws an error if the server's response contains an error.
26
+ * @param jobId The Job ID as returned by the enqueue request.
27
+ * @returns a `Promise` containing the job response.
27
28
  */
28
29
  getJob(jobId: string): Promise<JobResponse>;
29
30
  /**
30
- * Requests the job of a queued document from the API.
31
- * Throws an error if the server's response contains one.
31
+ * Get the result of a queued document from the API.
32
+ * Throws an error if the server's response contains an error.
32
33
  * @param product
33
- * @param inferenceId The document's ID in the queue.
34
- * @category Asynchronous
35
- * @returns a `Promise` containing either the parsed result, or information on the queue.
34
+ * @param inferenceId The inference ID for the result.
35
+ * @returns a `Promise` containing the parsed result.
36
36
  */
37
- getProductResult<P extends typeof BaseProduct>(product: P, inferenceId: string): Promise<InstanceType<P["responseClass"]>>;
37
+ getProductResultById<P extends typeof BaseProduct>(product: P, inferenceId: string): Promise<InstanceType<P["responseClass"]>>;
38
+ /**
39
+ * Get the result of a queued document from the API.
40
+ * Throws an error if the server's response contains an error.
41
+ * @param product
42
+ * @param url The URL as returned by a Job's resultUrl property.
43
+ * @returns a `Promise` containing the parsed result.
44
+ */
45
+ getProductResultByUrl<P extends typeof BaseProduct>(product: P, url: string): Promise<InstanceType<P["responseClass"]>>;
38
46
  }
@@ -8,21 +8,23 @@ import { ApiSettings } from "./apiSettings.js";
8
8
  import { ErrorResponse, JobResponse, } from "../../v2/parsing/index.js";
9
9
  import { sendRequestAndReadResponse } from "../../http/apiCore.js";
10
10
  import { LocalInputSource } from "../../input/index.js";
11
- import { MindeeDeserializationError } from "../../errors/index.js";
11
+ import { MindeeDeserializationError, MindeeError } from "../../errors/index.js";
12
12
  import { MindeeHttpErrorV2 } from "./errors.js";
13
13
  import { logger } from "../../logger.js";
14
+ /**
15
+ * Mindee V2 API handler.
16
+ */
14
17
  export class MindeeApiV2 {
15
18
  constructor(dispatcher, apiKey) {
16
19
  _MindeeApiV2_instances.add(this);
17
20
  this.settings = new ApiSettings({ dispatcher: dispatcher, apiKey: apiKey });
18
21
  }
19
22
  /**
20
- * Sends a file to the extraction inference queue.
23
+ * Sends a file to the product inference queue.
21
24
  * @param product product to enqueue.
22
25
  * @param inputSource Local file loaded as an input.
23
26
  * @param params {ExtractionParameters} parameters relating to the enqueueing options.
24
- * @category V2
25
- * @throws Error if the server's response contains one.
27
+ * @throws Error if the server's response contains an error.
26
28
  * @returns a `Promise` containing a job response.
27
29
  */
28
30
  async enqueueProduct(product, inputSource, params) {
@@ -34,26 +36,35 @@ export class MindeeApiV2 {
34
36
  return __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_processResponse).call(this, result, JobResponse);
35
37
  }
36
38
  /**
37
- * Requests the results of a queued document from the API.
38
- * Throws an error if the server's response contains one.
39
- * @param jobId The document's ID in the queue.
40
- * @category Asynchronous
41
- * @returns a `Promise` containing information on the queue.
39
+ * Get the specified Job.
40
+ * Throws an error if the server's response contains an error.
41
+ * @param jobId The Job ID as returned by the enqueue request.
42
+ * @returns a `Promise` containing the job response.
42
43
  */
43
44
  async getJob(jobId) {
44
45
  const response = await __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_reqGetJob).call(this, jobId);
45
46
  return __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_processResponse).call(this, response, JobResponse);
46
47
  }
47
48
  /**
48
- * Requests the job of a queued document from the API.
49
- * Throws an error if the server's response contains one.
49
+ * Get the result of a queued document from the API.
50
+ * Throws an error if the server's response contains an error.
51
+ * @param product
52
+ * @param inferenceId The inference ID for the result.
53
+ * @returns a `Promise` containing the parsed result.
54
+ */
55
+ async getProductResultById(product, inferenceId) {
56
+ const queueResponse = await __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_reqGetProductResult).call(this, `https://${this.settings.hostname}/v2/products/${product.slug}/results/${inferenceId}`);
57
+ return __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_processResponse).call(this, queueResponse, product.responseClass);
58
+ }
59
+ /**
60
+ * Get the result of a queued document from the API.
61
+ * Throws an error if the server's response contains an error.
50
62
  * @param product
51
- * @param inferenceId The document's ID in the queue.
52
- * @category Asynchronous
53
- * @returns a `Promise` containing either the parsed result, or information on the queue.
63
+ * @param url The URL as returned by a Job's resultUrl property.
64
+ * @returns a `Promise` containing the parsed result.
54
65
  */
55
- async getProductResult(product, inferenceId) {
56
- const queueResponse = await __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_reqGetProductResult).call(this, inferenceId, product.slug);
66
+ async getProductResultByUrl(product, url) {
67
+ const queueResponse = await __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_reqGetProductResult).call(this, url);
57
68
  return __classPrivateFieldGet(this, _MindeeApiV2_instances, "m", _MindeeApiV2_processResponse).call(this, queueResponse, product.responseClass);
58
69
  }
59
70
  }
@@ -80,7 +91,6 @@ _MindeeApiV2_instances = new WeakSet(), _MindeeApiV2_processResponse = function
80
91
  }, _MindeeApiV2_reqPostProductEnqueue =
81
92
  /**
82
93
  * Sends a document to the inference queue.
83
- *
84
94
  * @param product Product to enqueue.
85
95
  * @param inputSource Local or remote file as an input.
86
96
  * @param params {ExtractionParameters} parameters relating to the enqueueing options.
@@ -115,18 +125,17 @@ async function _MindeeApiV2_reqPostProductEnqueue(product, inputSource, params)
115
125
  }, _MindeeApiV2_reqGetProductResult =
116
126
  /**
117
127
  * Make a request to GET the status of a document in the queue.
118
- * @param inferenceId ID of the inference.
119
- * @param slug "jobs" or "inferences"...
120
- * @category Asynchronous
121
- * @returns a `Promise` containing either the parsed result, or information on the queue.
128
+ * @param url URL path to the result.
129
+ * @returns a `Promise` containing the parsed result.
122
130
  */
123
- async function _MindeeApiV2_reqGetProductResult(inferenceId, slug) {
131
+ async function _MindeeApiV2_reqGetProductResult(url) {
124
132
  const options = {
125
133
  method: "GET",
126
134
  headers: this.settings.baseHeaders,
127
- hostname: this.settings.hostname,
128
- path: `/v2/products/${slug}/results/${inferenceId}`,
129
135
  timeoutSecs: this.settings.timeoutSecs,
130
136
  };
131
- return await sendRequestAndReadResponse(this.settings.dispatcher, options);
137
+ if (!url.startsWith("https://")) {
138
+ throw new MindeeError(`Invalid URL: ${url}`);
139
+ }
140
+ return await sendRequestAndReadResponse(this.settings.dispatcher, options, url);
132
141
  };
@@ -1,13 +1,13 @@
1
1
  import { Polygon } from "../../../../geometry/index.js";
2
2
  import { StringDict } from "../../../../parsing/stringDict.js";
3
3
  /**
4
- * Location of a field.
4
+ * A field's location on the document.
5
5
  */
6
6
  export declare class FieldLocation {
7
- /** Free polygon made up of points (can be null when not provided). */
8
- readonly polygon: Polygon | null;
9
- /** Page ID. */
10
- readonly page: number | undefined;
7
+ /** Position information as a list of points in clockwise order. */
8
+ readonly polygon: Polygon;
9
+ /** 0-based page index of where the polygon is located. */
10
+ readonly page: any;
11
11
  constructor(serverResponse: StringDict);
12
12
  toString(): string;
13
13
  }
@@ -1,13 +1,13 @@
1
1
  import { Polygon } from "../../../../geometry/index.js";
2
2
  /**
3
- * Location of a field.
3
+ * A field's location on the document.
4
4
  */
5
5
  export class FieldLocation {
6
6
  constructor(serverResponse) {
7
- this.polygon = "polygon" in serverResponse ? new Polygon(...serverResponse["polygon"]) : null;
8
- this.page = "page" in serverResponse ? serverResponse["page"] : undefined;
7
+ this.polygon = new Polygon(...serverResponse["polygon"]);
8
+ this.page = serverResponse["page"];
9
9
  }
10
10
  toString() {
11
- return this.polygon?.toString() ?? "";
11
+ return `${this.polygon} on page ${this.page}`;
12
12
  }
13
13
  }
@@ -14,9 +14,13 @@ export declare class Job {
14
14
  */
15
15
  error?: ErrorResponse;
16
16
  /**
17
- * Timestamp of the job creation.
17
+ * Date and time of the Job creation.
18
18
  */
19
19
  createdAt: Date | null;
20
+ /**
21
+ * Date and time of the Job completion. Filled once processing is finished.
22
+ */
23
+ completedAt: Date | null | undefined;
20
24
  /**
21
25
  * ID of the model.
22
26
  */
@@ -1,5 +1,6 @@
1
1
  import { parseDate } from "../../../parsing/index.js";
2
2
  import { ErrorResponse } from "../../../v2/index.js";
3
+ import { JobWebhook } from "./jobWebhook.js";
3
4
  /**
4
5
  * Job information for a V2 polling attempt.
5
6
  */
@@ -9,17 +10,21 @@ export class Job {
9
10
  if (serverResponse["status"] !== undefined) {
10
11
  this.status = serverResponse["status"];
11
12
  }
12
- if (serverResponse["error"] !== undefined &&
13
- serverResponse["error"] !== null &&
14
- Object.keys(serverResponse["error"]).length > 0) {
13
+ if (serverResponse["error"]) {
15
14
  this.error = new ErrorResponse(serverResponse["error"]);
16
15
  }
17
16
  this.createdAt = parseDate(serverResponse["created_at"]);
17
+ if (!serverResponse["completed_at"]) {
18
+ this.completedAt = undefined;
19
+ }
20
+ else {
21
+ this.completedAt = parseDate(serverResponse["completed_at"]);
22
+ }
18
23
  this.modelId = serverResponse["model_id"];
19
24
  this.pollingUrl = serverResponse["polling_url"];
20
25
  this.filename = serverResponse["filename"];
21
26
  this.resultUrl = serverResponse["result_url"];
22
27
  this.alias = serverResponse["alias"];
23
- this.webhooks = serverResponse["webhooks"];
28
+ this.webhooks = (serverResponse["webhooks"] ?? []).map((webhook) => new JobWebhook(webhook));
24
29
  }
25
30
  }
@@ -8,7 +8,7 @@ export class JobWebhook {
8
8
  this.id = serverResponse["id"];
9
9
  this.createdAt = parseDate(serverResponse["created_at"]);
10
10
  this.status = serverResponse["status"];
11
- if (serverResponse["error"] !== undefined) {
11
+ if (serverResponse["error"]) {
12
12
  this.error = new ErrorResponse(serverResponse["error"]);
13
13
  }
14
14
  }
@@ -5,6 +5,6 @@ export class CropItem {
5
5
  this.location = new FieldLocation(serverResponse["location"]);
6
6
  }
7
7
  toString() {
8
- return `${this.objectType}: ${this.location}`;
8
+ return `* :Location: ${this.location}\n :Object Type: ${this.objectType}`;
9
9
  }
10
10
  }
@@ -8,7 +8,7 @@ export class CropResult {
8
8
  this.crops = serverResponse["crops"].map((cropItem) => new CropItem(cropItem));
9
9
  }
10
10
  toString() {
11
- const crops = this.crops.map(item => item.toString()).join("\n * ");
12
- return `Crop\n====\n * ${crops}`;
11
+ const crops = this.crops.map(item => item.toString()).join("\n");
12
+ return `Crops\n=====\n${crops}`;
13
13
  }
14
14
  }