@mybe/sdk 1.0.6 → 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 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
- - ✅ **Auto Environment Detection** - Automatically detects development vs production
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
- The SDK automatically detects the environment:
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
- > **Note:** The SDK uses a custom domain for all environments, providing a professional branded URL while hiding the underlying AWS infrastructure. Both development and production currently point to the same endpoint temporarily.
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({ apiKey: 'your-api-key' });
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
- this.apiKey = config.apiKey;
10
- if (config.baseUrl) {
11
- this.baseUrl = config.baseUrl;
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
- const isDevelopment = typeof process !== 'undefined' &&
15
- process.env.CONTENSA_SDK_ENV === 'development';
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.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
- return await this.request(`/type/${contentTypeId}${queryString}`);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mybe/sdk",
3
- "version": "1.0.6",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",