@bloque/sdk-identity 0.0.6 → 0.0.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/README.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # @bloque/sdk-identity
2
2
 
3
- Identity and aliases API client for the Bloque SDK.
3
+ Identity, aliases, and OTP authentication API client for the Bloque SDK.
4
+
5
+ ## Features
6
+
7
+ - **Aliases**: Get user identity information by email or phone
8
+ - **OTP Origins**: Send OTP codes via WhatsApp or Email
9
+ - **Custom Origins**: Support for custom authentication origins
10
+ - **TypeScript First**: Built with TypeScript for complete type safety
4
11
 
5
12
  ## Installation
6
13
 
@@ -27,11 +34,23 @@ const identity = new IdentityClient(httpClient);
27
34
  const alias = await identity.aliases.get('user@example.com');
28
35
  console.log('User URN:', alias.urn);
29
36
  console.log('Alias status:', alias.status);
37
+
38
+ // Send OTP via WhatsApp
39
+ const otpWhatsApp = await identity.origins.whatsapp.assert('+1234567890');
40
+ console.log('OTP sent to:', otpWhatsApp.value.phone);
41
+ console.log('Expires at:', otpWhatsApp.value.expires_at);
42
+
43
+ // Send OTP via Email
44
+ const otpEmail = await identity.origins.email.assert('user@example.com');
45
+ console.log('OTP sent to:', otpEmail.value.email);
46
+ console.log('Attempts remaining:', otpEmail.params.attempts_remaining);
30
47
  ```
31
48
 
32
49
  ## API Reference
33
50
 
34
- ### Get Alias
51
+ ### Aliases
52
+
53
+ #### `aliases.get(alias)`
35
54
 
36
55
  Retrieve alias information by the alias value (email or phone):
37
56
 
@@ -39,6 +58,9 @@ Retrieve alias information by the alias value (email or phone):
39
58
  const alias = await identity.aliases.get('user@example.com');
40
59
  ```
41
60
 
61
+ **Parameters**:
62
+ - `alias` (string): Email address or phone number
63
+
42
64
  **Response**:
43
65
 
44
66
  ```typescript
@@ -63,6 +85,76 @@ interface Alias {
63
85
  }
64
86
  ```
65
87
 
88
+ ### Origins
89
+
90
+ Origins provide OTP (One-Time Password) authentication flows for different channels.
91
+
92
+ #### `origins.whatsapp.assert(phone)`
93
+
94
+ Send an OTP code via WhatsApp to the specified phone number:
95
+
96
+ ```typescript
97
+ const otp = await identity.origins.whatsapp.assert('+1234567890');
98
+ ```
99
+
100
+ **Parameters**:
101
+ - `phone` (string): Phone number in international format (e.g., '+1234567890')
102
+
103
+ **Response**:
104
+
105
+ ```typescript
106
+ interface OTPAssertionWhatsApp {
107
+ type: 'OTP';
108
+ params: {
109
+ attempts_remaining: number; // Number of remaining OTP attempts
110
+ };
111
+ value: {
112
+ phone: string; // Phone number where OTP was sent
113
+ expires_at: number; // Unix timestamp when OTP expires
114
+ };
115
+ }
116
+ ```
117
+
118
+ #### `origins.email.assert(email)`
119
+
120
+ Send an OTP code via Email to the specified email address:
121
+
122
+ ```typescript
123
+ const otp = await identity.origins.email.assert('user@example.com');
124
+ ```
125
+
126
+ **Parameters**:
127
+ - `email` (string): Email address
128
+
129
+ **Response**:
130
+
131
+ ```typescript
132
+ interface OTPAssertionEmail {
133
+ type: 'OTP';
134
+ params: {
135
+ attempts_remaining: number; // Number of remaining OTP attempts
136
+ };
137
+ value: {
138
+ email: string; // Email address where OTP was sent
139
+ expires_at: number; // Unix timestamp when OTP expires
140
+ };
141
+ }
142
+ ```
143
+
144
+ #### `origins.custom(origin)`
145
+
146
+ Create a custom origin client for custom authentication origins:
147
+
148
+ ```typescript
149
+ const customOrigin = identity.origins.custom('my-custom-origin');
150
+ const otp = await customOrigin.assert('identifier');
151
+ ```
152
+
153
+ **Parameters**:
154
+ - `origin` (string): Custom origin identifier
155
+
156
+ **Returns**: `OriginClient<OTPAssertion>` instance with `assert()` method
157
+
66
158
  ## Examples
