@mybe/sdk 1.0.5 → 1.1.1
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 +186 -7
- package/dist/client.d.ts +16 -0
- package/dist/client.js +51 -12
- package/dist/types.d.ts +28 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @mybe/sdk
|
|
|
12
12
|
|
|
13
13
|
- ✅ **Zero Dependencies** - Uses native fetch API
|
|
14
14
|
- ✅ **TypeScript Support** - Full type safety with TypeScript
|
|
15
|
-
- ✅ **
|
|
15
|
+
- ✅ **Environment Support** - Query content from different environments (master, staging, development)
|
|
16
16
|
- ✅ **Error Handling** - Custom error classes for better error handling
|
|
17
17
|
- ✅ **Pagination Support** - Built-in pagination for large datasets
|
|
18
18
|
- ✅ **Status Filtering** - Filter content by status (draft, published, archived)
|
|
@@ -46,22 +46,77 @@ const contentList = await sdk.getContentByType('content-type-id', {
|
|
|
46
46
|
```typescript
|
|
47
47
|
const sdk = new MybeSDK({
|
|
48
48
|
apiKey: 'your-api-key'
|
|
49
|
+
// Defaults to 'master' environment
|
|
49
50
|
});
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
- **Development** (`NODE_ENV=development`): Uses `https://sdk-dev.contensa.ai/dev/api/v1`
|
|
54
|
-
- **Production**: Uses `https://sdk-dev.contensa.ai/dev/api/v1`
|
|
53
|
+
### Environment Configuration
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
Mybe CMS supports multiple environments for content isolation. Each SDK instance is locked to a specific environment.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Production environment (default)
|
|
59
|
+
const prodClient = new MybeSDK({
|
|
60
|
+
apiKey: 'your-api-key',
|
|
61
|
+
environment: 'master' // or omit for default
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Staging environment
|
|
65
|
+
const stagingClient = new MybeSDK({
|
|
66
|
+
apiKey: 'your-api-key',
|
|
67
|
+
environment: 'staging'
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Development environment
|
|
71
|
+
const devClient = new MybeSDK({
|
|
72
|
+
apiKey: 'your-api-key',
|
|
73
|
+
environment: 'development'
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Custom environment (by slug or UUID)
|
|
77
|
+
const customClient = new MybeSDK({
|
|
78
|
+
apiKey: 'your-api-key',
|
|
79
|
+
environment: 'my-custom-env'
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Environment Best Practices:**
|
|
84
|
+
|
|
85
|
+
1. **Master Environment** - Your production content (default)
|
|
86
|
+
2. **Staging Environment** - Test changes before production
|
|
87
|
+
3. **Development Environment** - Active development work
|
|
88
|
+
4. **Custom Environments** - Feature branches, testing, etc.
|
|
89
|
+
|
|
90
|
+
**Important:** Each client instance is locked to its environment. To query different environments, create separate client instances.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// ✅ Correct: Separate clients for different environments
|
|
94
|
+
const prodPosts = await prodClient.getContentByType('blog-post-id');
|
|
95
|
+
const stagingPosts = await stagingClient.getContentByType('blog-post-id');
|
|
96
|
+
|
|
97
|
+
// ❌ Incorrect: Cannot switch environments on the same client
|
|
98
|
+
// You must create a new client instance
|
|
99
|
+
```
|
|
57
100
|
|
|
58
101
|
### Custom Base URL (Optional)
|
|
59
102
|
|
|
60
103
|
```typescript
|
|
61
104
|
const sdk = new MybeSDK({
|
|
62
105
|
apiKey: 'your-api-key',
|
|
63
|
-
baseUrl: 'https://custom-api.example.com/api/v1'
|
|
106
|
+
baseUrl: 'https://custom-api.example.com/api/v1',
|
|
107
|
+
environment: 'staging'
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Getting Current Environment
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const sdk = new MybeSDK({
|
|
115
|
+
apiKey: 'your-api-key',
|
|
116
|
+
environment: 'staging'
|
|
64
117
|
});
|
|
118
|
+
|
|
119
|
+
console.log(sdk.getEnvironment()); // 'staging'
|
|
65
120
|
```
|
|
66
121
|
|
|
67
122
|
## API Reference
|
|
@@ -255,10 +310,102 @@ interface ContentEntry {
|
|
|
255
310
|
|
|
256
311
|
## Examples
|
|
257
312
|
|
|
313
|
+
### Environment-based Workflows
|
|
314
|
+
|
|
315
|
+
#### Development → Staging → Production
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { MybeSDK } from '@mybe/sdk';
|
|
319
|
+
|
|
320
|
+
// Create separate clients for each environment
|
|
321
|
+
const devClient = new MybeSDK({
|
|
322
|
+
apiKey: 'your-api-key',
|
|
323
|
+
environment: 'development'
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
const stagingClient = new MybeSDK({
|
|
327
|
+
apiKey: 'your-api-key',
|
|
328
|
+
environment: 'staging'
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const prodClient = new MybeSDK({
|
|
332
|
+
apiKey: 'your-api-key',
|
|
333
|
+
environment: 'master'
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Development: Work with draft content
|
|
337
|
+
const draftPosts = await devClient.getContentByType('blog-post-id', {
|
|
338
|
+
status: 'draft',
|
|
339
|
+
limit: 10
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Staging: Test published content
|
|
343
|
+
const stagingPosts = await stagingClient.getContentByType('blog-post-id', {
|
|
344
|
+
status: 'published',
|
|
345
|
+
limit: 10
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Production: Serve live content
|
|
349
|
+
const livePosts = await prodClient.getContentByType('blog-post-id', {
|
|
350
|
+
status: 'published',
|
|
351
|
+
limit: 10
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### Environment-aware Application
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
// Automatically select environment based on NODE_ENV
|
|
359
|
+
const getSDKClient = () => {
|
|
360
|
+
const apiKey = process.env.MYBE_API_KEY!;
|
|
361
|
+
|
|
362
|
+
switch (process.env.NODE_ENV) {
|
|
363
|
+
case 'production':
|
|
364
|
+
return new MybeSDK({ apiKey, environment: 'master' });
|
|
365
|
+
case 'staging':
|
|
366
|
+
return new MybeSDK({ apiKey, environment: 'staging' });
|
|
367
|
+
case 'development':
|
|
368
|
+
default:
|
|
369
|
+
return new MybeSDK({ apiKey, environment: 'development' });
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const sdk = getSDKClient();
|
|
374
|
+
console.log(`Using environment: ${sdk.getEnvironment()}`);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
#### Preview Mode (Staging vs Production)
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// Next.js example: Preview mode with environments
|
|
381
|
+
export async function getStaticProps({ preview = false }) {
|
|
382
|
+
const sdk = new MybeSDK({
|
|
383
|
+
apiKey: process.env.MYBE_API_KEY!,
|
|
384
|
+
environment: preview ? 'staging' : 'master'
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
const posts = await sdk.getContentByType('blog-post-id', {
|
|
388
|
+
status: preview ? 'draft' : 'published',
|
|
389
|
+
limit: 20
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
props: {
|
|
394
|
+
posts: posts.data,
|
|
395
|
+
preview
|
|
396
|
+
},
|
|
397
|
+
revalidate: 60
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
258
402
|
### Fetch Published Blog Posts
|
|
259
403
|
|
|
260
404
|
```typescript
|
|
261
|
-
const sdk = new MybeSDK({
|
|
405
|
+
const sdk = new MybeSDK({
|
|
406
|
+
apiKey: 'your-api-key',
|
|
407
|
+
environment: 'master' // Production content
|
|
408
|
+
});
|
|
262
409
|
|
|
263
410
|
const posts = await sdk.getContentByType('blog-post-type-id', {
|
|
264
411
|
status: 'published',
|
|
@@ -274,6 +421,8 @@ posts.data.forEach(post => {
|
|
|
274
421
|
### Fetch All Content Models
|
|
275
422
|
|
|
276
423
|
```typescript
|
|
424
|
+
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
|
|
425
|
+
|
|
277
426
|
const contentModels = await sdk.getContentModels('project-id');
|
|
278
427
|
|
|
279
428
|
contentModels.forEach(model => {
|
|
@@ -284,12 +433,42 @@ contentModels.forEach(model => {
|
|
|
284
433
|
### Fetch Single Content Entry
|
|
285
434
|
|
|
286
435
|
```typescript
|
|
436
|
+
const sdk = new MybeSDK({ apiKey: 'your-api-key' });
|
|
437
|
+
|
|
287
438
|
const content = await sdk.getContent('content-entry-id');
|
|
288
439
|
|
|
289
440
|
console.log(content.data); // Your content data
|
|
290
441
|
console.log(content.status); // draft | published | archived
|
|
291
442
|
```
|
|
292
443
|
|
|
444
|
+
### Compare Content Across Environments
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
const masterClient = new MybeSDK({
|
|
448
|
+
apiKey: 'your-api-key',
|
|
449
|
+
environment: 'master'
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
const stagingClient = new MybeSDK({
|
|
453
|
+
apiKey: 'your-api-key',
|
|
454
|
+
environment: 'staging'
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Fetch from both environments in parallel
|
|
458
|
+
const [masterContent, stagingContent] = await Promise.all([
|
|
459
|
+
masterClient.getContentByType('blog-post-id', { limit: 10 }),
|
|
460
|
+
stagingClient.getContentByType('blog-post-id', { limit: 10 })
|
|
461
|
+
]);
|
|
462
|
+
|
|
463
|
+
console.log(`Master has ${masterContent.data.length} posts`);
|
|
464
|
+
console.log(`Staging has ${stagingContent.data.length} posts`);
|
|
465
|
+
|
|
466
|
+
// Find differences
|
|
467
|
+
const masterIds = new Set(masterContent.data.map(p => p.id));
|
|
468
|
+
const stagingOnly = stagingContent.data.filter(p => !masterIds.has(p.id));
|
|
469
|
+
console.log(`${stagingOnly.length} posts only in staging`);
|
|
470
|
+
```
|
|
471
|
+
|
|
293
472
|
### Multi-locale Content
|
|
294
473
|
|
|
295
474
|
Fetch content in different languages using the locale filter:
|
package/dist/client.d.ts
CHANGED
|
@@ -2,9 +2,25 @@ import { MybeSDKConfig, ContentType, ContentEntry, ContentFilterOptions, Content
|
|
|
2
2
|
export declare class MybeSDK {
|
|
3
3
|
private apiKey;
|
|
4
4
|
private baseUrl;
|
|
5
|
+
private environment;
|
|
5
6
|
constructor(config: MybeSDKConfig);
|
|
7
|
+
/**
|
|
8
|
+
* Get the current environment this SDK instance is configured for
|
|
9
|
+
*
|
|
10
|
+
* @returns The environment identifier (slug or UUID)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const sdk = new MybeSDK({ apiKey: 'key', environment: 'staging' });
|
|
14
|
+
* console.log(sdk.getEnvironment()); // 'staging'
|
|
15
|
+
*/
|
|
16
|
+
getEnvironment(): string;
|
|
6
17
|
/**
|
|
7
18
|
* Make HTTP request to API
|
|
19
|
+
*
|
|
20
|
+
* Automatically includes:
|
|
21
|
+
* - API key authentication
|
|
22
|
+
* - Environment context header
|
|
23
|
+
* - Content-Type header
|
|
8
24
|
*/
|
|
9
25
|
private request;
|
|
10
26
|
/**
|
package/dist/client.js
CHANGED
|
@@ -2,33 +2,67 @@ import { MybeSDKError, NotFoundError, UnauthorizedError, ValidationError, Server
|
|
|
2
2
|
export class MybeSDK {
|
|
3
3
|
apiKey;
|
|
4
4
|
baseUrl;
|
|
5
|
+
environment;
|
|
5
6
|
constructor(config) {
|
|
6
7
|
if (!config.apiKey) {
|
|
7
8
|
throw new MybeSDKError('API key is required');
|
|
8
9
|
}
|
|
9
|
-
|
|
10
|
-
if (config.
|
|
11
|
-
|
|
10
|
+
// Validate API key format (basic check)
|
|
11
|
+
if (typeof config.apiKey !== 'string' || config.apiKey.trim().length === 0) {
|
|
12
|
+
throw new MybeSDKError('API key must be a non-empty string');
|
|
13
|
+
}
|
|
14
|
+
this.apiKey = config.apiKey.trim();
|
|
15
|
+
this.baseUrl = config.baseUrl || 'https://sdk.contensa.ai/v1/api/v1';
|
|
16
|
+
// Environment handling with validation
|
|
17
|
+
if (config.environment !== undefined) {
|
|
18
|
+
// Validate environment format
|
|
19
|
+
if (typeof config.environment !== 'string') {
|
|
20
|
+
throw new MybeSDKError('Environment must be a string');
|
|
21
|
+
}
|
|
22
|
+
const trimmedEnv = config.environment.trim();
|
|
23
|
+
if (trimmedEnv.length === 0) {
|
|
24
|
+
throw new MybeSDKError('Environment cannot be an empty string');
|
|
25
|
+
}
|
|
26
|
+
// Validate environment slug format (alphanumeric, hyphens, underscores)
|
|
27
|
+
// Supports both slugs (e.g., 'staging') and UUIDs
|
|
28
|
+
const isValidSlug = /^[a-z0-9][a-z0-9-_]*$/i.test(trimmedEnv);
|
|
29
|
+
const isValidUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmedEnv);
|
|
30
|
+
if (!isValidSlug && !isValidUUID) {
|
|
31
|
+
throw new MybeSDKError('Environment must be a valid slug (alphanumeric with hyphens/underscores) or UUID');
|
|
32
|
+
}
|
|
33
|
+
this.environment = trimmedEnv;
|
|
12
34
|
}
|
|
13
35
|
else {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// Use custom domain for SDK endpoints
|
|
17
|
-
// TODO: Update production URL when production custom domain is ready
|
|
18
|
-
// Production: https://fizsdck7l0.execute-api.us-east-1.amazonaws.com/dev/api/v1
|
|
19
|
-
this.baseUrl = isDevelopment
|
|
20
|
-
? 'https://sdk-dev.contensa.ai/dev/api/v1'
|
|
21
|
-
: 'https://sdk-dev.contensa.ai/dev/api/v1'; // Using dev URL for both temporarily
|
|
36
|
+
// Default to 'master' environment for backward compatibility
|
|
37
|
+
this.environment = 'master';
|
|
22
38
|
}
|
|
23
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the current environment this SDK instance is configured for
|
|
42
|
+
*
|
|
43
|
+
* @returns The environment identifier (slug or UUID)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const sdk = new MybeSDK({ apiKey: 'key', environment: 'staging' });
|
|
47
|
+
* console.log(sdk.getEnvironment()); // 'staging'
|
|
48
|
+
*/
|
|
49
|
+
getEnvironment() {
|
|
50
|
+
return this.environment;
|
|
51
|
+
}
|
|
24
52
|
/**
|
|
25
53
|
* Make HTTP request to API
|
|
54
|
+
*
|
|
55
|
+
* Automatically includes:
|
|
56
|
+
* - API key authentication
|
|
57
|
+
* - Environment context header
|
|
58
|
+
* - Content-Type header
|
|
26
59
|
*/
|
|
27
60
|
async request(endpoint, options = {}) {
|
|
28
61
|
const url = `${this.baseUrl}${endpoint}`;
|
|
29
62
|
const headers = {
|
|
30
63
|
'Content-Type': 'application/json',
|
|
31
64
|
'X-API-Key': this.apiKey,
|
|
65
|
+
'x-environment-id': this.environment, // Send environment with every request
|
|
32
66
|
...options.headers,
|
|
33
67
|
};
|
|
34
68
|
try {
|
|
@@ -149,6 +183,9 @@ export class MybeSDK {
|
|
|
149
183
|
if (options.lastKey) {
|
|
150
184
|
params.append('lastKey', encodeURIComponent(options.lastKey));
|
|
151
185
|
}
|
|
186
|
+
if (options.include !== undefined) {
|
|
187
|
+
params.append('include', options.include.toString());
|
|
188
|
+
}
|
|
152
189
|
const queryString = params.toString();
|
|
153
190
|
return queryString ? `?${queryString}` : '';
|
|
154
191
|
}
|
|
@@ -178,7 +215,9 @@ export class MybeSDK {
|
|
|
178
215
|
*/
|
|
179
216
|
async getContentByType(contentTypeId, options) {
|
|
180
217
|
const queryString = this.buildQueryString(options);
|
|
181
|
-
|
|
218
|
+
const endpoint = `/type/${contentTypeId}${queryString}`;
|
|
219
|
+
console.log('🔍 Fetching from endpoint:', endpoint);
|
|
220
|
+
return await this.request(endpoint);
|
|
182
221
|
}
|
|
183
222
|
/**
|
|
184
223
|
* Get all content entries for a project
|
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,33 @@
|
|
|
4
4
|
export interface MybeSDKConfig {
|
|
5
5
|
apiKey: string;
|
|
6
6
|
baseUrl?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Environment to query content from.
|
|
9
|
+
*
|
|
10
|
+
* Environments allow you to maintain separate content for different stages
|
|
11
|
+
* of your workflow (e.g., development, staging, production).
|
|
12
|
+
*
|
|
13
|
+
* @default 'master' - The production environment
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Production environment (default)
|
|
17
|
+
* const prodClient = new MybeSDK({ apiKey: 'key' });
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Staging environment
|
|
21
|
+
* const stagingClient = new MybeSDK({
|
|
22
|
+
* apiKey: 'key',
|
|
23
|
+
* environment: 'staging'
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Development environment
|
|
28
|
+
* const devClient = new MybeSDK({
|
|
29
|
+
* apiKey: 'key',
|
|
30
|
+
* environment: 'development'
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
environment?: string;
|
|
7
34
|
}
|
|
8
35
|
/**
|
|
9
36
|
* Content Type (Content Model)
|
|
@@ -57,6 +84,7 @@ export interface PaginationOptions {
|
|
|
57
84
|
export interface ContentFilterOptions extends PaginationOptions {
|
|
58
85
|
status?: 'draft' | 'published' | 'archived';
|
|
59
86
|
locale?: string;
|
|
87
|
+
include?: number;
|
|
60
88
|
}
|
|
61
89
|
/**
|
|
62
90
|
* Pagination Response
|