@snackbase/sdk 0.1.1 → 0.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/dist/index.mjs CHANGED
@@ -36,8 +36,11 @@ var SnackBaseError = class SnackBaseError extends Error {
36
36
  details;
37
37
  field;
38
38
  retryable;
39
- constructor(message, code, status, details, retryable = false, field) {
39
+ constructor(message, code, status, details, retryable = false, field, redirectUrl, authProvider, providerName) {
40
40
  super(message);
41
+ this.redirectUrl = redirectUrl;
42
+ this.authProvider = authProvider;
43
+ this.providerName = providerName;
41
44
  this.name = this.constructor.name;
42
45
  this.code = code;
43
46
  this.status = status;
@@ -66,6 +69,30 @@ var AuthorizationError = class AuthorizationError extends SnackBaseError {
66
69
  }
67
70
  };
68
71
  /**
72
+ * Thrown when an API key is restricted to superadmin users (403).
73
+ */
74
+ var ApiKeyRestrictedError = class ApiKeyRestrictedError extends SnackBaseError {
75
+ constructor(message, details) {
76
+ super(message || "API keys are restricted to superadmin users. Please use JWT authentication.", "API_KEY_RESTRICTED", 403, details || {
77
+ suggestion: "Remove apiKey config and use login() instead",
78
+ documentation: "https://docs.snackbase.com/authentication/api-keys"
79
+ }, false);
80
+ Object.setPrototypeOf(this, ApiKeyRestrictedError.prototype);
81
+ }
82
+ };
83
+ /**
84
+ * Thrown when email verification is required (401).
85
+ */
86
+ var EmailVerificationRequiredError = class EmailVerificationRequiredError extends SnackBaseError {
87
+ constructor(message, details) {
88
+ super(message || "Please check your email inbox to verify your account before logging in.", "EMAIL_VERIFICATION_REQUIRED", 401, details || {
89
+ suggestion: "Click the verification link sent to your email address",
90
+ canResend: true
91
+ }, false);
92
+ Object.setPrototypeOf(this, EmailVerificationRequiredError.prototype);
93
+ }
94
+ };
95
+ /**
69
96
  * Thrown when a resource is not found (404).
70
97
  */
71
98
  var NotFoundError = class NotFoundError extends SnackBaseError {
@@ -319,9 +346,9 @@ var Logger = class {
319
346
  constructor(level = LogLevel.NONE) {
320
347
  this.level = level;
321
348
  this.handlers.push((entry) => {
322
- const { level: level$1, message, data } = entry;
349
+ const { level, message, data } = entry;
323
350
  const args = data ? [message, data] : [message];
324
- switch (level$1) {
351
+ switch (level) {
325
352
  case LogLevel.ERROR:
326
353
  console.error("[SnackBase]", ...args);
327
354
  break;
@@ -389,7 +416,9 @@ const contentTypeInterceptor = (request) => {
389
416
  const createAuthInterceptor = (getToken, apiKey) => {
390
417
  return (request) => {
391
418
  const isUserSpecific = request.url.includes("/auth/oauth/") || request.url.includes("/auth/saml/");
392
- if (apiKey && !isUserSpecific) request.headers["X-API-Key"] = apiKey;
419
+ if (apiKey && !isUserSpecific) {
420
+ if (!(request.url.includes("/auth/login") || request.url.includes("/auth/register"))) request.headers["X-API-Key"] = apiKey;
421
+ }
393
422
  const token = getToken();
394
423
  if (token) request.headers["Authorization"] = `Bearer ${token}`;
395
424
  return request;
@@ -433,6 +462,51 @@ function createErrorFromResponse(response) {
433
462
  return new SnackBaseError(message, "UNKNOWN_ERROR", status, data, false);
434
463
  }
435
464
  }
465
+ /**
466
+ * Enhanced error interceptor to handle 403 API key errors and preserve redirects.
467
+ */
468
+ const createAuthErrorInterceptor = (onAuthError) => {
469
+ return (error) => {
470
+ if (error.status === 403 && error.details) {
471
+ const detail = error.details.detail || error.details.message || "";
472
+ if (detail.includes("superadmin") || detail.includes("restricted")) {
473
+ const restrictedError = new ApiKeyRestrictedError(detail, error.details);
474
+ if (onAuthError) onAuthError(restrictedError);
475
+ throw restrictedError;
476
+ }
477
+ }
478
+ if (error.status === 403 && error.details?.redirect_url) {
479
+ error.redirectUrl = error.details.redirect_url;
480
+ error.authProvider = error.details.auth_provider;
481
+ error.providerName = error.details.provider_name;
482
+ }
483
+ if (error.status === 401 && error.details) {
484
+ const detail = error.details.detail || error.details.message || "";
485
+ if (detail.includes("verify") || detail.includes("email")) {
486
+ const verificationError = new EmailVerificationRequiredError(detail, error.details);
487
+ if (onAuthError) onAuthError(verificationError);
488
+ throw verificationError;
489
+ }
490
+ }
491
+ if (error.status === 401 || error.status === 403) {
492
+ if (onAuthError) onAuthError(error);
493
+ }
494
+ throw error;
495
+ };
496
+ };
497
+
498
+ //#endregion
499
+ //#region src/types/auth.ts
500
+ /**
501
+ * Token type enum matching backend TokenType
502
+ */
503
+ let TokenType = /* @__PURE__ */ function(TokenType) {
504
+ TokenType["JWT"] = "jwt";
505
+ TokenType["API_KEY"] = "api_key";
506
+ TokenType["PERSONAL_TOKEN"] = "personal_token";
507
+ TokenType["OAUTH"] = "oauth";
508
+ return TokenType;
509
+ }({});
436
510
 
437
511
  //#endregion
438
512
  //#region src/core/events.ts
@@ -453,6 +527,74 @@ var AuthEventEmitter = class {
453
527
  }
454
528
  };
455
529
 
530
+ //#endregion
531
+ //#region src/core/constants.ts
532
+ /**
533
+ * System account ID for superadmin detection
534
+ * Nil UUID format used by backend
535
+ * @see https://github.com/snackbase/snackbase/blob/main/src/snackbase/infrastructure/api/middleware/authorization.py
536
+ */
537
+ const SYSTEM_ACCOUNT_ID = "00000000-0000-0000-0000-000000000000";
538
+ /**
539
+ * Token type prefixes matching backend TokenCodec
540
+ */
541
+ const TOKEN_PREFIXES = {
542
+ JWT: "sb_jwt",
543
+ API_KEY: "sb_ak",
544
+ PERSONAL_TOKEN: "sb_pt",
545
+ OAUTH: "sb_ot"
546
+ };
547
+ /**
548
+ * Valid token prefixes for validation
549
+ */
550
+ const VALID_TOKEN_PREFIXES = new Set(Object.values(TOKEN_PREFIXES));
551
+ /**
552
+ * API key endpoint path
553
+ */
554
+ const API_KEY_BASE_PATH = "/api/v1/admin/api-keys";
555
+
556
+ //#endregion
557
+ //#region src/utils/token-utils.ts
558
+ /**
559
+ * Detect token type from token string
560
+ * @param token - The token to analyze
561
+ * @returns Detected token type or undefined
562
+ */
563
+ function detectTokenType(token) {
564
+ if (!token) return void 0;
565
+ switch (token.split(".")[0]) {
566
+ case TOKEN_PREFIXES.API_KEY: return TokenType.API_KEY;
567
+ case TOKEN_PREFIXES.PERSONAL_TOKEN: return TokenType.PERSONAL_TOKEN;
568
+ case TOKEN_PREFIXES.OAUTH: return TokenType.OAUTH;
569
+ case TOKEN_PREFIXES.JWT: return TokenType.JWT;
570
+ default: return token.startsWith("ey") ? TokenType.JWT : void 0;
571
+ }
572
+ }
573
+ /**
574
+ * Check if user is a superadmin
575
+ * @param user - User object to check
576
+ * @returns true if user is superadmin
577
+ */
578
+ function isSuperadmin(user) {
579
+ if (!user) return false;
580
+ return user.account_id === SYSTEM_ACCOUNT_ID;
581
+ }
582
+ /**
583
+ * Format masked API key for display
584
+ * @param key - The full or masked key
585
+ * @returns Formatted masked key
586
+ */
587
+ function formatMaskedKey(key) {
588
+ if (!key) return "";
589
+ if (key.includes("...")) return key;
590
+ const parts = key.split(".");
591
+ if (parts.length === 3) {
592
+ const [, payload, signature] = parts;
593
+ return `${parts[0]}.${payload.slice(0, 4)}...${signature.slice(-4)}`;
594
+ }
595
+ return key;
596
+ }
597
+
456
598
  //#endregion
457
599
  //#region src/core/auth.ts
458
600
  const DEFAULT_AUTH_STATE = {
@@ -461,7 +603,8 @@ const DEFAULT_AUTH_STATE = {
461
603
  token: null,
462
604
  refreshToken: null,
463
605
  isAuthenticated: false,
464
- expiresAt: null
606
+ expiresAt: null,
607
+ tokenType: TokenType.JWT
465
608
  };
466
609
  var AuthManager = class {
467
610
  state = { ...DEFAULT_AUTH_STATE };
@@ -495,6 +638,76 @@ var AuthManager = class {
495
638
  get isAuthenticated() {
496
639
  return this.state.isAuthenticated;
497
640
  }
641
+ get tokenType() {
642
+ return this.state.tokenType;
643
+ }
644
+ /**
645
+ * Update auth state (enhanced to extract token_type)
646
+ */
647
+ async updateState(data) {
648
+ const user = data.user || (data.user_id ? {
649
+ id: data.user_id,
650
+ email: data.email || "",
651
+ role: data.role || "user",
652
+ account_id: data.account_id || "",
653
+ groups: [],
654
+ is_active: true,
655
+ created_at: "",
656
+ last_login: null,
657
+ token_type: TokenType.JWT
658
+ } : null);
659
+ const token = data.token || null;
660
+ const refreshToken = data.refresh_token || data.refreshToken || null;
661
+ let tokenType = TokenType.JWT;
662
+ if (token) tokenType = detectTokenType(token) || TokenType.JWT;
663
+ else if (user?.token_type) tokenType = user.token_type;
664
+ this.state = {
665
+ ...this.state,
666
+ user,
667
+ account: data.account || (data.account_id ? {
668
+ id: data.account_id,
669
+ slug: "",
670
+ name: "",
671
+ created_at: ""
672
+ } : this.state.account),
673
+ token: token || this.state.token,
674
+ refreshToken: refreshToken || this.state.refreshToken,
675
+ isAuthenticated: !!((token || this.state.token) && user),
676
+ expiresAt: this.calculateExpiry(data) || this.state.expiresAt,
677
+ tokenType
678
+ };
679
+ await this.persist();
680
+ if (token || user) this.events.emit("auth:login", this.state);
681
+ }
682
+ /**
683
+ * Check if current user is superadmin
684
+ */
685
+ isSuperadmin() {
686
+ return isSuperadmin(this.state.user);
687
+ }
688
+ /**
689
+ * Check if current session uses API key authentication
690
+ */
691
+ isApiKeySession() {
692
+ return this.state.tokenType === TokenType.API_KEY;
693
+ }
694
+ /**
695
+ * Check if current session uses personal token authentication
696
+ */
697
+ isPersonalTokenSession() {
698
+ return this.state.tokenType === TokenType.PERSONAL_TOKEN;
699
+ }
700
+ /**
701
+ * Check if current session uses OAuth authentication
702
+ */
703
+ isOAuthSession() {
704
+ return this.state.tokenType === TokenType.OAUTH;
705
+ }
706
+ calculateExpiry(data) {
707
+ if (data.expiresAt) return data.expiresAt;
708
+ if (data.expires_in) return new Date(Date.now() + data.expires_in * 1e3).toISOString();
709
+ return null;
710
+ }
498
711
  async setState(newState) {
499
712
  this.state = {
500
713
  ...this.state,
@@ -568,13 +781,8 @@ var AuthService = class {
568
781
  const data = { ...credentials };
569
782
  if (!data.account && this.defaultAccount) data.account = this.defaultAccount;
570
783
  const authData = (await this.http.post("/api/v1/auth/login", data)).data;
571
- await this.auth.setState({
572
- user: authData.user,
573
- account: authData.account,
574
- token: authData.token,
575
- refreshToken: authData.refreshToken,
576
- expiresAt: authData.expiresAt
577
- });
784
+ console.log("Login Response:", JSON.stringify(authData, null, 2));
785
+ await this.auth.updateState(authData);
578
786
  return authData;
579
787
  }
580
788
  /**
@@ -582,7 +790,7 @@ var AuthService = class {
582
790
  */
583
791
  async register(data) {
584
792
  const payload = { ...data };
585
- if (!payload.accountName && this.defaultAccount) payload.accountName = this.defaultAccount;
793
+ if (!payload.account_name && this.defaultAccount) payload.account_name = this.defaultAccount;
586
794
  return (await this.http.post("/api/v1/auth/register", payload)).data;
587
795
  }
588
796
  /**
@@ -591,14 +799,8 @@ var AuthService = class {
591
799
  async refreshToken() {
592
800
  const refreshToken = this.auth.refreshToken;
593
801
  if (!refreshToken) throw new Error("No refresh token available");
594
- const authData = (await this.http.post("/api/v1/auth/refresh", { refreshToken })).data;
595
- await this.auth.setState({
596
- user: authData.user,
597
- account: authData.account,
598
- token: authData.token,
599
- refreshToken: authData.refreshToken,
600
- expiresAt: authData.expiresAt
601
- });
802
+ const authData = (await this.http.post("/api/v1/auth/refresh", { refresh_token: refreshToken })).data;
803
+ await this.auth.updateState(authData);
602
804
  return authData;
603
805
  }
604
806
  /**
@@ -617,10 +819,8 @@ var AuthService = class {
617
819
  */
618
820
  async getCurrentUser() {
619
821
  const authData = (await this.http.get("/api/v1/auth/me")).data;
620
- await this.auth.setState({
621
- user: authData.user,
622
- account: authData.account
623
- });
822
+ console.log("GetMe Response:", JSON.stringify(authData, null, 2));
823
+ await this.auth.updateState(authData);
624
824
  return authData;
625
825
  }
626
826
  /**
@@ -694,13 +894,7 @@ var AuthService = class {
694
894
  redirectUri,
695
895
  state
696
896
  })).data;
697
- await this.auth.setState({
698
- user: authData.user,
699
- account: authData.account,
700
- token: authData.token,
701
- refreshToken: authData.refreshToken,
702
- expiresAt: authData.expiresAt
703
- });
897
+ await this.auth.updateState(authData);
704
898
  return authData;
705
899
  }
706
900
  /**
@@ -719,13 +913,7 @@ var AuthService = class {
719
913
  */
720
914
  async handleSAMLCallback(params) {
721
915
  const authData = (await this.http.post("/api/v1/auth/saml/acs", params)).data;
722
- await this.auth.setState({
723
- user: authData.user,
724
- account: authData.account,
725
- token: authData.token,
726
- refreshToken: authData.refreshToken,
727
- expiresAt: authData.expiresAt
728
- });
916
+ await this.auth.updateState(authData);
729
917
  return authData;
730
918
  }
731
919
  /**
@@ -907,6 +1095,62 @@ var CollectionService = class {
907
1095
  await this.http.delete(`/api/v1/collections/${collectionId}`);
908
1096
  return { success: true };
909
1097
  }
1098
+ /**
1099
+ * Export collections to JSON format.
1100
+ * Returns collection schemas and rules for backup or migration.
1101
+ *
1102
+ * @param params Optional filter by collection IDs
1103
+ * @returns Complete export data structure with collections, schemas, and rules
1104
+ * @throws {AuthorizationError} If user is not a superadmin
1105
+ *
1106
+ * @example
1107
+ * // Export all collections
1108
+ * const exportData = await client.collections.export();
1109
+ *
1110
+ * @example
1111
+ * // Export specific collections
1112
+ * const exportData = await client.collections.export({
1113
+ * collection_ids: ['col-123', 'col-456']
1114
+ * });
1115
+ */
1116
+ async export(params) {
1117
+ const queryParams = {};
1118
+ if (params?.collection_ids && params.collection_ids.length > 0) queryParams.collection_ids = params.collection_ids.join(",");
1119
+ return (await this.http.get("/api/v1/collections/export", { params: queryParams })).data;
1120
+ }
1121
+ /**
1122
+ * Import collections from JSON export.
1123
+ *
1124
+ * @param request Import request with data and conflict strategy
1125
+ * @returns Import result with per-collection status and migration IDs
1126
+ * @throws {ValidationError} If import data is invalid
1127
+ * @throws {ConflictError} If collection exists and strategy is 'error'
1128
+ * @throws {AuthorizationError} If user is not a superadmin
1129
+ *
1130
+ * @example
1131
+ * // Import with error strategy (fail on conflicts)
1132
+ * const result = await client.collections.import({
1133
+ * data: exportData,
1134
+ * strategy: 'error'
1135
+ * });
1136
+ *
1137
+ * @example
1138
+ * // Import with skip strategy (skip existing collections)
1139
+ * const result = await client.collections.import({
1140
+ * data: exportData,
1141
+ * strategy: 'skip'
1142
+ * });
1143
+ *
1144
+ * @example
1145
+ * // Import with update strategy (update existing collections)
1146
+ * const result = await client.collections.import({
1147
+ * data: exportData,
1148
+ * strategy: 'update'
1149
+ * });
1150
+ */
1151
+ async import(request) {
1152
+ return (await this.http.post("/api/v1/collections/import", request)).data;
1153
+ }
910
1154
  };
911
1155
 
912
1156
  //#endregion
@@ -1090,7 +1334,14 @@ var RecordService = class {
1090
1334
  if (params.sort !== void 0) formattedParams.sort = params.sort;
1091
1335
  if (params.fields) formattedParams.fields = Array.isArray(params.fields) ? params.fields.join(",") : params.fields;
1092
1336
  if (params.expand) formattedParams.expand = Array.isArray(params.expand) ? params.expand.join(",") : params.expand;
1093
- if (params.filter) formattedParams.filter = typeof params.filter === "string" ? params.filter : JSON.stringify(params.filter);
1337
+ if (params.filter) {
1338
+ const filterStr = typeof params.filter === "string" ? params.filter : JSON.stringify(params.filter);
1339
+ const match = filterStr.match(/^\(?\s*(\w+)\s*=\s*(["']?)([^"'\)]+)\2\s*\)?$/);
1340
+ if (match) {
1341
+ const [, key, , value] = match;
1342
+ formattedParams[key] = value;
1343
+ } else formattedParams.filter = filterStr;
1344
+ }
1094
1345
  }
1095
1346
  return (await this.http.get(`/api/v1/records/${collection}`, { params: formattedParams })).data;
1096
1347
  }
@@ -1276,33 +1527,34 @@ var ApiKeyService = class {
1276
1527
  this.http = http;
1277
1528
  }
1278
1529
  /**
1279
- * List all API keys for the current user.
1280
- * Keys are masked except for the last 4 characters.
1530
+ * List all API keys
1531
+ * GET /api/v1/admin/api-keys
1281
1532
  */
1282
- async list() {
1283
- return (await this.http.get("/api/v1/admin/api-keys")).data;
1533
+ async list(params) {
1534
+ return (await this.http.get(API_KEY_BASE_PATH, { params })).data;
1284
1535
  }
1285
1536
  /**
1286
- * Get details for a specific API key.
1287
- * The key itself is masked.
1537
+ * Get specific API key
1538
+ * GET /api/v1/admin/api-keys/{id}
1288
1539
  */
1289
1540
  async get(keyId) {
1290
- return (await this.http.get(`/api/v1/admin/api-keys/${keyId}`)).data;
1541
+ return (await this.http.get(`${API_KEY_BASE_PATH}/${encodeURIComponent(keyId)}`)).data;
1291
1542
  }
1292
1543
  /**
1293
- * Create a new API key.
1294
- * The response includes the full key, which is shown only once.
1544
+ * Create a new API key
1545
+ * POST /api/v1/admin/api-keys
1295
1546
  */
1296
1547
  async create(data) {
1297
- return (await this.http.post("/api/v1/admin/api-keys", data)).data;
1548
+ const apiKey = (await this.http.post(API_KEY_BASE_PATH, data)).data;
1549
+ if (apiKey.key && !apiKey.masked_key) apiKey.masked_key = formatMaskedKey(apiKey.key);
1550
+ return apiKey;
1298
1551
  }
1299
1552
  /**
1300
- * Revoke an existing API key.
1301
- * Once revoked, the key can no longer be used.
1553
+ * Revoke an API key
1554
+ * DELETE /api/v1/admin/api-keys/{id}
1302
1555
  */
1303
1556
  async revoke(keyId) {
1304
- await this.http.delete(`/api/v1/admin/api-keys/${keyId}`);
1305
- return { success: true };
1557
+ return (await this.http.delete(`${API_KEY_BASE_PATH}/${encodeURIComponent(keyId)}`)).data;
1306
1558
  }
1307
1559
  };
1308
1560
 
@@ -1325,7 +1577,25 @@ var AuditLogService = class {
1325
1577
  return (await this.httpClient.get(`/api/v1/audit-logs/${logId}`)).data;
1326
1578
  }
1327
1579
  /**
1328
- * Exports audit logs in the specified format.
1580
+ * Exports audit logs in the specified format (JSON, CSV, or PDF).
1581
+ *
1582
+ * @param params Optional filters (account_id, table_name, operation, date range, etc.)
1583
+ * @param format Export format: 'json', 'csv', or 'pdf' (default: 'json')
1584
+ * @returns Exported data as string (base64-encoded for PDF format)
1585
+ * @throws {AuthorizationError} If user is not a superadmin
1586
+ *
1587
+ * @example
1588
+ * // Export as JSON
1589
+ * const jsonData = await client.auditLogs.export({ table_name: 'users' }, 'json');
1590
+ *
1591
+ * @example
1592
+ * // Export as CSV
1593
+ * const csvData = await client.auditLogs.export({ table_name: 'users' }, 'csv');
1594
+ *
1595
+ * @example
1596
+ * // Export as PDF
1597
+ * const pdfBase64 = await client.auditLogs.export({ table_name: 'users' }, 'pdf');
1598
+ * // pdfBase64 is a base64-encoded PDF string
1329
1599
  */
1330
1600
  async export(params, format = "json") {
1331
1601
  return (await this.httpClient.get("/api/v1/audit-logs/export", { params: {
@@ -2278,6 +2548,7 @@ var SnackBaseClient = class {
2278
2548
  this.http.addRequestInterceptor(contentTypeInterceptor);
2279
2549
  this.http.addRequestInterceptor(createAuthInterceptor(() => this.authManager.token || void 0, this.config.apiKey));
2280
2550
  this.http.addResponseInterceptor(errorNormalizationInterceptor);
2551
+ this.http.addErrorInterceptor(createAuthErrorInterceptor(this.config.onAuthError));
2281
2552
  this.http.addErrorInterceptor(errorInterceptor);
2282
2553
  }
2283
2554
  /**
@@ -2299,6 +2570,36 @@ var SnackBaseClient = class {
2299
2570
  return this.authManager.isAuthenticated;
2300
2571
  }
2301
2572
  /**
2573
+ * Check if current user is superadmin.
2574
+ */
2575
+ get isSuperadmin() {
2576
+ return this.authManager.isSuperadmin();
2577
+ }
2578
+ /**
2579
+ * Check if current session uses API key authentication.
2580
+ */
2581
+ get isApiKeySession() {
2582
+ return this.authManager.isApiKeySession();
2583
+ }
2584
+ /**
2585
+ * Check if current session uses personal token authentication.
2586
+ */
2587
+ get isPersonalTokenSession() {
2588
+ return this.authManager.isPersonalTokenSession();
2589
+ }
2590
+ /**
2591
+ * Check if current session uses OAuth authentication.
2592
+ */
2593
+ get isOAuthSession() {
2594
+ return this.authManager.isOAuthSession();
2595
+ }
2596
+ /**
2597
+ * Returns the current token type.
2598
+ */
2599
+ get tokenType() {
2600
+ return this.authManager.tokenType;
2601
+ }
2602
+ /**
2302
2603
  * Access to authentication methods.
2303
2604
  */
2304
2605
  get auth() {
@@ -2513,4 +2814,4 @@ var SnackBaseClient = class {
2513
2814
  };
2514
2815
 
2515
2816
  //#endregion
2516
- export { DEFAULT_CONFIG, QueryBuilder, SnackBaseClient, getAutoDetectedStorage };
2817
+ export { ApiKeyRestrictedError, AuthenticationError, AuthorizationError, ConflictError, DEFAULT_CONFIG, EmailVerificationRequiredError, NetworkError, NotFoundError, QueryBuilder, RateLimitError, ServerError, SnackBaseClient, SnackBaseError, TimeoutError, TokenType, ValidationError, getAutoDetectedStorage };
package/package.json CHANGED
@@ -1,48 +1,43 @@
1
1
  {
2
2
  "name": "@snackbase/sdk",
3
- "version": "0.1.1",
4
- "description": "JavaScript/TypeScript SDK for SnackBase",
3
+ "version": "0.3.0",
4
+ "description": "Core SDK for SnackBase",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.cts",
5
8
  "exports": {
6
9
  ".": {
7
- "import": "./dist/index.mjs",
8
- "require": "./dist/index.js",
9
- "types": "./dist/index.d.ts"
10
- },
11
- "./react": {
12
- "import": "./dist/react/index.mjs",
13
- "require": "./dist/react/index.js",
14
- "types": "./dist/react/index.d.ts"
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
15
18
  }
16
19
  },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "snackbase",
25
+ "sdk",
26
+ "database"
27
+ ],
28
+ "author": "SnackBase Team",
29
+ "license": "MIT",
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "devDependencies": {
34
+ "@snackbase/tsconfig": "0.1.0"
35
+ },
17
36
  "scripts": {
18
- "dev": "tsdown src/index.ts src/react/index.ts --watch",
19
- "build": "tsdown src/index.ts src/react/index.ts",
37
+ "dev": "tsdown src/index.ts --format esm,cjs --watch",
38
+ "build": "tsdown src/index.ts --format esm,cjs --dts",
20
39
  "test": "vitest run",
21
- "test:watch": "vitest",
22
- "test:integration": "vitest run --config vitest.integration.config.ts",
23
- "test:coverage": "vitest run --coverage",
24
40
  "typecheck": "tsc --noEmit",
25
- "lint": "eslint src --ext .ts,.tsx",
26
- "prepublishOnly": "npm run build && npm run test"
27
- },
28
- "peerDependencies": {
29
- "react": "^18.0.0 || ^19.0.0"
30
- },
31
- "peerDependenciesMeta": {
32
- "react": {
33
- "optional": true
34
- }
35
- },
36
- "devDependencies": {
37
- "@testing-library/jest-dom": "^6.9.1",
38
- "@testing-library/react": "^16.3.2",
39
- "@vitejs/plugin-react": "^5.1.2",
40
- "jsdom": "^27.4.0",
41
- "react": "^18.2.0",
42
- "react-dom": "^18.2.0",
43
- "tsdown": "^0.20.0-beta.4",
44
- "typescript": "^5.3.3",
45
- "vite": "^7.3.1",
46
- "vitest": "^1.2.1"
41
+ "clean": "rm -rf dist"
47
42
  }
48
- }
43
+ }