67
159
 
68
160
  ### Get Email Alias
@@ -92,6 +184,246 @@ try {
92
184
  }
93
185
  ```
94
186
 
187
+ ### Send OTP via WhatsApp
188
+
189
+ ```typescript
190
+ import { SDK } from '@bloque/sdk';
191
+
192
+ const bloque = new SDK({
193
+ apiKey: process.env.BLOQUE_API_KEY!,
194
+ mode: 'production',
195
+ });
196
+
197
+ try {
198
+ const otp = await bloque.identity.origins.whatsapp.assert('+1234567890');
199
+
200
+ console.log('OTP sent to:', otp.value.phone);
201
+ console.log('Expires at:', new Date(otp.value.expires_at * 1000));
202
+ console.log('Attempts remaining:', otp.params.attempts_remaining);
203
+
204
+ // Now user can verify the OTP code they received
205
+ } catch (error) {
206
+ console.error('Failed to send OTP:', error);
207
+ }
208
+ ```
209
+
210
+ ### Send OTP via Email
211
+
212
+ ```typescript
213
+ import { SDK } from '@bloque/sdk';
214
+
215
+ const bloque = new SDK({
216
+ apiKey: process.env.BLOQUE_API_KEY!,
217
+ mode: 'production',
218
+ });
219
+
220
+ try {
221
+ const otp = await bloque.identity.origins.email.assert('user@example.com');
222
+
223
+ console.log('OTP sent to:', otp.value.email);
224
+ console.log('Expires at:', new Date(otp.value.expires_at * 1000));
225
+ console.log('Attempts remaining:', otp.params.attempts_remaining);
226
+
227
+ // Now user can verify the OTP code they received
228
+ } catch (error) {
229
+ console.error('Failed to send OTP:', error);
230
+ }
231
+ ```
232
+
233
+ ### Complete OTP Flow Example
234
+
235
+ ```typescript
236
+ import { SDK } from '@bloque/sdk';
237
+
238
+ const bloque = new SDK({
239
+ apiKey: process.env.BLOQUE_API_KEY!,
240
+ mode: 'production',
241
+ });
242
+
243
+ async function authenticateUser(email: string) {
244
+ try {
245
+ // Step 1: Check if user exists
246
+ const alias = await bloque.identity.aliases.get(email);
247
+
248
+ if (alias.status !== 'active') {
249
+ throw new Error('User is not active');
250
+ }
251
+
252
+ // Step 2: Send OTP
253
+ const otp = await bloque.identity.origins.email.assert(email);
254
+
255
+ console.log('OTP sent successfully to:', otp.value.email);
256
+ console.log('User has', otp.params.attempts_remaining, 'attempts remaining');
257
+ console.log('OTP expires at:', new Date(otp.value.expires_at * 1000));
258
+
259
+ // Step 3: User would now verify the OTP code
260
+ // (verification would be done through your app's verification endpoint)
261
+
262
+ return {
263
+ userUrn: alias.urn,
264
+ otpSent: true,
265
+ expiresAt: otp.value.expires_at,
266
+ };
267
+ } catch (error) {
268
+ console.error('Authentication failed:', error);
269
+ throw error;
270
+ }
271
+ }
272
+
273
+ // Usage
274
+ await authenticateUser('user@example.com');
275
+ ```
276
+
277
+ ### Using Custom Origin
278
+
279
+ ```typescript
280
+ import { SDK } from '@bloque/sdk';
281
+
282
+ const bloque = new SDK({
283
+ apiKey: process.env.BLOQUE_API_KEY!,
284
+ mode: 'production',
285
+ });
286
+
287
+ // Create a custom origin client
288
+ const customOrigin = bloque.identity.origins.custom('my-custom-sms-provider');
289
+
290
+ try {
291
+ const otp = await customOrigin.assert('+1234567890');
292
+
293
+ console.log('OTP sent via custom origin');
294
+ console.log('Attempts remaining:', otp.params.attempts_remaining);
295
+ } catch (error) {
296
+ console.error('Failed to send OTP via custom origin:', error);
297
+ }
298
+ ```
299
+
300
+ ### Error Handling with Rate Limiting
301
+
302
+ ```typescript
303
+ import { SDK } from '@bloque/sdk';
304
+
305
+ const bloque = new SDK({
306
+ apiKey: process.env.BLOQUE_API_KEY!,
307
+ mode: 'production',
308
+ });
309
+
310
+ async function sendOTPWithRetry(phone: string, maxRetries = 3) {
311
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
312
+ try {
313
+ const otp = await bloque.identity.origins.whatsapp.assert(phone);
314
+
315
+ if (otp.params.attempts_remaining === 0) {
316
+ console.warn('No OTP attempts remaining!');
317
+ return null;
318
+ }
319
+
320
+ console.log('OTP sent successfully');
321
+ console.log('Attempts remaining:', otp.params.attempts_remaining);
322
+
323
+ return otp;
324
+ } catch (error) {
325
+ console.error(`Attempt ${attempt} failed:`, error);
326
+
327
+ if (attempt === maxRetries) {
328
+ throw new Error('Max retries reached');
329
+ }
330
+
331
+ // Wait before retrying
332
+ await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
333
+ }
334
+ }
335
+ }
336
+
337
+ await sendOTPWithRetry('+1234567890');
338
+ ```
339
+
340
+ ## TypeScript Support
341
+
342
+ This package is written in TypeScript and includes complete type definitions:
343
+
344
+ ```typescript
345
+ import type {
346
+ Alias,
347
+ OTPAssertionEmail,
348
+ OTPAssertionWhatsApp,
349
+ OTPAssertion,
350
+ IdentityClient,
351
+ AliasesClient,
352
+ OriginsClient,
353
+ OriginClient,
354
+ } from '@bloque/sdk-identity';
355
+
356
+ // Type-safe alias retrieval
357
+ const alias: Alias = await identity.aliases.get('user@example.com');
358
+
359
+ // Type-safe OTP with WhatsApp
360
+ const whatsappOTP: OTPAssertionWhatsApp =
361
+ await identity.origins.whatsapp.assert('+1234567890');
362
+
363
+ // Type-safe OTP with Email
364
+ const emailOTP: OTPAssertionEmail =
365
+ await identity.origins.email.assert('user@example.com');
366
+
367
+ // Generic OTP type
368
+ const otp: OTPAssertion =
369
+ await identity.origins.email.assert('user@example.com');
370
+
371
+ // Custom origin client
372
+ const customOrigin: OriginClient<OTPAssertion> =
373
+ identity.origins.custom('my-origin');
374
+ ```
375
+
376
+ ## Use with Main SDK
377
+
378
+ When using through the main `@bloque/sdk` package:
379
+
380
+ ```typescript
381
+ import { SDK } from '@bloque/sdk';
382
+
383
+ const bloque = new SDK({
384
+ apiKey: process.env.BLOQUE_API_KEY!,
385
+ mode: 'production',
386
+ });
387
+
388
+ // All identity features are available under bloque.identity
389
+ const alias = await bloque.identity.aliases.get('user@example.com');
390
+ const otp = await bloque.identity.origins.whatsapp.assert('+1234567890');
391
+ ```
392
+
393
+ ## Key Features
394
+
395
+ ### OTP Authentication Channels
396
+
397
+ - **WhatsApp**: Send OTP codes via WhatsApp messages
398
+ - **Email**: Send OTP codes via email
399
+ - **Custom Origins**: Integrate custom authentication providers
400
+
401
+ ### Rate Limiting & Security
402
+
403
+ OTP assertions include built-in rate limiting:
404
+ - `attempts_remaining`: Track remaining OTP attempts
405
+ - `expires_at`: Unix timestamp for OTP expiration
406
+ - Automatic retry protection
407
+
408
+ ### Alias Management
409
+
410
+ - Retrieve user information by email or phone
411
+ - Check user status (active, inactive, revoked)
412
+ - Support for primary and public aliases
413
+ - Rich metadata support
414
+
415
+ ## Requirements
416
+
417
+ - Node.js 22.x or higher / Bun 1.x or higher
418
+ - TypeScript 5.x or higher (for TypeScript projects)
419
+
420
+ ## Links
421
+
422
+ - [Homepage](https://www.bloque.app)
423
+ - [Main SDK Documentation](../sdk/README.md)
424
+ - [GitHub Repository](https://github.com/bloque-app/sdk)
425
+ - [Issue Tracker](https://github.com/bloque-app/sdk/issues)
426
+
95
427
  ## Development
96
428
 
97
429
  ```bash
