@obniz/obniz-now-sdk 0.1.0 → 0.1.10

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 obniz
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -3,6 +3,190 @@
3
3
  TypeScript/JavaScript SDK for Obniz Now API
4
4
 
5
5
  ## Installation
6
+ ```bash
7
+ npm install @obniz/obniz-now-sdk-js
8
+ ```
9
+
10
+ ## Authentication
11
+
12
+ The SDK supports authentication using an API token (Bearer token). You can obtain your API token from your [Obniz account settings](https://obniz.com/).
13
+
14
+ ### Using API Token
15
+ ```typescript
16
+ import { ObnizNow } from '@obniz/sdk';
17
+
18
+ const client = new ObnizNow({
19
+ token: 'your-api-token-here'
20
+ });
21
+ ```
22
+
23
+ ### Using Environment Variables (Recommended)
24
+ ```typescript
25
+ const client = new ObnizNow({
26
+ token: process.env.OBNIZ_NOW_TOKEN
27
+ });
28
+ ```
29
+
30
+ ## Basic Usage
31
+
32
+ ### List Machines
33
+
34
+ ```typescript
35
+ import { ObnizNow } from '@obniz/obniz-now-sdk-js';
36
+
37
+ const client = new ObnizNow({ token: process.env.OBNIZ_TOKEN });
38
+
39
+ // Get list of machines
40
+ const response = await client.machines.listMachines({
41
+ limit: 10,
42
+ offset: 0
43
+ });
44
+
45
+ console.log(`Found ${response.count} machines`);
46
+ response.items.forEach((item) => {
47
+ console.log(`- ${item.machine.name} (${item.machine.id})`);
48
+ });
49
+ ```
50
+
51
+ ### Get Machine Details
52
+ ```typescript
53
+ // Get specific machine
54
+ const machine = await client.machine.getMachine({
55
+ machineId: 'machine-id'
56
+ });
57
+
58
+ console.log(`Name: ${machine.name}`);
59
+ console.log(`Created: ${machine.createdAt}`);
60
+ ```
61
+
62
+ ### Get Events
63
+ ```typescript
64
+ // Get recent events
65
+ const events = await client.events.listEvents({
66
+ from: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
67
+ to: new Date().toISOString(),
68
+ limit: 20
69
+ });
70
+
71
+ console.log(`Found ${events.count} events`);
72
+ ```
73
+
74
+ ## Error Handling
75
+
76
+ All API errors are automatically converted to `ObnizNowApiError` with parsed response data.
77
+
78
+ ```typescript
79
+ import { ObnizNow, ObnizNowApiError } from '@obniz/obniz-now-sdk-js';
80
+
81
+ try {
82
+ const machine = await client.machine.getMachine({ machineId: 'invalid-id' });
83
+ } catch (error) {
84
+ if (error instanceof ObnizNowApiError) {
85
+ console.error(`Error ${error.status}: ${error.message}`);
86
+ console.error('Details:', error.data);
87
+
88
+ // Access response headers
89
+ const headers = error.getResponseHeaders();
90
+ const rateLimit = headers.get('x-ratelimit-remaining');
91
+
92
+ // Get request URL for debugging
93
+ console.error('Failed request:', error.getRequestUrl());
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## Browser Usage (Svelte)
6
99
 
100
+ ### ⚠️ Security Warning
101
+ **Never expose your API token in client-side code!** Use one of these safe approaches:
102
+
103
+ ### Option 1: Cookie-based Authentication (Recommended)
104
+ ```typescript
105
+ // In your Svelte component
106
+ import { ObnizNow } from '@obniz/obniz-now-sdk-js';
107
+
108
+ const client = new ObnizNow({
109
+ cookies: {
110
+ token: getCookie('token'),
111
+ accountId: getCookie('account_id'),
112
+ },
113
+ });
114
+
115
+ function getCookie(name: string): string {
116
+ const value = `; ${document.cookie}`;
117
+ const parts = value.split(`; ${name}=`);
118
+ if (parts.length === 2) return parts.pop()?.split(';').shift() || '';
119
+ return '';
120
+ }
121
+ ```
122
+
123
+ Your backend should set httpOnly cookies after user authentication.
124
+
125
+ ### Option 2: Backend Proxy
126
+ ```typescript
127
+ // Frontend - call your backend API
128
+ const machines = await fetch('/api/obniz/machines').then(r => r.json());
129
+
130
+ // Backend (Node.js) - proxy to Obniz API
131
+ app.get('/api/obniz/machines', async (req, res) => {
132
+ const client = new ObnizNow({ token: process.env.OBNIZ_TOKEN });
133
+ const data = await client.machines.listMachines({ limit: 20 });
134
+ res.json(data);
135
+ });
136
+ ```
137
+
138
+ ### SvelteKit Server-Side Example
139
+ ```typescript
140
+ // src/routes/+page.server.ts
141
+ import { ObnizNow } from '@obniz/sdk';
142
+
143
+ export async function load() {
144
+ const client = new ObnizNow({ token: process.env.OBNIZ_TOKEN });
145
+ const machines = await client.machines.listMachines({ limit: 20 });
146
+
147
+ return { machines: machines.items };
148
+ }
149
+ ```
150
+
151
+ ```svelte
152
+ <!-- src/routes/+page.svelte -->
153
+ <script lang="ts">
154
+ export let data;
155
+ </script>
156
+
157
+ <h1>Machines</h1>
158
+ <ul>
159
+ {#each data.machines as item}
160
+ <li>{item.machine.name}</li>
161
+ {/each}
162
+ </ul>
163
+ ```
164
+
165
+ ## Examples
166
+ See the examples/ directory for more detailed examples:
167
+
168
+ `basic-usage.ts` - SDK initialization and basic operations
169
+
170
+ `analytics.ts` - Working with analytics
171
+
172
+ `events.ts` - Retrieving and filtering events
173
+
174
+ `machine-management.ts` - CRUD operations
175
+
176
+ `custom-config.ts` - Advanced configuration (retry, logging)
177
+
178
+ `advanced-error-handling.ts` - Error inspection and debugging
179
+
180
+ ### Run any example:
7
181
  ```bash
8
- npm install @obniz/obniz-now-sdk
182
+ npx tsx examples/basic-usage.ts
183
+ ```
184
+
185
+ # Requirements
186
+ Node.js >= 18.0.0
187
+
188
+ # Links
189
+ Website:
190
+ https://iot.obniz.com
191
+
192
+ API documentation: https://now.obniz.com/api/1/docs/
@@ -1,16 +1,13 @@
1
1
  import { ResponseError } from "./sdk-core/runtime";
2
2
  /**
3
- * Enhanced API error with automatically parsed response data
4
- *
5
- * All API methods automatically convert ResponseError to ObnizApiError,
6
- * so you get parsed error information without manual handling.
3
+ * All API methods automatically convert ResponseError to ObnizApiError
7
4
  *
8
5
  * @example
9
6
  * ```typescript
10
7
  * try {
11
8
  * await client.machines.getMachine({ id: 'invalid-id' });
12
9
  * } catch (error) {
13
- * if (error instanceof ObnizApiError) {
10
+ * if (error instanceof ObnizNowApiError) {
14
11
  * console.error(`API Error [${error.status}]: ${error.message}`);
15
12
  * console.error('Error data:', error.data);
16
13
  * }
@@ -28,7 +25,7 @@ export declare class ObnizNowApiError extends Error {
28
25
  readonly originalError: ResponseError;
29
26
  constructor(responseError: ResponseError, status: number, statusText: string, data: any);
30
27
  /**
31
- * Create ObnizApiError from ResponseError by parsing the response
28
+ * Create ObnizNowApiError from ResponseError by parsing the response
32
29
  */
33
30
  static fromResponseError(error: ResponseError): Promise<ObnizNowApiError>;
34
31
  /**
@@ -57,6 +54,6 @@ export declare class ObnizNowApiError extends Error {
57
54
  };
58
55
  }
59
56
  /**
60
- * Wraps an API object to automatically convert ResponseError to ObnizApiError
57
+ * Wraps an API object to automatically convert ResponseError to ObnizNowApiError
61
58
  */
62
59
  export declare function wrapApiWithErrorHandling<T extends object>(api: T): T;
package/dist/index.d.ts CHANGED
@@ -1,2 +1 @@
1
1
  export * from "./ObnizNow";
2
- export { ObnizNowApiError } from "./ObnizNowApiError";
package/dist/index.js CHANGED
@@ -2267,6 +2267,38 @@ class NotificationsApi extends BaseAPI {
2267
2267
  async deleteNotification(requestParameters, initOverrides) {
2268
2268
  await this.deleteNotificationRaw(requestParameters, initOverrides);
2269
2269
  }
2270
+ /**
2271
+ * Retrieves the send history for a specific notification destination with pagination **Authorization** - API token is required in the `Authorization` header **Permissions** - `notifications:read` permission is required
2272
+ * Get notification history
2273
+ */
2274
+ async listNotificationHistoryRaw(requestParameters, initOverrides) {
2275
+ if (requestParameters['id'] == null) {
2276
+ throw new RequiredError('id', 'Required parameter "id" was null or undefined when calling listNotificationHistory().');
2277
+ }
2278
+ const queryParameters = {};
2279
+ if (requestParameters['limit'] != null) {
2280
+ queryParameters['limit'] = requestParameters['limit'];
2281
+ }
2282
+ if (requestParameters['offset'] != null) {
2283
+ queryParameters['offset'] = requestParameters['offset'];
2284
+ }
2285
+ const headerParameters = {};
2286
+ const response = await this.request({
2287
+ path: `/api/1/notifications/{id}/history`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
2288
+ method: 'GET',
2289
+ headers: headerParameters,
2290
+ query: queryParameters,
2291
+ }, initOverrides);
2292
+ return new JSONApiResponse(response);
2293
+ }
2294
+ /**
2295
+ * Retrieves the send history for a specific notification destination with pagination **Authorization** - API token is required in the `Authorization` header **Permissions** - `notifications:read` permission is required
2296
+ * Get notification history
2297
+ */
2298
+ async listNotificationHistory(requestParameters, initOverrides) {
2299
+ const response = await this.listNotificationHistoryRaw(requestParameters, initOverrides);
2300
+ return await response.value();
2301
+ }
2270
2302
  /**
2271
2303
  * Retrieves notification destinations within the account with pagination **Authorization** - API token is required in the `Authorization` header **Permissions** - `notifications:read` permission is required
2272
2304
  * Get notifications list
@@ -2312,6 +2344,7 @@ class NotificationsApi extends BaseAPI {
2312
2344
  }
2313
2345
  const queryParameters = {};
2314
2346
  const headerParameters = {};
2347
+ headerParameters['Content-Type'] = 'application/json';
2315
2348
  if (this.configuration && this.configuration.apiKey) {
2316
2349
  headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiToken authentication
2317
2350
  }
@@ -2320,6 +2353,7 @@ class NotificationsApi extends BaseAPI {
2320
2353
  method: 'POST',
2321
2354
  headers: headerParameters,
2322
2355
  query: queryParameters,
2356
+ body: requestParameters['testNotificationRequest'],
2323
2357
  }, initOverrides);
2324
2358
  return new JSONApiResponse(response);
2325
2359
  }
@@ -2331,6 +2365,39 @@ class NotificationsApi extends BaseAPI {
2331
2365
  const response = await this.testNotificationRaw(requestParameters, initOverrides);
2332
2366
  return await response.value();
2333
2367
  }
2368
+ /**
2369
+ * Updates the title/body templates for a notification destination. Templates support {:key} placeholders that are dynamically replaced when sending notifications. Set to null to clear the template and use the controller-generated values as-is. **Authorization** - API token is required in the `Authorization` header **Permissions** - `notifications:write` permission is required
2370
+ * Update notification template
2371
+ */
2372
+ async updateNotificationTemplateRaw(requestParameters, initOverrides) {
2373
+ if (requestParameters['id'] == null) {
2374
+ throw new RequiredError('id', 'Required parameter "id" was null or undefined when calling updateNotificationTemplate().');
2375
+ }
2376
+ if (requestParameters['updateNotificationTemplateRequest'] == null) {
2377
+ throw new RequiredError('updateNotificationTemplateRequest', 'Required parameter "updateNotificationTemplateRequest" was null or undefined when calling updateNotificationTemplate().');
2378
+ }
2379
+ const queryParameters = {};
2380
+ const headerParameters = {};
2381
+ headerParameters['Content-Type'] = 'application/json';
2382
+ if (this.configuration && this.configuration.apiKey) {
2383
+ headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiToken authentication
2384
+ }
2385
+ const response = await this.request({
2386
+ path: `/api/1/notifications/{id}`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
2387
+ method: 'PATCH',
2388
+ headers: headerParameters,
2389
+ query: queryParameters,
2390
+ body: requestParameters['updateNotificationTemplateRequest'],
2391
+ }, initOverrides);
2392
+ return new VoidApiResponse(response);
2393
+ }
2394
+ /**
2395
+ * Updates the title/body templates for a notification destination. Templates support {:key} placeholders that are dynamically replaced when sending notifications. Set to null to clear the template and use the controller-generated values as-is. **Authorization** - API token is required in the `Authorization` header **Permissions** - `notifications:write` permission is required
2396
+ * Update notification template
2397
+ */
2398
+ async updateNotificationTemplate(requestParameters, initOverrides) {
2399
+ await this.updateNotificationTemplateRaw(requestParameters, initOverrides);
2400
+ }
2334
2401
  }
2335
2402
 
2336
2403
  /* tslint:disable */
@@ -3152,128 +3219,6 @@ class UnitsApi extends BaseAPI {
3152
3219
  }
3153
3220
  }
3154
3221
 
3155
- /**
3156
- * Enhanced API error with automatically parsed response data
3157
- *
3158
- * All API methods automatically convert ResponseError to ObnizApiError,
3159
- * so you get parsed error information without manual handling.
3160
- *
3161
- * @example
3162
- * ```typescript
3163
- * try {
3164
- * await client.machines.getMachine({ id: 'invalid-id' });
3165
- * } catch (error) {
3166
- * if (error instanceof ObnizApiError) {
3167
- * console.error(`API Error [${error.status}]: ${error.message}`);
3168
- * console.error('Error data:', error.data);
3169
- * }
3170
- * }
3171
- * ```
3172
- */
3173
- class ObnizNowApiError extends Error {
3174
- constructor(responseError, status, statusText, data) {
3175
- const message = data?.error || data?.message || statusText || `HTTP ${status}`;
3176
- super(message);
3177
- this.name = "ObnizApiError";
3178
- this.status = status;
3179
- this.statusText = statusText;
3180
- this.data = data;
3181
- // Store originalError as non-enumerable property to keep it out of console.log
3182
- // but still accessible for advanced use cases
3183
- Object.defineProperty(this, 'originalError', {
3184
- value: responseError,
3185
- writable: false,
3186
- enumerable: false, // Не будет засирать console.log!
3187
- configurable: false
3188
- });
3189
- // Maintain proper stack trace (ES2015+)
3190
- if (Error.captureStackTrace) {
3191
- Error.captureStackTrace(this, ObnizNowApiError);
3192
- }
3193
- }
3194
- /**
3195
- * Create ObnizApiError from ResponseError by parsing the response
3196
- */
3197
- static async fromResponseError(error) {
3198
- const status = error.response.status;
3199
- const statusText = error.response.statusText;
3200
- let data;
3201
- try {
3202
- // Try to parse as JSON
3203
- const text = await error.response.text();
3204
- data = JSON.parse(text);
3205
- }
3206
- catch {
3207
- // If not JSON, wrap as error object
3208
- try {
3209
- data = { error: await error.response.text() };
3210
- }
3211
- catch {
3212
- data = { error: statusText };
3213
- }
3214
- }
3215
- return new ObnizNowApiError(error, status, statusText, data);
3216
- }
3217
- /**
3218
- * Get response headers (useful for rate limiting, caching, etc.)
3219
- *
3220
- * @example
3221
- * ```typescript
3222
- * const rateLimit = error.getResponseHeaders().get('x-ratelimit-remaining');
3223
- * ```
3224
- */
3225
- getResponseHeaders() {
3226
- return this.originalError.response.headers;
3227
- }
3228
- /**
3229
- * Get full request URL
3230
- */
3231
- getRequestUrl() {
3232
- return this.originalError.response.url;
3233
- }
3234
- /**
3235
- * Control JSON serialization - don't include originalError
3236
- */
3237
- toJSON() {
3238
- return {
3239
- name: this.name,
3240
- message: this.message,
3241
- status: this.status,
3242
- statusText: this.statusText,
3243
- data: this.data,
3244
- stack: this.stack,
3245
- };
3246
- }
3247
- }
3248
- /**
3249
- * Wraps an API object to automatically convert ResponseError to ObnizApiError
3250
- */
3251
- function wrapApiWithErrorHandling(api) {
3252
- return new Proxy(api, {
3253
- get(target, prop) {
3254
- const original = target[prop];
3255
- // Only wrap functions
3256
- if (typeof original !== 'function') {
3257
- return original;
3258
- }
3259
- // Return wrapped function that auto-converts errors
3260
- return async function (...args) {
3261
- try {
3262
- return await original.apply(this, args);
3263
- }
3264
- catch (error) {
3265
- // Convert ResponseError to ObnizApiError
3266
- if (error instanceof ResponseError) {
3267
- throw await ObnizNowApiError.fromResponseError(error);
3268
- }
3269
- // Re-throw other errors as-is
3270
- throw error;
3271
- }
3272
- };
3273
- }
3274
- });
3275
- }
3276
-
3277
3222
  /**
3278
3223
  * ObnizNow SDK main class
3279
3224
  *
@@ -3354,26 +3299,24 @@ class ObnizNow {
3354
3299
  fetchApi: customFetch || fetchApi,
3355
3300
  credentials: cookies ? "include" : undefined,
3356
3301
  });
3357
- // Wrap all APIs with automatic error handling
3358
- this.analytics = wrapApiWithErrorHandling(new AnalyticsApi(config));
3359
- this.connectionModels = wrapApiWithErrorHandling(new ConnectionModelsApi(config));
3360
- this.connections = wrapApiWithErrorHandling(new ConnectionsApi(config));
3361
- this.events = wrapApiWithErrorHandling(new EventsApi(config));
3362
- this.groups = wrapApiWithErrorHandling(new GroupsApi(config));
3363
- this.inboundConnections = wrapApiWithErrorHandling(new InboundConnectionsApi(config));
3364
- this.inboundSources = wrapApiWithErrorHandling(new InboundSourcesApi(config));
3365
- this.integrations = wrapApiWithErrorHandling(new IntegrationsApi(config));
3366
- this.intelligences = wrapApiWithErrorHandling(new IntelligencesApi(config));
3367
- this.issues = wrapApiWithErrorHandling(new IssuesApi(config));
3368
- this.machine = wrapApiWithErrorHandling(new MachineApi(config));
3369
- this.machines = wrapApiWithErrorHandling(new MachinesApi(config));
3370
- this.notifications = wrapApiWithErrorHandling(new NotificationsApi(config));
3371
- this.reports = wrapApiWithErrorHandling(new ReportsApi(config));
3372
- this.threads = wrapApiWithErrorHandling(new ThreadsApi(config));
3373
- this.units = wrapApiWithErrorHandling(new UnitsApi(config));
3302
+ this.analytics = new AnalyticsApi(config);
3303
+ this.connectionModels = new ConnectionModelsApi(config);
3304
+ this.connections = new ConnectionsApi(config);
3305
+ this.events = new EventsApi(config);
3306
+ this.groups = new GroupsApi(config);
3307
+ this.inboundConnections = new InboundConnectionsApi(config);
3308
+ this.inboundSources = new InboundSourcesApi(config);
3309
+ this.integrations = new IntegrationsApi(config);
3310
+ this.intelligences = new IntelligencesApi(config);
3311
+ this.issues = new IssuesApi(config);
3312
+ this.machine = new MachineApi(config);
3313
+ this.machines = new MachinesApi(config);
3314
+ this.notifications = new NotificationsApi(config);
3315
+ this.reports = new ReportsApi(config);
3316
+ this.threads = new ThreadsApi(config);
3317
+ this.units = new UnitsApi(config);
3374
3318
  }
3375
3319
  }
3376
3320
 
3377
3321
  exports.ObnizNow = ObnizNow;
3378
- exports.ObnizNowApiError = ObnizNowApiError;
3379
3322
  //# sourceMappingURL=index.js.map