@machhub-dev/sdk-ts 1.0.0 → 1.0.2

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.
@@ -1,5 +1,6 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
2
  import { MQTTService } from "../services/mqtt.service.js";
3
+ import { Operator } from "../types/operator.models.js";
3
4
  export declare class CollectionError extends Error {
4
5
  operation: string;
5
6
  collectionName: string;
@@ -12,7 +13,7 @@ export declare class Collection {
12
13
  protected collectionName: string;
13
14
  protected queryParams: Record<string, any>;
14
15
  constructor(httpService: HTTPService, mqttService: MQTTService | null, collectionName: string);
15
- filter(fieldName: string, operator: "=" | ">" | "<" | "<=" | ">=" | "!=" | "CONTAINS" | "IN", value: any): Collection;
16
+ filter(fieldName: string, operator: Operator, value: any): Collection;
16
17
  sort(field: string, direction?: "asc" | "desc"): Collection;
17
18
  limit(limit: number): Collection;
18
19
  offset(offset: number): Collection;
@@ -21,6 +22,7 @@ export declare class Collection {
21
22
  first(): Promise<any>;
22
23
  getAll(options?: {
23
24
  expand?: string | string[];
25
+ fields?: string | string[];
24
26
  }): Promise<any[]>;
25
27
  count(options?: {
26
28
  filter?: any;
@@ -55,7 +55,10 @@ class Collection {
55
55
  try {
56
56
  this.applyOptions(options);
57
57
  if (options?.expand) {
58
- this.queryParams.expand = Array.isArray(options.expand) ? options.expand.join() : options.expand;
58
+ this.queryParams.expand = Array.isArray(options.expand) ? options.expand.join(",") : options.expand;
59
+ }
60
+ if (options?.fields) {
61
+ this.queryParams.fields = Array.isArray(options.fields) ? options.fields.join(",") : options.fields;
59
62
  }
60
63
  return await this.httpService.request.get(this.collectionName + "/all", this.queryParams);
61
64
  }
@@ -6,5 +6,5 @@ export declare class Tag {
6
6
  constructor(httpService: HTTPService, mqttService: MQTTService | null);
7
7
  getAllTags(): Promise<string[]>;
8
8
  publish(topic: string, data: any): Promise<void>;
9
- subscribe(topic: string, callback: (data: any) => void): Promise<void>;
9
+ subscribe(topic: string, callback: (data: any, topic?: string) => void): Promise<void>;
10
10
  }
@@ -1,5 +1,6 @@
1
1
  export { SDK, type SDKConfig } from './sdk-ts.js';
2
2
  export type { LoginResponse, PermissionResponse, User, Group, Feature, Permission, ActionResponse, Action, Scope } from './types/auth.models.js';
3
+ export type { Operator } from './types/operator.models.js';
3
4
  export type { BaseResponse } from './types/response.models.js';
4
5
  export type { RecordID } from './types/recordID.models.js';
5
6
  export type { HistorizedData } from './types/tag.models.js';
@@ -7,9 +7,10 @@ export declare class MQTTService {
7
7
  constructor(url: string);
8
8
  static getInstance(url?: string, developerKey?: string): Promise<MQTTService>;
9
9
  static resetInstance(): void;
10
- addTopicHandler(topic: string, handler: (message: unknown) => void): void;
10
+ addTopicHandler(topic: string, handler: (message: unknown, topic?: string) => void): void;
11
11
  clearTopics(): void;
12
12
  publish(topic: string, message: unknown): boolean;
13
13
  private attachMessageListener;
14
+ private matchesTopic;
14
15
  private parseMessage;
15
16
  }
@@ -89,14 +89,48 @@ class MQTTService {
89
89
  });
90
90
  this.client.on('message', (topic, message) => {
91
91
  for (const subscribedTopic of this.subscribedTopics) {
92
- if (topic === subscribedTopic.topic) {
92
+ if (this.matchesTopic(subscribedTopic.topic, topic)) {
93
93
  const parsedMessage = this.parseMessage(message, topic);
94
- subscribedTopic.handler(parsedMessage);
94
+ subscribedTopic.handler(parsedMessage, topic);
95
95
  break;
96
96
  }
97
97
  }
98
98
  });
99
99
  }
100
+ // Matches MQTT topic patterns with wildcards (+ for single level, # for multi-level)
101
+ matchesTopic(pattern, topic) {
102
+ // Handle exact match first for performance
103
+ if (pattern === topic) {
104
+ return true;
105
+ }
106
+ const patternParts = pattern.split('/');
107
+ const topicParts = topic.split('/');
108
+ let i = 0;
109
+ let j = 0;
110
+ while (i < patternParts.length && j < topicParts.length) {
111
+ const patternPart = patternParts[i];
112
+ if (patternPart === '#') {
113
+ // Multi-level wildcard matches everything from this point
114
+ return true;
115
+ }
116
+ else if (patternPart === '+') {
117
+ // Single-level wildcard matches any single level
118
+ i++;
119
+ j++;
120
+ }
121
+ else if (patternPart === topicParts[j]) {
122
+ // Exact match
123
+ i++;
124
+ j++;
125
+ }
126
+ else {
127
+ // No match
128
+ return false;
129
+ }
130
+ }
131
+ // Check if we've consumed both pattern and topic completely
132
+ return i === patternParts.length && j === topicParts.length;
133
+ }
100
134
  parseMessage(message, topic) {
101
135
  try {
102
136
  return JSON.parse(message.toString());
@@ -0,0 +1,28 @@
1
+ /**
2
+ * SurrealDB Operators
3
+ * Reference: https://surrealdb.com/docs/surrealql/operators
4
+ */
5
+ /**
6
+ * Comparison operators
7
+ */
8
+ export type ComparisonOperator = "=" | "!=" | "==" | "?=" | "*=" | "~" | "!~" | "?~" | "*~" | "<" | "<=" | ">" | ">=";
9
+ /**
10
+ * Containment operators
11
+ */
12
+ export type ContainmentOperator = "CONTAINS" | "CONTAINSNOT" | "CONTAINSALL" | "CONTAINSANY" | "CONTAINSNONE" | "INSIDE" | "NOTINSIDE" | "ALLINSIDE" | "ANYINSIDE" | "NONEINSIDE";
13
+ /**
14
+ * String operators
15
+ */
16
+ export type StringOperator = "@@" | "@0@" | "@1@" | "@2@" | "@3@";
17
+ /**
18
+ * Array operators
19
+ */
20
+ export type ArrayOperator = "IN" | "NOT IN";
21
+ /**
22
+ * All available operators in SurrealDB
23
+ */
24
+ export type Operator = ComparisonOperator | ContainmentOperator | StringOperator | ArrayOperator;
25
+ /**
26
+ * Common operators for basic queries
27
+ */
28
+ export type BasicOperator = "=" | "!=" | "<" | "<=" | ">" | ">=" | "CONTAINS" | "IN";
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * SurrealDB Operators
4
+ * Reference: https://surrealdb.com/docs/surrealql/operators
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +1,6 @@
1
1
  import { HTTPService } from "../services/http.service.js";
2
2
  import { MQTTService } from "../services/mqtt.service.js";
3
+ import { Operator } from "../types/operator.models.js";
3
4
  export declare class CollectionError extends Error {
4
5
  operation: string;
5
6
  collectionName: string;
@@ -12,7 +13,7 @@ export declare class Collection {
12
13
  protected collectionName: string;
13
14
  protected queryParams: Record<string, any>;
14
15
  constructor(httpService: HTTPService, mqttService: MQTTService | null, collectionName: string);
15
- filter(fieldName: string, operator: "=" | ">" | "<" | "<=" | ">=" | "!=" | "CONTAINS" | "IN", value: any): Collection;
16
+ filter(fieldName: string, operator: Operator, value: any): Collection;
16
17
  sort(field: string, direction?: "asc" | "desc"): Collection;
17
18
  limit(limit: number): Collection;
18
19
  offset(offset: number): Collection;
@@ -21,6 +22,7 @@ export declare class Collection {
21
22
  first(): Promise<any>;
22
23
  getAll(options?: {
23
24
  expand?: string | string[];
25
+ fields?: string | string[];
24
26
  }): Promise<any[]>;
25
27
  count(options?: {
26
28
  filter?: any;
@@ -51,7 +51,10 @@ export class Collection {
51
51
  try {
52
52
  this.applyOptions(options);
53
53
  if (options?.expand) {
54
- this.queryParams.expand = Array.isArray(options.expand) ? options.expand.join() : options.expand;
54
+ this.queryParams.expand = Array.isArray(options.expand) ? options.expand.join(",") : options.expand;
55
+ }
56
+ if (options?.fields) {
57
+ this.queryParams.fields = Array.isArray(options.fields) ? options.fields.join(",") : options.fields;
55
58
  }
56
59
  return await this.httpService.request.get(this.collectionName + "/all", this.queryParams);
57
60
  }
@@ -6,5 +6,5 @@ export declare class Tag {
6
6
  constructor(httpService: HTTPService, mqttService: MQTTService | null);
7
7
  getAllTags(): Promise<string[]>;
8
8
  publish(topic: string, data: any): Promise<void>;
9
- subscribe(topic: string, callback: (data: any) => void): Promise<void>;
9
+ subscribe(topic: string, callback: (data: any, topic?: string) => void): Promise<void>;
10
10
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { SDK, type SDKConfig } from './sdk-ts.js';
2
2
  export type { LoginResponse, PermissionResponse, User, Group, Feature, Permission, ActionResponse, Action, Scope } from './types/auth.models.js';
3
+ export type { Operator } from './types/operator.models.js';
3
4
  export type { BaseResponse } from './types/response.models.js';
4
5
  export type { RecordID } from './types/recordID.models.js';
5
6
  export type { HistorizedData } from './types/tag.models.js';
@@ -7,9 +7,10 @@ export declare class MQTTService {
7
7
  constructor(url: string);
8
8
  static getInstance(url?: string, developerKey?: string): Promise<MQTTService>;
9
9
  static resetInstance(): void;
10
- addTopicHandler(topic: string, handler: (message: unknown) => void): void;
10
+ addTopicHandler(topic: string, handler: (message: unknown, topic?: string) => void): void;
11
11
  clearTopics(): void;
12
12
  publish(topic: string, message: unknown): boolean;
13
13
  private attachMessageListener;
14
+ private matchesTopic;
14
15
  private parseMessage;
15
16
  }
@@ -83,14 +83,48 @@ export class MQTTService {
83
83
  });
84
84
  this.client.on('message', (topic, message) => {
85
85
  for (const subscribedTopic of this.subscribedTopics) {
86
- if (topic === subscribedTopic.topic) {
86
+ if (this.matchesTopic(subscribedTopic.topic, topic)) {
87
87
  const parsedMessage = this.parseMessage(message, topic);
88
- subscribedTopic.handler(parsedMessage);
88
+ subscribedTopic.handler(parsedMessage, topic);
89
89
  break;
90
90
  }
91
91
  }
92
92
  });
93
93
  }
94
+ // Matches MQTT topic patterns with wildcards (+ for single level, # for multi-level)
95
+ matchesTopic(pattern, topic) {
96
+ // Handle exact match first for performance
97
+ if (pattern === topic) {
98
+ return true;
99
+ }
100
+ const patternParts = pattern.split('/');
101
+ const topicParts = topic.split('/');
102
+ let i = 0;
103
+ let j = 0;
104
+ while (i < patternParts.length && j < topicParts.length) {
105
+ const patternPart = patternParts[i];
106
+ if (patternPart === '#') {
107
+ // Multi-level wildcard matches everything from this point
108
+ return true;
109
+ }
110
+ else if (patternPart === '+') {
111
+ // Single-level wildcard matches any single level
112
+ i++;
113
+ j++;
114
+ }
115
+ else if (patternPart === topicParts[j]) {
116
+ // Exact match
117
+ i++;
118
+ j++;
119
+ }
120
+ else {
121
+ // No match
122
+ return false;
123
+ }
124
+ }
125
+ // Check if we've consumed both pattern and topic completely
126
+ return i === patternParts.length && j === topicParts.length;
127
+ }
94
128
  parseMessage(message, topic) {
95
129
  try {
96
130
  return JSON.parse(message.toString());
@@ -0,0 +1,28 @@
1
+ /**
2
+ * SurrealDB Operators
3
+ * Reference: https://surrealdb.com/docs/surrealql/operators
4
+ */
5
+ /**
6
+ * Comparison operators
7
+ */
8
+ export type ComparisonOperator = "=" | "!=" | "==" | "?=" | "*=" | "~" | "!~" | "?~" | "*~" | "<" | "<=" | ">" | ">=";
9
+ /**
10
+ * Containment operators
11
+ */
12
+ export type ContainmentOperator = "CONTAINS" | "CONTAINSNOT" | "CONTAINSALL" | "CONTAINSANY" | "CONTAINSNONE" | "INSIDE" | "NOTINSIDE" | "ALLINSIDE" | "ANYINSIDE" | "NONEINSIDE";
13
+ /**
14
+ * String operators
15
+ */
16
+ export type StringOperator = "@@" | "@0@" | "@1@" | "@2@" | "@3@";
17
+ /**
18
+ * Array operators
19
+ */
20
+ export type ArrayOperator = "IN" | "NOT IN";
21
+ /**
22
+ * All available operators in SurrealDB
23
+ */
24
+ export type Operator = ComparisonOperator | ContainmentOperator | StringOperator | ArrayOperator;
25
+ /**
26
+ * Common operators for basic queries
27
+ */
28
+ export type BasicOperator = "=" | "!=" | "<" | "<=" | ">" | ">=" | "CONTAINS" | "IN";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * SurrealDB Operators
3
+ * Reference: https://surrealdb.com/docs/surrealql/operators
4
+ */
5
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@machhub-dev/sdk-ts",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "MACHHUB TYPESCRIPT SDK",
5
5
  "keywords": [
6
6
  "machhub",
@@ -21,7 +21,7 @@ export class Tag {
21
21
  this.mqttService.publish(topic, data);
22
22
  }
23
23
 
24
- async subscribe(topic: string, callback: (data: any) => void): Promise<void> {
24
+ async subscribe(topic: string, callback: (data: any, topic?: string) => void): Promise<void> {
25
25
  if (!this.mqttService) {
26
26
  throw new Error("MQTT service not connected");
27
27
  }
@@ -2,7 +2,7 @@ import mqtt from 'mqtt';
2
2
 
3
3
  interface SubscribedTopic {
4
4
  topic: string;
5
- handler: (message: unknown) => void;
5
+ handler: (message: unknown, topic?: string) => void;
6
6
  }
7
7
 
8
8
  export class MQTTService {
@@ -46,7 +46,7 @@ export class MQTTService {
46
46
  }
47
47
 
48
48
  // addTopicHandler Adds a topic and handler to the subscribed list
49
- public addTopicHandler(topic: string, handler: (message: unknown) => void): void {
49
+ public addTopicHandler(topic: string, handler: (message: unknown, topic?: string) => void): void {
50
50
  try {
51
51
  this.subscribedTopics.push({ topic, handler });
52
52
  if (topic == "") return;
@@ -101,15 +101,52 @@ export class MQTTService {
101
101
 
102
102
  this.client.on('message', (topic: string, message: Buffer) => {
103
103
  for (const subscribedTopic of this.subscribedTopics) {
104
- if (topic === subscribedTopic.topic) {
104
+ if (this.matchesTopic(subscribedTopic.topic, topic)) {
105
105
  const parsedMessage = this.parseMessage(message, topic);
106
- subscribedTopic.handler(parsedMessage);
106
+ subscribedTopic.handler(parsedMessage, topic);
107
107
  break;
108
108
  }
109
109
  }
110
110
  });
111
111
  }
112
112
 
113
+ // Matches MQTT topic patterns with wildcards (+ for single level, # for multi-level)
114
+ private matchesTopic(pattern: string, topic: string): boolean {
115
+ // Handle exact match first for performance
116
+ if (pattern === topic) {
117
+ return true;
118
+ }
119
+
120
+ const patternParts = pattern.split('/');
121
+ const topicParts = topic.split('/');
122
+
123
+ let i = 0;
124
+ let j = 0;
125
+
126
+ while (i < patternParts.length && j < topicParts.length) {
127
+ const patternPart = patternParts[i];
128
+
129
+ if (patternPart === '#') {
130
+ // Multi-level wildcard matches everything from this point
131
+ return true;
132
+ } else if (patternPart === '+') {
133
+ // Single-level wildcard matches any single level
134
+ i++;
135
+ j++;
136
+ } else if (patternPart === topicParts[j]) {
137
+ // Exact match
138
+ i++;
139
+ j++;
140
+ } else {
141
+ // No match
142
+ return false;
143
+ }
144
+ }
145
+
146
+ // Check if we've consumed both pattern and topic completely
147
+ return i === patternParts.length && j === topicParts.length;
148
+ }
149
+
113
150
  private parseMessage(message: Buffer, topic: string): unknown {
114
151
  try {
115
152
  return JSON.parse(message.toString());