@@ -111,3 +443,5 @@ bun run check
111
443
  ## License
112
444
 
113
445
  [MIT](../../LICENSE)
446
+
447
+ Copyright (c) 2025-present Bloque Copilot Inc.
@@ -17,3 +17,24 @@ export type AliasResponse = {
17
17
  created_at: string;
18
18
  updated_at: string;
19
19
  };
20
+ interface OTPBase {
21
+ type: 'OTP';
22
+ params: {
23
+ attempts_remaining: number;
24
+ };
25
+ value: {
26
+ expires_at: number;
27
+ };
28
+ }
29
+ export interface OTPAssertionEmail extends OTPBase {
30
+ value: OTPBase['value'] & {
31
+ email: string;
32
+ };
33
+ }
34
+ export interface OTPAssertionWhatsApp extends OTPBase {
35
+ value: OTPBase['value'] & {
36
+ phone: string;
37
+ };
38
+ }
39
+ export type OTPAssertion = OTPAssertionEmail | OTPAssertionWhatsApp;
40
+ export {};
package/dist/client.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import type { HttpClient } from '@bloque/sdk-core';
2
2
  import { AliasesClient } from './aliases/client';
3
+ import { OriginsClient } from './origins/client';
3
4
  export declare class IdentityClient {
4
5
  private readonly httpClient;
5
6
  readonly aliases: AliasesClient;
7
+ readonly origins: OriginsClient;
6
8
  constructor(httpClient: HttpClient);
7
9
  }
