@thinkingdifferently/core 1.1.0 → 1.3.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/README.md ADDED
@@ -0,0 +1,321 @@
1
+ # `@thinkingdifferently/core`
2
+
3
+ Official TypeScript SDK for the Thinking Differently Backend-as-a-Service platform.
4
+
5
+ The SDK provides a simple interface for interacting with Thinking Differently collections without manually managing HTTP requests, authentication headers, request formatting, or query serialization.
6
+
7
+ ## Features
8
+
9
+ - TypeScript-first SDK
10
+ - Collection querying with chained builders
11
+ - Automatic API key authentication via `x-api-key`
12
+ - Axios-based HTTP layer
13
+ - Built-in validation for query inputs
14
+ - `FormData` support for inserts
15
+ - Query inspection with `toJSON()`
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @thinkingdifferently/core
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```ts
26
+ import { ThinkingDifferently } from "@thinkingdifferently/core";
27
+
28
+ const sdk = new ThinkingDifferently({
29
+ apiKey: "YOUR_API_KEY"
30
+ });
31
+
32
+ const animals = await sdk
33
+ .collection("animals")
34
+ .where("age", ">", 10)
35
+ .limit(10)
36
+ .sort("createdAt", "desc")
37
+ .get();
38
+
39
+ console.log(animals);
40
+ ```
41
+
42
+ ## TypeScript Usage
43
+
44
+ The SDK is designed for TypeScript developers and supports generic response typing:
45
+
46
+ ```ts
47
+ type Animal = {
48
+ name: string;
49
+ age: number;
50
+ };
51
+
52
+ const animals = await sdk
53
+ .collection("animals")
54
+ .get<Animal>();
55
+ ```
56
+
57
+ You can also inspect the generated query before sending it:
58
+
59
+ ```ts
60
+ const query = sdk
61
+ .collection("animals")
62
+ .where("age", ">", 10);
63
+
64
+ console.log(query.toJSON());
65
+ ```
66
+
67
+ ## API Reference
68
+
69
+ ### `new ThinkingDifferently(config)`
70
+
71
+ Creates an SDK instance.
72
+
73
+ #### Parameters
74
+
75
+ - `config.apiKey: string` — API key used for authenticated requests
76
+
77
+ #### Example
78
+
79
+ ```ts
80
+ const sdk = new ThinkingDifferently({
81
+ apiKey: "YOUR_API_KEY"
82
+ });
83
+ ```
84
+
85
+ ### `sdk.collection(name)`
86
+
87
+ Creates a query builder for a collection.
88
+
89
+ #### Parameters
90
+
91
+ - `name: string` — collection name
92
+
93
+ #### Returns
94
+
95
+ A `QueryBuilder` instance.
96
+
97
+ ### `QueryBuilder.where(field, operator, value)`
98
+
99
+ Adds a filter to the query.
100
+
101
+ #### Supported operators
102
+
103
+ - `=`
104
+ - `!=`
105
+ - `>`
106
+ - `<`
107
+ - `>=`
108
+ - `<=`
109
+ - `in`
110
+ - `contains`
111
+
112
+ #### Notes
113
+
114
+ - Empty field names are rejected
115
+ - The `in` operator requires an array value
116
+ - Multiple `where()` calls append filters
117
+
118
+ #### Example
119
+
120
+ ```ts
121
+ const query = sdk
122
+ .collection("animals")
123
+ .where("age", ">", 10)
124
+ .where("status", "=", "active");
125
+ ```
126
+
127
+ ### `QueryBuilder.limit(count)`
128
+
129
+ Sets the maximum number of returned documents.
130
+
131
+ #### Validation
132
+
133
+ - Must be a positive integer
134
+ - Subsequent calls overwrite the previous limit
135
+
136
+ #### Example
137
+
138
+ ```ts
139
+ const query = sdk.collection("animals").limit(20);
140
+ ```
141
+
142
+ ### `QueryBuilder.sort(field, direction)`
143
+
144
+ Adds a sort clause to the query.
145
+
146
+ #### Parameters
147
+
148
+ - `field: string` — field to sort by
149
+ - `direction: "asc" | "desc"` — sort direction
150
+
151
+ #### Notes
152
+
153
+ - Empty field names are rejected
154
+ - Subsequent calls overwrite the previous sort
155
+
156
+ #### Example
157
+
158
+ ```ts
159
+ const query = sdk.collection("animals").sort("createdAt", "desc");
160
+ ```
161
+
162
+ ### `QueryBuilder.get<T>()`
163
+
164
+ Executes the query and returns an array of typed results.
165
+
166
+ #### Signature
167
+
168
+ ```ts
169
+ get<T = any>(): Promise<T[]>
170
+ ```
171
+
172
+ #### Example
173
+
174
+ ```ts
175
+ const animals = await sdk
176
+ .collection("animals")
177
+ .where("age", ">", 10)
178
+ .get<{ name: string; age: number }>();
179
+ ```
180
+
181
+ ### `QueryBuilder.count()`
182
+
183
+ Returns the number of documents matching the current query.
184
+
185
+ #### Signature
186
+
187
+ ```ts
188
+ count(): Promise<number>
189
+ ```
190
+
191
+ #### Example
192
+
193
+ ```ts
194
+ const total = await sdk
195
+ .collection("animals")
196
+ .where("age", ">", 10)
197
+ .count();
198
+ ```
199
+
200
+ ### `QueryBuilder.toJSON()`
201
+
202
+ Returns a deep copy of the generated query object.
203
+
204
+ #### Example
205
+
206
+ ```ts
207
+ const query = sdk.collection("animals").where("age", ">", 10);
208
+ console.log(query.toJSON());
209
+ ```
210
+
211
+ ### `types `
212
+
213
+ ```ts
214
+ interface SDKConfig {
215
+ apiKey: string;
216
+ }
217
+ ```
218
+
219
+ ## HTTP Details
220
+
221
+ - Base URL: `https://www.thinkingdifferently.dev/api/v1`
222
+ - Authentication header: `x-api-key: YOUR_API_KEY`
223
+ - HTTP client: Axios
224
+ - Supported methods: `GET`, `POST`, `PATCH`, `DELETE`
225
+
226
+ ## Error Handling
227
+
228
+ The SDK throws JavaScript `Error` objects when requests fail or when query validation fails.
229
+
230
+ ### Request errors
231
+
232
+ Backend errors are converted into `Error` messages.
233
+
234
+ ```ts
235
+ try {
236
+ const animals = await sdk
237
+ .collection("animals")
238
+ .get();
239
+
240
+ console.log(animals);
241
+ } catch (error) {
242
+ console.error(error);
243
+ }
244
+ ```
245
+
246
+ ### Validation errors
247
+
248
+ The SDK validates query input before sending requests:
249
+
250
+ - Empty field names are rejected
251
+ - Invalid limit values are rejected
252
+ - The `in` operator requires an array
253
+ - Query responses are validated before parsing
254
+
255
+ ## Examples
256
+
257
+ ### Filter, sort, and limit
258
+
259
+ ```ts
260
+ const animals = await sdk
261
+ .collection("animals")
262
+ .where("age", ">", 10)
263
+ .where("price", "<", 50000)
264
+ .limit(10)
265
+ .sort("createdAt", "desc")
266
+ .get();
267
+ ```
268
+
269
+ ### Count matching documents
270
+
271
+ ```ts
272
+ const total = await sdk
273
+ .collection("animals")
274
+ .where("age", ">", 10)
275
+ .count();
276
+ ```
277
+
278
+ ### Inspect the generated query
279
+
280
+ ```ts
281
+ const query = sdk
282
+ .collection("animals")
283
+ .where("age", ">", 10);
284
+
285
+ console.log(JSON.stringify(query.toJSON(), null, 2));
286
+ ```
287
+
288
+ ## FAQ
289
+
290
+ ### How do I authenticate?
291
+
292
+ Pass your API key to `new ThinkingDifferently({ apiKey })`. The SDK automatically sends it using the `x-api-key` header.
293
+
294
+ ### What does `collection()` return?
295
+
296
+ It returns a query builder that lets you chain `where()`, `limit()`, `sort()`, `get()`, `count()`, and `toJSON()`.
297
+
298
+ ### Can I inspect a query before executing it?
299
+
300
+ Yes. Call `toJSON()` on the query builder to get a deep copy of the query object.
301
+
302
+ ### Does the SDK validate input?
303
+
304
+ Yes. Empty field names, invalid limit values, and invalid `in` operator values are rejected.
305
+
306
+ ### What transport does the SDK use?
307
+
308
+ The SDK uses Axios for network requests.
309
+
310
+ ## Roadmap
311
+
312
+ The following items are listed in the current design notes as not yet implemented:
313
+
314
+ - `update()`
315
+ - `delete()`
316
+ - `first()`
317
+ - pagination helpers
318
+ - aggregation queries
319
+ - `OR` conditions
320
+ - joins
321
+
package/dist/index.d.mts CHANGED
@@ -1,23 +1,66 @@
1
1
  interface SDKConfig {
2
2
  apiKey: string;
3
+ securityKey?: string;
4
+ publicKey?: string;
3
5
  }
