@machhub-dev/sdk-ts 1.0.16 → 1.0.18

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.
@@ -24,9 +24,7 @@ export declare class Collection {
24
24
  expand?: string | string[];
25
25
  fields?: string | string[];
26
26
  }): Promise<any[]>;
27
- count(options?: {
28
- filter?: any;
29
- }): Promise<number>;
27
+ count(): Promise<number>;
30
28
  getOne(id: string, options?: {
31
29
  expand?: string | string[];
32
30
  }): Promise<any>;
@@ -66,12 +66,9 @@ class Collection {
66
66
  throw new CollectionError('getAll', this.collectionName, error);
67
67
  }
68
68
  }
69
- async count(options) {
69
+ async count() {
70
70
  try {
71
- this.applyOptions(options);
72
- // Build query parameters for filters
73
71
  const response = await this.httpService.request.get(`${this.collectionName}/count`, this.queryParams);
74
- // Extract count from response
75
72
  return response.count;
76
73
  }
77
74
  catch (error) {
@@ -1,6 +1,13 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
2
  import { MQTTService } from "../services/mqtt.service.js";
3
3
  import { HistorizedData } from "../types/tag.models.js";
4
+ interface AggregationOption {
5
+ mean: "mean";
6
+ sum: "sum";
7
+ min: "min";
8
+ max: "max";
9
+ median: "median";
10
+ }
4
11
  export declare class Historian {
5
12
  private httpService;
6
13
  private mqttService;
@@ -10,4 +17,20 @@ export declare class Historian {
10
17
  subscribeLiveData(topic: string, callback: (data: any) => void): Promise<any>;
11
18
  getLastNValues(topic: string, n: number): Promise<HistorizedData[]>;
12
19
  query(SurrealQL: string): Promise<any>;
20
+ /**
21
+ * Export historized data for one or more topics as a gzipped CSV file (Blob).
22
+ * When multiple topics are provided, they are merged into a single CSV with columns: [Timestamp, topic1, topic2, ...].
23
+ * Supports optional time bucketing (sampleRate) and aggregation (mean, sum, min, max, median).
24
+ *
25
+ * @param topics - Array of topic strings to export
26
+ * @param startDate - Start date for the data range
27
+ * @param endDate - End date for the data range
28
+ * @param timezone - Optional Timezone string (e.g. "Asia/Kuala Lumpur")
29
+ * @param sampleRate - Optional bucket interval in underscore format (e.g. "5_second", "1_minute", "1_hour")
30
+ * @param aggregation - Optional aggregation function: "mean" | "sum" | "min" | "max" | "median" | "none"
31
+ * @param mapping - Optional key-value pairs to rename topic columns in the CSV header (e.g. { "Sensor/Temperature": "Temp °C" })
32
+ * @returns A Blob containing the gzipped CSV data
33
+ */
34
+ getHistoricalDataAsCSV(topics: string[], startDate: Date, endDate: Date, timezone?: string, sampleRate?: string, aggregation?: AggregationOption, mapping?: Record<string, string>): Promise<Blob>;
13
35
  }
36
+ export {};
@@ -41,5 +41,30 @@ class Historian {
41
41
  query: SurrealQL
42
42
  }).post("historian/query");
43
43
  }
44
+ /**
45
+ * Export historized data for one or more topics as a gzipped CSV file (Blob).
46
+ * When multiple topics are provided, they are merged into a single CSV with columns: [Timestamp, topic1, topic2, ...].
47
+ * Supports optional time bucketing (sampleRate) and aggregation (mean, sum, min, max, median).
48
+ *
49
+ * @param topics - Array of topic strings to export
50
+ * @param startDate - Start date for the data range
51
+ * @param endDate - End date for the data range
52
+ * @param timezone - Optional Timezone string (e.g. "Asia/Kuala Lumpur")
53
+ * @param sampleRate - Optional bucket interval in underscore format (e.g. "5_second", "1_minute", "1_hour")
54
+ * @param aggregation - Optional aggregation function: "mean" | "sum" | "min" | "max" | "median" | "none"
55
+ * @param mapping - Optional key-value pairs to rename topic columns in the CSV header (e.g. { "Sensor/Temperature": "Temp °C" })
56
+ * @returns A Blob containing the gzipped CSV data
57
+ */
58
+ async getHistoricalDataAsCSV(topics, startDate, endDate, timezone, sampleRate, aggregation, mapping) {
59
+ return this.httpService.request.withJSON({
60
+ topics,
61
+ startDate: startDate.toISOString(),
62
+ endDate: endDate.toISOString(),
63
+ timezone,
64
+ sampleRate: sampleRate ?? "",
65
+ aggregation: aggregation ?? "",
66
+ mapping: mapping ?? {},
67
+ }).postAsBlob("historian/export/aggregated");
68
+ }
44
69
  }
45
70
  exports.Historian = Historian;
@@ -1,4 +1,8 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
+ import { Process, ProcessTrigger } from "../types/processes.models.js";
3
+ import { RecordID } from "../types/recordID.models.js";
4
+ export { Process, ProcessTrigger } from "../types/processes.models.js";
5
+ export type { ProcessLanguage, TriggerType, TriggerConfig, InputType, InputConfig, ProcessInput, OutputType, OutputConfig, ProcessOutput, ProcessKey, ProcessValue } from "../types/processes.models.js";
2
6
  export declare class Processes {
3
7
  private httpService;
4
8
  constructor(httpService: HTTPService);
@@ -9,4 +13,16 @@ export declare class Processes {
9
13
  * @returns The result of the process execution
10
14
  */
11
15
  execute(name: string, input?: Record<string, any>): Promise<any>;
16
+ /**
17
+ * Retrieves all processes for the current domain
18
+ * @returns A list of domain processes
19
+ */
20
+ getProcesses(): Promise<Process[]>;
21
+ /**
22
+ * Updates the triggers for a specific process
23
+ * @param id - The ID of the process to update
24
+ * @param triggers - The list of triggers to set on the process
25
+ * @returns The updated process
26
+ */
27
+ changeTriggers(id: RecordID, triggers: ProcessTrigger[]): Promise<Process>;
12
28
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Processes = void 0;
4
+ const recordID_models_js_1 = require("../types/recordID.models.js");
4
5
  class Processes {
5
6
  constructor(httpService) {
6
7
  this.httpService = httpService;
@@ -18,5 +19,22 @@ class Processes {
18
19
  };
19
20
  return await this.httpService.request.withJSON(payload).post("processes/execute");
20
21
  }
22
+ /**
23
+ * Retrieves all processes for the current domain
24
+ * @returns A list of domain processes
25
+ */
26
+ async getProcesses() {
27
+ return await this.httpService.request.get("processes/domain");
28
+ }
29
+ /**
30
+ * Updates the triggers for a specific process
31
+ * @param id - The ID of the process to update
32
+ * @param triggers - The list of triggers to set on the process
33
+ * @returns The updated process
34
+ */
35
+ async changeTriggers(id, triggers) {
36
+ let stringID = (0, recordID_models_js_1.RecordIDToString)(id);
37
+ return await this.httpService.request.withJSON({ triggers }).put(`processes/triggers/${stringID}`);
38
+ }
21
39
  }
22
40
  exports.Processes = Processes;
@@ -5,3 +5,4 @@ export type { BaseResponse } from './types/response.models.js';
5
5
  export type { RecordID } from './types/recordID.models.js';
6
6
  export { StringToRecordID, RecordIDToString, emptyRecordID } from './types/recordID.models.js';
7
7
  export type { HistorizedData } from './types/tag.models.js';
8
+ export type { Process, ProcessLanguage, ProcessTrigger, TriggerType, TriggerConfig, ProcessInput, InputType, InputConfig, ProcessOutput, OutputType, OutputConfig, ProcessKey, ProcessValue } from './types/processes.models.js';
@@ -145,7 +145,8 @@ class SDK {
145
145
  host += envCfg.pathHosted;
146
146
  }
147
147
  if (!config.httpUrl) {
148
- config.httpUrl = `${secured ? 'https' : 'http'}://${host}`;
148
+ const httpHost = envCfg.hostingMode === 'path' ? `${host}/` : host;
149
+ config.httpUrl = `${secured ? 'https' : 'http'}://${httpHost}`;
149
150
  }
150
151
  if (!config.mqttUrl) {
151
152
  config.mqttUrl = `${secured ? 'wss' : 'ws'}://${host}/mqtt`;
@@ -40,6 +40,7 @@ declare class RequestParameters {
40
40
  withJSON(body: Record<string, unknown>): RequestParameters;
41
41
  get<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
42
42
  post<ReturnType>(path: string, query?: Record<string, string>, body?: FormData | Record<string, string>): Promise<ReturnType>;
43
+ postAsBlob(path: string, query?: Record<string, string>): Promise<Blob>;
43
44
  put<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
44
45
  delete<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
45
46
  patch<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
@@ -40,7 +40,7 @@ class RequestParameters {
40
40
  this.withRuntimeID(); // Ensure withRuntimeID() is called by default
41
41
  }
42
42
  withQuery(path, query) {
43
- const newPath = [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
43
+ const newPath = "/" + [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
44
44
  const newURL = new URL(newPath, this.base);
45
45
  for (const key in query) {
46
46
  newURL.searchParams.append(key, query[key]);
@@ -183,6 +183,14 @@ class RequestParameters {
183
183
  }
184
184
  return response.json();
185
185
  }
186
+ async postAsBlob(path, query) {
187
+ const init = this.parseInit("POST") || {};
188
+ const response = await fetch(this.withQuery(path, query), init);
189
+ if (!response.ok) {
190
+ throw new HTTPException(response.status, response.statusText, await response.text());
191
+ }
192
+ return response.blob();
193
+ }
186
194
  async put(path, query) {
187
195
  const response = await fetch(this.withQuery(path, query), this.parseInit("PUT"));
188
196
  if (!response.ok) {
@@ -0,0 +1,58 @@
1
+ import { RecordID } from "./recordID.models.js";
2
+ export type ProcessLanguage = "python" | "typescript";
3
+ export type TriggerType = "tag_change" | "interval" | "cron" | "http" | "manual";
4
+ export interface TriggerConfig {
5
+ cron_expression?: string;
6
+ interval_value?: number;
7
+ interval_unit?: string;
8
+ tag?: string;
9
+ endpoint?: string;
10
+ }
11
+ export interface ProcessTrigger {
12
+ type: TriggerType;
13
+ config: TriggerConfig;
14
+ }
15
+ export type InputType = "tag" | "sql";
16
+ export interface InputConfig {
17
+ tag?: string;
18
+ query?: string;
19
+ }
20
+ export interface ProcessInput {
21
+ name: string;
22
+ type: InputType;
23
+ config: InputConfig;
24
+ }
25
+ export type OutputType = "sql" | "tag_write";
26
+ export interface OutputConfig {
27
+ query?: string;
28
+ tag?: string;
29
+ field?: string;
30
+ }
31
+ export interface ProcessOutput {
32
+ type: OutputType;
33
+ config: OutputConfig;
34
+ }
35
+ export interface ProcessKey {
36
+ key: string;
37
+ }
38
+ export interface ProcessValue {
39
+ value: string;
40
+ }
41
+ export interface Process {
42
+ id?: RecordID;
43
+ domain_id?: RecordID;
44
+ name: string;
45
+ enabled: boolean;
46
+ log_enabled: boolean;
47
+ language: ProcessLanguage;
48
+ code: string;
49
+ version: number;
50
+ triggers: ProcessTrigger[];
51
+ inputs: ProcessInput[];
52
+ outputs: ProcessOutput[];
53
+ keys?: ProcessKey[];
54
+ values?: ProcessValue[];
55
+ createdBy?: RecordID;
56
+ createdDt?: string;
57
+ updated_dt?: string;
58
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -24,9 +24,7 @@ export declare class Collection {
24
24
  expand?: string | string[];
25
25
  fields?: string | string[];
26
26
  }): Promise<any[]>;
27
- count(options?: {
28
- filter?: any;
29
- }): Promise<number>;
27
+ count(): Promise<number>;
30
28
  getOne(id: string, options?: {
31
29
  expand?: string | string[];
32
30
  }): Promise<any>;
@@ -62,12 +62,9 @@ export class Collection {
62
62
  throw new CollectionError('getAll', this.collectionName, error);
63
63
  }
64
64
  }
65
- async count(options) {
65
+ async count() {
66
66
  try {
67
- this.applyOptions(options);
68
- // Build query parameters for filters
69
67
  const response = await this.httpService.request.get(`${this.collectionName}/count`, this.queryParams);
70
- // Extract count from response
71
68
  return response.count;
72
69
  }
73
70
  catch (error) {
@@ -1,6 +1,13 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
2
  import { MQTTService } from "../services/mqtt.service.js";
3
3
  import { HistorizedData } from "../types/tag.models.js";
4
+ interface AggregationOption {
5
+ mean: "mean";
6
+ sum: "sum";
7
+ min: "min";
8
+ max: "max";
9
+ median: "median";
10
+ }
4
11
  export declare class Historian {
5
12
  private httpService;
6
13
  private mqttService;
@@ -10,4 +17,20 @@ export declare class Historian {
10
17
  subscribeLiveData(topic: string, callback: (data: any) => void): Promise<any>;
11
18
  getLastNValues(topic: string, n: number): Promise<HistorizedData[]>;
12
19
  query(SurrealQL: string): Promise<any>;
20
+ /**
21
+ * Export historized data for one or more topics as a gzipped CSV file (Blob).
22
+ * When multiple topics are provided, they are merged into a single CSV with columns: [Timestamp, topic1, topic2, ...].
23
+ * Supports optional time bucketing (sampleRate) and aggregation (mean, sum, min, max, median).
24
+ *
25
+ * @param topics - Array of topic strings to export
26
+ * @param startDate - Start date for the data range
27
+ * @param endDate - End date for the data range
28
+ * @param timezone - Optional Timezone string (e.g. "Asia/Kuala Lumpur")
29
+ * @param sampleRate - Optional bucket interval in underscore format (e.g. "5_second", "1_minute", "1_hour")
30
+ * @param aggregation - Optional aggregation function: "mean" | "sum" | "min" | "max" | "median" | "none"
31
+ * @param mapping - Optional key-value pairs to rename topic columns in the CSV header (e.g. { "Sensor/Temperature": "Temp °C" })
32
+ * @returns A Blob containing the gzipped CSV data
33
+ */
34
+ getHistoricalDataAsCSV(topics: string[], startDate: Date, endDate: Date, timezone?: string, sampleRate?: string, aggregation?: AggregationOption, mapping?: Record<string, string>): Promise<Blob>;
13
35
  }
36
+ export {};
@@ -38,4 +38,29 @@ export class Historian {
38
38
  query: SurrealQL
39
39
  }).post("historian/query");
40
40
  }
41
+ /**
42
+ * Export historized data for one or more topics as a gzipped CSV file (Blob).
43
+ * When multiple topics are provided, they are merged into a single CSV with columns: [Timestamp, topic1, topic2, ...].
44
+ * Supports optional time bucketing (sampleRate) and aggregation (mean, sum, min, max, median).
45
+ *
46
+ * @param topics - Array of topic strings to export
47
+ * @param startDate - Start date for the data range
48
+ * @param endDate - End date for the data range
49
+ * @param timezone - Optional Timezone string (e.g. "Asia/Kuala Lumpur")
50
+ * @param sampleRate - Optional bucket interval in underscore format (e.g. "5_second", "1_minute", "1_hour")
51
+ * @param aggregation - Optional aggregation function: "mean" | "sum" | "min" | "max" | "median" | "none"
52
+ * @param mapping - Optional key-value pairs to rename topic columns in the CSV header (e.g. { "Sensor/Temperature": "Temp °C" })
53
+ * @returns A Blob containing the gzipped CSV data
54
+ */
55
+ async getHistoricalDataAsCSV(topics, startDate, endDate, timezone, sampleRate, aggregation, mapping) {
56
+ return this.httpService.request.withJSON({
57
+ topics,
58
+ startDate: startDate.toISOString(),
59
+ endDate: endDate.toISOString(),
60
+ timezone,
61
+ sampleRate: sampleRate ?? "",
62
+ aggregation: aggregation ?? "",
63
+ mapping: mapping ?? {},
64
+ }).postAsBlob("historian/export/aggregated");
65
+ }
41
66
  }
@@ -1,4 +1,8 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
+ import { Process, ProcessTrigger } from "../types/processes.models.js";
3
+ import { RecordID } from "../types/recordID.models.js";
4
+ export { Process, ProcessTrigger } from "../types/processes.models.js";
5
+ export type { ProcessLanguage, TriggerType, TriggerConfig, InputType, InputConfig, ProcessInput, OutputType, OutputConfig, ProcessOutput, ProcessKey, ProcessValue } from "../types/processes.models.js";
2
6
  export declare class Processes {
3
7
  private httpService;
4
8
  constructor(httpService: HTTPService);
@@ -9,4 +13,16 @@ export declare class Processes {
9
13
  * @returns The result of the process execution
10
14
  */
11
15
  execute(name: string, input?: Record<string, any>): Promise<any>;
16
+ /**
17
+ * Retrieves all processes for the current domain
18
+ * @returns A list of domain processes
19
+ */
20
+ getProcesses(): Promise<Process[]>;
21
+ /**
22
+ * Updates the triggers for a specific process
23
+ * @param id - The ID of the process to update
24
+ * @param triggers - The list of triggers to set on the process
25
+ * @returns The updated process
26
+ */
27
+ changeTriggers(id: RecordID, triggers: ProcessTrigger[]): Promise<Process>;
12
28
  }
@@ -1,3 +1,4 @@
1
+ import { RecordIDToString } from "../types/recordID.models.js";
1
2
  export class Processes {
2
3
  constructor(httpService) {
3
4
  this.httpService = httpService;
@@ -15,4 +16,21 @@ export class Processes {
15
16
  };
16
17
  return await this.httpService.request.withJSON(payload).post("processes/execute");
17
18
  }
19
+ /**
20
+ * Retrieves all processes for the current domain
21
+ * @returns A list of domain processes
22
+ */
23
+ async getProcesses() {
24
+ return await this.httpService.request.get("processes/domain");
25
+ }
26
+ /**
27
+ * Updates the triggers for a specific process
28
+ * @param id - The ID of the process to update
29
+ * @param triggers - The list of triggers to set on the process
30
+ * @returns The updated process
31
+ */
32
+ async changeTriggers(id, triggers) {
33
+ let stringID = RecordIDToString(id);
34
+ return await this.httpService.request.withJSON({ triggers }).put(`processes/triggers/${stringID}`);
35
+ }
18
36
  }
package/dist/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export type { BaseResponse } from './types/response.models.js';
5
5
  export type { RecordID } from './types/recordID.models.js';
6
6
  export { StringToRecordID, RecordIDToString, emptyRecordID } from './types/recordID.models.js';
7
7
  export type { HistorizedData } from './types/tag.models.js';
8
+ export type { Process, ProcessLanguage, ProcessTrigger, TriggerType, TriggerConfig, ProcessInput, InputType, InputConfig, ProcessOutput, OutputType, OutputConfig, ProcessKey, ProcessValue } from './types/processes.models.js';
package/dist/sdk-ts.js CHANGED
@@ -142,7 +142,8 @@ export class SDK {
142
142
  host += envCfg.pathHosted;
143
143
  }
144
144
  if (!config.httpUrl) {
145
- config.httpUrl = `${secured ? 'https' : 'http'}://${host}`;
145
+ const httpHost = envCfg.hostingMode === 'path' ? `${host}/` : host;
146
+ config.httpUrl = `${secured ? 'https' : 'http'}://${httpHost}`;
146
147
  }
147
148
  if (!config.mqttUrl) {
148
149
  config.mqttUrl = `${secured ? 'wss' : 'ws'}://${host}/mqtt`;
@@ -40,6 +40,7 @@ declare class RequestParameters {
40
40
  withJSON(body: Record<string, unknown>): RequestParameters;
41
41
  get<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
42
42
  post<ReturnType>(path: string, query?: Record<string, string>, body?: FormData | Record<string, string>): Promise<ReturnType>;
43
+ postAsBlob(path: string, query?: Record<string, string>): Promise<Blob>;
43
44
  put<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
44
45
  delete<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
45
46
  patch<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType>;
@@ -35,7 +35,7 @@ class RequestParameters {
35
35
  this.withRuntimeID(); // Ensure withRuntimeID() is called by default
36
36
  }
37
37
  withQuery(path, query) {
38
- const newPath = [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
38
+ const newPath = "/" + [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
39
39
  const newURL = new URL(newPath, this.base);
40
40
  for (const key in query) {
41
41
  newURL.searchParams.append(key, query[key]);
@@ -178,6 +178,14 @@ class RequestParameters {
178
178
  }
179
179
  return response.json();
180
180
  }
181
+ async postAsBlob(path, query) {
182
+ const init = this.parseInit("POST") || {};
183
+ const response = await fetch(this.withQuery(path, query), init);
184
+ if (!response.ok) {
185
+ throw new HTTPException(response.status, response.statusText, await response.text());
186
+ }
187
+ return response.blob();
188
+ }
181
189
  async put(path, query) {
182
190
  const response = await fetch(this.withQuery(path, query), this.parseInit("PUT"));
183
191
  if (!response.ok) {
@@ -0,0 +1,58 @@
1
+ import { RecordID } from "./recordID.models.js";
2
+ export type ProcessLanguage = "python" | "typescript";
3
+ export type TriggerType = "tag_change" | "interval" | "cron" | "http" | "manual";
4
+ export interface TriggerConfig {
5
+ cron_expression?: string;
6
+ interval_value?: number;
7
+ interval_unit?: string;
8
+ tag?: string;
9
+ endpoint?: string;
10
+ }
11
+ export interface ProcessTrigger {
12
+ type: TriggerType;
13
+ config: TriggerConfig;
14
+ }
15
+ export type InputType = "tag" | "sql";
16
+ export interface InputConfig {
17
+ tag?: string;
18
+ query?: string;
19
+ }
20
+ export interface ProcessInput {
21
+ name: string;
22
+ type: InputType;
23
+ config: InputConfig;
24
+ }
25
+ export type OutputType = "sql" | "tag_write";
26
+ export interface OutputConfig {
27
+ query?: string;
28
+ tag?: string;
29
+ field?: string;
30
+ }
31
+ export interface ProcessOutput {
32
+ type: OutputType;
33
+ config: OutputConfig;
34
+ }
35
+ export interface ProcessKey {
36
+ key: string;
37
+ }
38
+ export interface ProcessValue {
39
+ value: string;
40
+ }
41
+ export interface Process {
42
+ id?: RecordID;
43
+ domain_id?: RecordID;
44
+ name: string;
45
+ enabled: boolean;
46
+ log_enabled: boolean;
47
+ language: ProcessLanguage;
48
+ code: string;
49
+ version: number;
50
+ triggers: ProcessTrigger[];
51
+ inputs: ProcessInput[];
52
+ outputs: ProcessOutput[];
53
+ keys?: ProcessKey[];
54
+ values?: ProcessValue[];
55
+ createdBy?: RecordID;
56
+ createdDt?: string;
57
+ updated_dt?: string;
58
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@machhub-dev/sdk-ts",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "MACHHUB TYPESCRIPT SDK",
5
5
  "keywords": [
6
6
  "machhub",
@@ -84,14 +84,9 @@ export class Collection {
84
84
  }
85
85
  }
86
86
 
87
- async count(options?: { filter?: any }): Promise<number> {
87
+ async count(): Promise<number> {
88
88
  try {
89
- this.applyOptions(options);
90
-
91
- // Build query parameters for filters
92
89
  const response: { count: number } = await this.httpService.request.get(`${this.collectionName}/count`, this.queryParams);
93
-
94
- // Extract count from response
95
90
  return response.count;
96
91
  } catch (error) {
97
92
  throw new CollectionError('count', this.collectionName, error as Error);
@@ -2,6 +2,15 @@ import { HTTPService } from "../services/http.service.js";
2
2
  import { MQTTService } from "../services/mqtt.service.js";
3
3
  import { HistorizedData } from "../types/tag.models.js";
4
4
 
5
+ interface AggregationOption {
6
+ mean: "mean",
7
+ sum: "sum",
8
+ min: "min",
9
+ max: "max",
10
+ median: "median",
11
+ }
12
+
13
+
5
14
  export class Historian {
6
15
  private httpService: HTTPService;
7
16
  private mqttService: MQTTService | null;
@@ -36,7 +45,7 @@ export class Historian {
36
45
  throw new Error("The number of values to fetch must be greater than 0.");
37
46
  }
38
47
 
39
- if (n > 100){
48
+ if (n > 100) {
40
49
  throw new Error("The number of values to fetch must be less than 100.");
41
50
  }
42
51
 
@@ -47,9 +56,43 @@ export class Historian {
47
56
  }).patch("historian/last");
48
57
  }
49
58
 
50
- async query(SurrealQL:string): Promise<any> {
59
+ async query(SurrealQL: string): Promise<any> {
51
60
  return this.httpService.request.withJSON({
52
61
  query: SurrealQL
53
62
  }).post("historian/query");
54
63
  }
64
+
65
+ /**
66
+ * Export historized data for one or more topics as a gzipped CSV file (Blob).
67
+ * When multiple topics are provided, they are merged into a single CSV with columns: [Timestamp, topic1, topic2, ...].
68
+ * Supports optional time bucketing (sampleRate) and aggregation (mean, sum, min, max, median).
69
+ *
70
+ * @param topics - Array of topic strings to export
71
+ * @param startDate - Start date for the data range
72
+ * @param endDate - End date for the data range
73
+ * @param timezone - Optional Timezone string (e.g. "Asia/Kuala Lumpur")
74
+ * @param sampleRate - Optional bucket interval in underscore format (e.g. "5_second", "1_minute", "1_hour")
75
+ * @param aggregation - Optional aggregation function: "mean" | "sum" | "min" | "max" | "median" | "none"
76
+ * @param mapping - Optional key-value pairs to rename topic columns in the CSV header (e.g. { "Sensor/Temperature": "Temp °C" })
77
+ * @returns A Blob containing the gzipped CSV data
78
+ */
79
+ async getHistoricalDataAsCSV(
80
+ topics: string[],
81
+ startDate: Date,
82
+ endDate: Date,
83
+ timezone?: string,
84
+ sampleRate?: string,
85
+ aggregation?: AggregationOption,
86
+ mapping?: Record<string, string>,
87
+ ): Promise<Blob> {
88
+ return this.httpService.request.withJSON({
89
+ topics,
90
+ startDate: startDate.toISOString(),
91
+ endDate: endDate.toISOString(),
92
+ timezone,
93
+ sampleRate: sampleRate ?? "",
94
+ aggregation: aggregation ?? "",
95
+ mapping: mapping ?? {},
96
+ }).postAsBlob("historian/export/aggregated");
97
+ }
55
98
  }
@@ -1,4 +1,9 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
+ import { Process, ProcessTrigger } from "../types/processes.models.js";
3
+ import { RecordID, RecordIDToString } from "../types/recordID.models.js";
4
+
5
+ export { Process, ProcessTrigger } from "../types/processes.models.js";
6
+ export type { ProcessLanguage, TriggerType, TriggerConfig, InputType, InputConfig, ProcessInput, OutputType, OutputConfig, ProcessOutput, ProcessKey, ProcessValue } from "../types/processes.models.js";
2
7
 
3
8
  export class Processes {
4
9
  private httpService: HTTPService;
@@ -20,4 +25,24 @@ export class Processes {
20
25
  };
21
26
  return await this.httpService.request.withJSON(payload).post("processes/execute");
22
27
  }
28
+
29
+ /**
30
+ * Retrieves all processes for the current domain
31
+ * @returns A list of domain processes
32
+ */
33
+ public async getProcesses(): Promise<Process[]> {
34
+ return await this.httpService.request.get("processes/domain");
35
+ }
36
+
37
+ /**
38
+ * Updates the triggers for a specific process
39
+ * @param id - The ID of the process to update
40
+ * @param triggers - The list of triggers to set on the process
41
+ * @returns The updated process
42
+ */
43
+ public async changeTriggers(id: RecordID, triggers: ProcessTrigger[]): Promise<Process> {
44
+ let stringID = RecordIDToString(id);
45
+ return await this.httpService.request.withJSON({ triggers } as unknown as Record<string, unknown>).put(`processes/triggers/${stringID}`);
46
+ }
23
47
  }
48
+
package/src/index.ts CHANGED
@@ -6,4 +6,5 @@ export type { Operator } from './types/operator.models.js';
6
6
  export type { BaseResponse } from './types/response.models.js';
7
7
  export type { RecordID } from './types/recordID.models.js';
8
8
  export { StringToRecordID, RecordIDToString, emptyRecordID } from './types/recordID.models.js';
9
- export type { HistorizedData } from './types/tag.models.js';
9
+ export type { HistorizedData } from './types/tag.models.js';
10
+ export type { Process, ProcessLanguage, ProcessTrigger, TriggerType, TriggerConfig, ProcessInput, InputType, InputConfig, ProcessOutput, OutputType, OutputConfig, ProcessKey, ProcessValue } from './types/processes.models.js';
package/src/sdk-ts.ts CHANGED
@@ -138,7 +138,6 @@ export class SDK {
138
138
  if (!config.application_id) config = { application_id: "" }
139
139
 
140
140
  const envCfg = await getEnvConfig();
141
-
142
141
  // Extract application_id from runtimeID if not provided in config
143
142
  const application_id = config.application_id ||
144
143
  this.extractApplicationIDFromRuntimeID(envCfg.runtimeID);
@@ -164,7 +163,8 @@ export class SDK {
164
163
  }
165
164
 
166
165
  if (!config.httpUrl) {
167
- config.httpUrl = `${secured ? 'https' : 'http'}://${host}`;
166
+ const httpHost = envCfg.hostingMode === 'path' ? `${host}/` : host;
167
+ config.httpUrl = `${secured ? 'https' : 'http'}://${httpHost}`;
168
168
  }
169
169
 
170
170
  if (!config.mqttUrl) {
@@ -56,7 +56,7 @@ class RequestParameters {
56
56
  }
57
57
 
58
58
  private withQuery(path: string, query?: Record<string, string>): URL {
59
- const newPath = [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
59
+ const newPath = "/" + [this.base.pathname, path].map(pathPart => pathPart.replace(/(^\/|\/$)/g, "")).join("/");
60
60
  const newURL = new URL(newPath, this.base);
61
61
 
62
62
  for (const key in query) {
@@ -231,6 +231,22 @@ class RequestParameters {
231
231
  }
232
232
 
233
233
 
234
+ public async postAsBlob(path: string, query?: Record<string, string>): Promise<Blob> {
235
+ const init: RequestInit = this.parseInit("POST") || {};
236
+
237
+ const response = await fetch(this.withQuery(path, query), init);
238
+
239
+ if (!response.ok) {
240
+ throw new HTTPException(
241
+ response.status,
242
+ response.statusText,
243
+ await response.text(),
244
+ );
245
+ }
246
+ return response.blob();
247
+ }
248
+
249
+
234
250
  public async put<ReturnType>(path: string, query?: Record<string, string>): Promise<ReturnType> {
235
251
  const response = await fetch(this.withQuery(path, query), this.parseInit("PUT"));
236
252
 
@@ -0,0 +1,71 @@
1
+ import { RecordID } from "./recordID.models.js";
2
+
3
+ export type ProcessLanguage = "python" | "typescript";
4
+
5
+ export type TriggerType = "tag_change" | "interval" | "cron" | "http" | "manual";
6
+
7
+ export interface TriggerConfig {
8
+ cron_expression?: string;
9
+ interval_value?: number;
10
+ interval_unit?: string;
11
+ tag?: string;
12
+ endpoint?: string;
13
+ }
14
+
15
+ export interface ProcessTrigger {
16
+ type: TriggerType;
17
+ config: TriggerConfig;
18
+ }
19
+
20
+ export type InputType = "tag" | "sql";
21
+
22
+ export interface InputConfig {
23
+ tag?: string;
24
+ query?: string;
25
+ }
26
+
27
+ export interface ProcessInput {
28
+ name: string;
29
+ type: InputType;
30
+ config: InputConfig;
31
+ }
32
+
33
+ export type OutputType = "sql" | "tag_write";
34
+
35
+ export interface OutputConfig {
36
+ query?: string;
37
+ tag?: string;
38
+ field?: string;
39
+ }
40
+
41
+ export interface ProcessOutput {
42
+ type: OutputType;
43
+ config: OutputConfig;
44
+ }
45
+
46
+ export interface ProcessKey {
47
+ key: string;
48
+ }
49
+
50
+ export interface ProcessValue {
51
+ value: string;
52
+ }
53
+
54
+ export interface Process {
55
+ id?: RecordID;
56
+ domain_id?: RecordID;
57
+ name: string;
58
+ enabled: boolean;
59
+ log_enabled: boolean;
60
+ language: ProcessLanguage;
61
+ code: string;
62
+ version: number;
63
+ triggers: ProcessTrigger[];
64
+ inputs: ProcessInput[];
65
+ outputs: ProcessOutput[];
66
+ keys?: ProcessKey[];
67
+ values?: ProcessValue[];
68
+ createdBy?: RecordID;
69
+ createdDt?: string;
70
+ updated_dt?: string;
71
+ }