package/dist/index.cjs CHANGED
@@ -24,8 +24,10 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ OriginClient: ()=>OriginClient,
27
28
  AliasesClient: ()=>AliasesClient,
28
- IdentityClient: ()=>IdentityClient
29
+ IdentityClient: ()=>IdentityClient,
30
+ OriginsClient: ()=>OriginsClient
29
31
  });
30
32
  class AliasesClient {
31
33
  httpClient;
@@ -40,19 +42,52 @@ class AliasesClient {
40
42
  return response;
41
43
  }
42
44
  }
45
+ class OriginClient {
46
+ httpClient;
47
+ origin;
48
+ constructor(httpClient, origin){
49
+ this.httpClient = httpClient;
50
+ this.origin = origin;
51
+ }
52
+ async assert(alias) {
53
+ return await this.httpClient.request({
54
+ method: 'GET',
55
+ path: `/api/origins/${this.origin}/assert?alias=${alias}`
56
+ });
57
+ }
58
+ }
59
+ class OriginsClient {
60
+ whatsapp;
61
+ email;
62
+ httpClient;
63
+ constructor(httpClient){
64
+ this.httpClient = httpClient;
65
+ this.whatsapp = new OriginClient(httpClient, 'bloque-whatsapp');
66
+ this.email = new OriginClient(httpClient, 'bloque-email');
67
+ }
68
+ custom(origin) {
69
+ return new OriginClient(this.httpClient, origin);
70
+ }
71
+ }
43
72
  class IdentityClient {
44
73
  httpClient;
45
74
  aliases;
75
+ origins;
46
76
  constructor(httpClient){
47
77
  this.httpClient = httpClient;
48
78
  this.aliases = new AliasesClient(this.httpClient);
79
+ this.origins = new OriginsClient(this.httpClient);
49
80
  }
50
81
  }