4
6
  interface GetOptions {
5
7
  limit?: number;
6
8
  }
9
+ interface CredentialParams {
10
+ adminEmail?: string;
11
+ password?: string;
12
+ }
13
+ interface LoginResponse {
14
+ message: string;
15
+ token: string;
16
+ admin: {
17
+ id: string;
18
+ adminName: string;
19
+ adminEmail: string;
20
+ projectId: string;
21
+ projectName: string;
22
+ };
23
+ }
7
24
 
8
25
  declare class TDClient {
9
26
  private api;
10
- constructor(apiKey: string);
11
- request(method: "POST" | "GET" | "PATCH" | "DELETE", body?: any): Promise<any>;
27
+ private apikey;
28
+ private securityKey?;
29
+ private publicKey?;
30
+ private adminToken;
31
+ constructor(apiKey: string, securityKey?: string, publicKey?: string);
32
+ setSecurityKey(key: string): void;
33
+ setPublicKey(key: string): void;
34
+ setAdminToken(token: string): void;
35
+ getAdminToken(): string | null;
36
+ getPublicKey(): string | undefined;
37
+ /**
38
+ * Reusable private error formatting utility
39
+ */
40
+ private handleError;
41
+ /**
42
+ * Handles authentication HTTP requests targeting /auth/admin/login
43
+ */
44
+ adminLogin(adminEmail?: string, password?: string): Promise<LoginResponse>;
45
+ /**
46
+ * Determines if an API request is a database write operation.
47
+ */
48
+ private isWriteOperation;
49
+ /**
50
+ * Executes queries and mutations against /data endpoint.
51
+ */
52
+ sendDataRequest(method: "POST" | "GET" | "PATCH" | "DELETE", body?: any): Promise<any>;
12
53
  }
13
54
 
14
55
  type Operator = "=" | "!=" | ">" | "<" | ">=" | "<=" | "in" | "contains";
56
+ type Operation = "find" | "count" | "insert" | "update" | "delete" | "updateMany" | "deleteMany";
15
57
  type Filter = {
16
58
  field: string;
17
59
  operator: Operator;
18
60
  value: unknown;
19
61
  };
20
62
  type Query = {
63
+ operation: Operation | null;
21
64
  collection: string;
22
65
  filters: Filter[];
23
66
  limit: number | null;
@@ -25,6 +68,8 @@ type Query = {
25
68
  field: string;
26
69
  direction: "asc" | "desc";
27
70
  } | null;
71
+ id?: string;
72
+ data?: unknown;
28
73
  };
29
74
  declare class QueryBuilder {
30
75
  private query;
@@ -33,18 +78,63 @@ declare class QueryBuilder {
33
78
  where(field: string, operator: Operator, value: unknown): this;
34
79
  limit(count: number): this;
35
80
  sort(field: string, direction: "asc" | "desc"): this;
36
- get<T = any>(): Promise<T[]>;
37
81
  count(): Promise<number>;
38
82
  toJSON(): Query;
83
+ get<T = any>(): Promise<T[]>;
84
+ insert(data: unknown): Promise<any>;
85
+ UpdateById(id: string, data: Record<string, any>): Promise<any>;
86
+ updateMany(data: Record<string, any>): Promise<any>;
87
+ DeleteById(id: string): Promise<any>;
88
+ deleteMany(): Promise<any>;
89
+ }
90
+
91
+ declare class AdminAuth {
92
+ private client;
93
+ constructor(client: TDClient);
94
+ /**
95
+ * Authenticate an administrator using credentials.
96
+ * The token returned will be automatically stored in the SDK client.
97
+ */
98
+ credentials(adminEmail?: string, password?: string): Promise<LoginResponse>;
99
+ /**
100
+ * Get the currently active administrator JWT token.
101
+ */
102
+ getToken(): string | null;
103
+ /**
104
+ * Manually set the administrator JWT token (e.g. for server-side requests).
105
+ */
106
+ setToken(token: string): void;
107
+ /**
108
+ * Offline verification of Ed25519 (EdDSA) JWT admin token using public key.
109
+ * Supported in Node.js / Server-side environments.
110
+ */
111
+ verifyJwt(token: string, publicKeyPem?: string): any;
112
+ }
113
+ declare class AuthModule {
114
+ admin: AdminAuth;
115
+ constructor(client: TDClient);
39
116
  }
40
117
 
41
118
  declare class ThinkingDifferently {
42
119
  private client;
120
+ auth: AuthModule;
43
121
  constructor(config: SDKConfig);
122
+ /**
123
+ * Dynamically update the security key (useful for backend projects).
124
+ */
125
+ setSecurityKey(key: string): void;
126
+ /**
127
+ * Dynamically update the public key used for offline verification.
128
+ */
129
+ setPublicKey(key: string): void;
130
+ /**
131
+ * Helper to verify Ed25519 admin JWT token offline.
132
+ */
133
+ verifyJwt(token: string, publicKey?: string): any;
44
134
  collection(name: string): QueryBuilder;
45
135
  insert(key: string, data: any): Promise<any>;
46
136
  update(key: string, id: string, data: Record<string, any>): Promise<any>;
47
137
  delete(key: string, id: string): Promise<any>;
48
138
  }
49
139
 
50
- export { type GetOptions, type SDKConfig, TDClient, ThinkingDifferently };
140
+ export { AdminAuth, AuthModule, type CredentialParams, type GetOptions, type LoginResponse, type SDKConfig, TDClient, ThinkingDifferently };
package/dist/index.d.ts CHANGED
@@ -1,23 +1,66 @@
1
1
  interface SDKConfig {
2
2
  apiKey: string;
3
+ securityKey?: string;
4
+ publicKey?: string;
3
5
  }
4
6
  interface GetOptions {
5
7
  limit?: number;
6
8
  }
9
+ interface CredentialParams {
10
+ adminEmail?: string;
11
+ password?: string;
12
+ }
13
+ interface LoginResponse {
14
+ message: string;
15
+ token: string;
16
+ admin: {
17
+ id: string;
18
+ adminName: string;
19
+ adminEmail: string;
20
+ projectId: string;
21
+ projectName: string;
22
+ };
23
+ }
7
24
 
8
25
  declare class TDClient {
9
26
  private api;
10
- constructor(apiKey: string);
11
- request(method: "POST" | "GET" | "PATCH" | "DELETE", body?: any): Promise<any>;
27
+ private apikey;
28
+ private securityKey?;
29
+ private publicKey?;
30
+ private adminToken;
31
+ constructor(apiKey: string, securityKey?: string, publicKey?: string);
32
+ setSecurityKey(key: string): void;
33
+ setPublicKey(key: string): void;
34
+ setAdminToken(token: string): void;
35
+ getAdminToken(): string | null;
36
+ getPublicKey(): string | undefined;
37
+ /**
38
+ * Reusable private error formatting utility
39
+ */
40
+ private handleError;
41
+ /**
42
+ * Handles authentication HTTP requests targeting /auth/admin/login
43
+ */
44
+ adminLogin(adminEmail?: string, password?: string): Promise<LoginResponse>;
45
+ /**
46
+ * Determines if an API request is a database write operation.
47
+ */
48
+ private isWriteOperation;
49
+ /**
50
+ * Executes queries and mutations against /data endpoint.
51
+ */
52
+ sendDataRequest(method: "POST" | "GET" | "PATCH" | "DELETE", body?: any): Promise<any>;
12
53
  }
13
54
 
14
55
  type Operator = "=" | "!=" | ">" | "<" | ">=" | "<=" | "in" | "contains";
56
+ type Operation = "find" | "count" | "insert" | "update" | "delete" | "updateMany" | "deleteMany";
15
57
  type Filter = {
16
58
  field: string;
17
59
  operator: Operator;
18
60
  value: unknown;
19
61
  };
20
62
  type Query = {
63
+ operation: Operation | null;
21
64
  collection: string;
22
65
  filters: Filter[];
23
66
  limit: number | null;
@@ -25,6 +68,8 @@ type Query = {
25
68
  field: string;
26
69
  direction: "asc" | "desc";
27
70
  } | null;
71
+ id?: string;
72
+ data?: unknown;
28
73
  };
29
74
  declare class QueryBuilder {
30
75
  private query;
@@ -33,18 +78,63 @@ declare class QueryBuilder {
33
78
  where(field: string, operator: Operator, value: unknown): this;
34
79
  limit(count: number): this;
35
80
  sort(field: string, direction: "asc" | "desc"): this;
36
- get<T = any>(): Promise<T[]>;
37
81
  count(): Promise<number>;
38
82
  toJSON(): Query;
83
+ get<T = any>(): Promise<T[]>;
84
+ insert(data: unknown): Promise<any>;
85
+ UpdateById(id: string, data: Record<string, any>): Promise<any>;
86
+ updateMany(data: Record<string, any>): Promise<any>;
87
+ DeleteById(id: string): Promise<any>;
88
+ deleteMany(): Promise<any>;
89
+ }
90
+
91
+ declare class AdminAuth {
92
+ private client;
93
+ constructor(client: TDClient);
94
+ /**
95
+ * Authenticate an administrator using credentials.
96
+ * The token returned will be automatically stored in the SDK client.
97
+ */
98
+ credentials(adminEmail?: string, password?: string): Promise<LoginResponse>;
99
+ /**
100
+ * Get the currently active administrator JWT token.
101
+ */
102
+ getToken(): string | null;
103
+ /**
104
+ * Manually set the administrator JWT token (e.g. for server-side requests).
105
+ */
106
+ setToken(token: string): void;
107
+ /**
108
+ * Offline verification of Ed25519 (EdDSA) JWT admin token using public key.
109
+ * Supported in Node.js / Server-side environments.
110
+ */
111
+ verifyJwt(token: string, publicKeyPem?: string): any;
112
+ }
113
+ declare class AuthModule {
114
+ admin: AdminAuth;
115
+ constructor(client: TDClient);
39
116
  }
40
117
 
41
118
  declare class ThinkingDifferently {
42
119
  private client;
120
+ auth: AuthModule;
43
121
  constructor(config: SDKConfig);
122
+ /**
123
+ * Dynamically update the security key (useful for backend projects).
124
+ */
125
+ setSecurityKey(key: string): void;
126
+ /**
127
+ * Dynamically update the public key used for offline verification.
128
+ */
129
+ setPublicKey(key: string): void;
130
+ /**
131
+ * Helper to verify Ed25519 admin JWT token offline.
132
+ */
133
+ verifyJwt(token: string, publicKey?: string): any;
44
134
  collection(name: string): QueryBuilder;
45
135
  insert(key: string, data: any): Promise<any>;
46
136
  update(key: string, id: string, data: Record<string, any>): Promise<any>;
47
137
  delete(key: string, id: string): Promise<any>;
48
138
  }
49
139
 
50
- export { type GetOptions, type SDKConfig, TDClient, ThinkingDifferently };
140
+ export { AdminAuth, AuthModule, type CredentialParams, type GetOptions, type LoginResponse, type SDKConfig, TDClient, ThinkingDifferently };