51
82
  exports.AliasesClient = __webpack_exports__.AliasesClient;
52
83
  exports.IdentityClient = __webpack_exports__.IdentityClient;
84
+ exports.OriginClient = __webpack_exports__.OriginClient;
85
+ exports.OriginsClient = __webpack_exports__.OriginsClient;
53
86
  for(var __rspack_i in __webpack_exports__)if (-1 === [
54
87
  "AliasesClient",
55
- "IdentityClient"
88
+ "IdentityClient",
89
+ "OriginClient",
90
+ "OriginsClient"
56
91
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
57
92
  Object.defineProperty(exports, '__esModule', {
58
93
  value: true
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  export * from './aliases/client';
2
2
  export * from './aliases/types';
3
+ export * from './api-types';
3
4
  export * from './client';
5
+ export * from './origins/client';
6
+ export * from './origins/origin';
package/dist/index.js CHANGED
@@ -11,12 +11,41 @@ class AliasesClient {
11
11
  return response;
12
12
  }
13
13
  }
14
+ class OriginClient {
15
+ httpClient;
16
+ origin;
17
+ constructor(httpClient, origin){
18
+ this.httpClient = httpClient;
19
+ this.origin = origin;
20
+ }
21
+ async assert(alias) {
22
+ return await this.httpClient.request({
23
+ method: 'GET',
24
+ path: `/api/origins/${this.origin}/assert?alias=${alias}`
25
+ });
26
+ }
27
+ }
28
+ class OriginsClient {
29
+ whatsapp;
30
+ email;
31
+ httpClient;
32
+ constructor(httpClient){
33
+ this.httpClient = httpClient;
34
+ this.whatsapp = new OriginClient(httpClient, 'bloque-whatsapp');
35
+ this.email = new OriginClient(httpClient, 'bloque-email');
36
+ }
37
+ custom(origin) {
38
+ return new OriginClient(this.httpClient, origin);
39
+ }
40
+ }
14
41
  class IdentityClient {
15
42
  httpClient;
16
43
  aliases;
44
+ origins;
17
45
  constructor(httpClient){
18
46
  this.httpClient = httpClient;
19
47
  this.aliases = new AliasesClient(this.httpClient);
48
+ this.origins = new OriginsClient(this.httpClient);
20
49
  }
21
50
  }
22
- export { AliasesClient, IdentityClient };
51
+ export { AliasesClient, IdentityClient, OriginClient, OriginsClient };
@@ -0,0 +1,10 @@
1
+ import type { HttpClient } from '@bloque/sdk-core';
2
+ import type { OTPAssertion, OTPAssertionEmail, OTPAssertionWhatsApp } from '../api-types';
3
+ import { OriginClient } from './origin';
4
+ export declare class OriginsClient {
5
+ readonly whatsapp: OriginClient<OTPAssertionWhatsApp>;
6
+ readonly email: OriginClient<OTPAssertionEmail>;
7
+ private readonly httpClient;
8
+ constructor(httpClient: HttpClient);
9
+ custom(origin: string): OriginClient<OTPAssertion>;
10
+ }
@@ -0,0 +1,7 @@
1
+ import type { HttpClient } from '@bloque/sdk-core';
2
+ export declare class OriginClient<TAssertion> {
3
+ private readonly httpClient;
4
+ private readonly origin;
5
+ constructor(httpClient: HttpClient, origin: string);
6
+ assert(alias: string): Promise<TAssertion>;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloque/sdk-identity",
3
- "version": "0.0.6",
3
+ "version": "0.0.10",
4
4
  "type": "module",
5
5
  "keywords": [
6
6
  "bloque",
@@ -34,7 +34,7 @@
34
34
  "node": ">=22"
35
35
  },
36
36
  "scripts": {
37
- "publish": "bun publish",
37
+ "release": "bun publish",
38
38
  "build": "rslib build",
39
39
  "dev": "rslib build --watch",
40
40
  "clean": "rm -rf node_modules && rm -rf dist",