appbuild-oceanbase-console 1.11.0 → 1.12.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/cjs/sdk.js CHANGED
@@ -434,9 +434,9 @@ Query.notTouches = (attribute, values) => new Query("notTouches", attribute, [va
434
434
  /**
435
435
  * Environment detection helpers
436
436
  */
437
- const isBrowser = typeof window !== 'undefined';
437
+ const isBrowser$1 = typeof window !== 'undefined';
438
438
  // Memory storage for server-side environment
439
- class MemoryStorage {
439
+ class MemoryStorage$1 {
440
440
  constructor() {
441
441
  this.data = new Map();
442
442
  }
@@ -450,9 +450,9 @@ class MemoryStorage {
450
450
  this.data.delete(key);
451
451
  }
452
452
  }
453
- const memoryStorage = new MemoryStorage();
454
- const getStorage = () => isBrowser ? window.localStorage : memoryStorage;
455
- const getLocation = () => isBrowser ? window.location : { host: 'nodejs' };
453
+ const memoryStorage$1 = new MemoryStorage$1();
454
+ const getStorage$1 = () => isBrowser$1 ? window.localStorage : memoryStorage$1;
455
+ const getLocation = () => isBrowser$1 ? window.location : { host: 'nodejs' };
456
456
  const getWebSocket = () => {
457
457
  if (typeof WebSocket !== 'undefined')
458
458
  return WebSocket;
@@ -619,7 +619,7 @@ class Client {
619
619
  case 'connected':
620
620
  let session = this.config.session;
621
621
  if (!session) {
622
- const storage = getStorage();
622
+ const storage = getStorage$1();
623
623
  const cookieFallback = storage.getItem('cookieFallback');
624
624
  if (cookieFallback) {
625
625
  const cookie = JSON.parse(cookieFallback);
@@ -772,6 +772,19 @@ class Client {
772
772
  this.config.mode = value;
773
773
  return this;
774
774
  }
775
+ /**
776
+ * Set Session Refresh Handler
777
+ *
778
+ * Set a callback function that will be called when a 401 error is detected.
779
+ * This allows automatic re-login when session expires.
780
+ *
781
+ * @param handler Function that returns a Promise to refresh the session
782
+ * @returns {this}
783
+ */
784
+ setSessionRefreshHandler(handler) {
785
+ this.sessionRefreshHandler = handler;
786
+ return this;
787
+ }
775
788
  /**
776
789
  * Subscribes to Appwrite events and passes you the payload in realtime.
777
790
  *
@@ -818,7 +831,7 @@ class Client {
818
831
  prepareRequest(method, url, headers = {}, params = {}) {
819
832
  method = method.toUpperCase();
820
833
  headers = Object.assign({}, this.headers, headers);
821
- const storage = getStorage();
834
+ const storage = getStorage$1();
822
835
  const cookieFallback = storage.getItem('cookieFallback');
823
836
  if (cookieFallback) {
824
837
  headers['X-Fallback-Cookies'] = cookieFallback;
@@ -906,7 +919,7 @@ class Client {
906
919
  return this.call('GET', new URL(this.config.endpoint + '/ping'));
907
920
  });
908
921
  }
909
- call(method, url, headers = {}, params = {}, responseType = 'json') {
922
+ call(method, url, headers = {}, params = {}, responseType = 'json', retryOn401 = true) {
910
923
  var _a, _b;
911
924
  return __awaiter(this, void 0, void 0, function* () {
912
925
  const { uri, options } = this.prepareRequest(method, url, headers, params);
@@ -950,6 +963,17 @@ class Client {
950
963
  };
951
964
  }
952
965
  if (400 <= response.status) {
966
+ // Handle 401 Unauthorized with automatic re-login
967
+ if (response.status === 401 && retryOn401 && this.sessionRefreshHandler) {
968
+ try {
969
+ yield this.sessionRefreshHandler();
970
+ // Retry the request once after re-login
971
+ return this.call(method, url, headers, params, responseType, false);
972
+ }
973
+ catch (refreshError) {
974
+ // If refresh fails, throw the original 401 error
975
+ }
976
+ }
953
977
  let responseText = '';
954
978
  if (((_b = response.headers.get('content-type')) === null || _b === void 0 ? void 0 : _b.includes('application/json')) || responseType === 'arrayBuffer') {
955
979
  responseText = JSON.stringify(data);
@@ -961,9 +985,9 @@ class Client {
961
985
  }
962
986
  const cookieFallback = response.headers.get('X-Fallback-Cookies');
963
987
  if (cookieFallback) {
964
- const storage = getStorage();
988
+ const storage = getStorage$1();
965
989
  storage.setItem('cookieFallback', cookieFallback);
966
- if (isBrowser) {
990
+ if (isBrowser$1) {
967
991
  console.warn('Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');
968
992
  }
969
993
  }
@@ -13943,6 +13967,26 @@ class Role {
13943
13967
  }
13944
13968
  }
13945
13969
 
13970
+ /**
13971
+ * Exception thrown when migration execution fails
13972
+ * Contains information about all failed operations
13973
+ */
13974
+ class MigrationExecutionException extends Error {
13975
+ constructor(failedOperations, totalOperations) {
13976
+ const failedCount = failedOperations.length;
13977
+ const succeededCount = totalOperations - failedCount;
13978
+ const errorMessages = failedOperations.map(fo => ` - ${fo.operation.type} for collection ${fo.operation.collectionId}: ${fo.errorMessage}`).join('\n');
13979
+ const message = `Migration execution completed with ${failedCount} failure(s) out of ${totalOperations} operation(s).\n` +
13980
+ `Succeeded: ${succeededCount}, Failed: ${failedCount}\n\n` +
13981
+ `Failed operations:\n${errorMessages}`;
13982
+ super(message);
13983
+ this.name = 'MigrationExecutionException';
13984
+ this.failedOperations = failedOperations;
13985
+ this.totalOperations = totalOperations;
13986
+ this.succeededOperations = succeededCount;
13987
+ this.failedOperationsCount = failedCount;
13988
+ }
13989
+ }
13946
13990
  /**
13947
13991
  * Database Schema Migration Tool
13948
13992
  *
@@ -13968,10 +14012,24 @@ class SchemaMigration {
13968
14012
  }
13969
14013
  /**
13970
14014
  * Check if an attribute key is a built-in field that cannot be modified
13971
- * Built-in fields: id, createdAt, updatedAt
14015
+ * Built-in fields include:
14016
+ * - Fields starting with '$' prefix (e.g., $id, $createdAt, $updatedAt)
14017
+ * - Legacy field names: id, createdAt, updatedAt
13972
14018
  */
13973
14019
  isBuiltInAttribute(key) {
13974
- return key === 'id' || key === 'createdAt' || key === 'updatedAt' || key === '$id' || key === '$createdAt' || key === '$updatedAt';
14020
+ // Check if starts with '$' prefix (all system/built-in fields)
14021
+ if (key.startsWith('$')) {
14022
+ return true;
14023
+ }
14024
+ // Legacy field names for backwards compatibility
14025
+ return key === 'id' || key === 'createdAt' || key === 'updatedAt';
14026
+ }
14027
+ /**
14028
+ * Check if an index key is a built-in index that cannot be modified
14029
+ * Built-in indexes start with '$' prefix
14030
+ */
14031
+ isBuiltInIndex(key) {
14032
+ return key.startsWith('$');
13975
14033
  }
13976
14034
  /**
13977
14035
  * Check if an index contains any built-in attributes
@@ -13989,6 +14047,7 @@ class SchemaMigration {
13989
14047
  // Store schema for later use in execution
13990
14048
  this._currentSchema = schema;
13991
14049
  const operations = [];
14050
+ const skippedBuiltIns = [];
13992
14051
  // If databaseId is empty, create a database with id "default"
13993
14052
  let databaseId = schema.databaseId;
13994
14053
  if (!databaseId || databaseId.trim() === '') {
@@ -14034,8 +14093,14 @@ class SchemaMigration {
14034
14093
  // For new tables, create all attributes and indexes
14035
14094
  // Process target attributes
14036
14095
  for (const targetAttr of targetCollection.attributes) {
14037
- // Skip built-in attributes (id, createdAt, updatedAt)
14096
+ // Skip built-in attributes (starting with '$' or legacy names)
14038
14097
  if (this.isBuiltInAttribute(targetAttr.key)) {
14098
+ skippedBuiltIns.push({
14099
+ collectionId: collectionId,
14100
+ key: targetAttr.key,
14101
+ type: 'attribute',
14102
+ reason: `Built-in column '${targetAttr.key}' is automatically managed by the system`
14103
+ });
14039
14104
  continue;
14040
14105
  }
14041
14106
  operations.push({
@@ -14049,9 +14114,24 @@ class SchemaMigration {
14049
14114
  // Process target indexes
14050
14115
  if (targetCollection.indexes) {
14051
14116
  for (const targetIndex of targetCollection.indexes) {
14117
+ // Skip built-in indexes (starting with '$')
14118
+ if (this.isBuiltInIndex(targetIndex.key)) {
14119
+ skippedBuiltIns.push({
14120
+ collectionId: collectionId,
14121
+ key: targetIndex.key,
14122
+ type: 'index',
14123
+ reason: `Built-in index '${targetIndex.key}' is automatically managed by the system`
14124
+ });
14125
+ continue;
14126
+ }
14052
14127
  // Skip indexes that contain built-in attributes
14053
14128
  if (this.indexContainsBuiltInAttributes(targetIndex)) {
14054
- console.log(`Skipping index ${targetIndex.key} because it contains built-in attributes`);
14129
+ skippedBuiltIns.push({
14130
+ collectionId: collectionId,
14131
+ key: targetIndex.key,
14132
+ type: 'index',
14133
+ reason: `Index '${targetIndex.key}' references built-in columns and is automatically managed`
14134
+ });
14055
14135
  continue;
14056
14136
  }
14057
14137
  operations.push({
@@ -14090,8 +14170,14 @@ class SchemaMigration {
14090
14170
  });
14091
14171
  // Process target attributes
14092
14172
  for (const targetAttr of targetCollection.attributes) {
14093
- // Skip built-in attributes (id, createdAt, updatedAt)
14173
+ // Skip built-in attributes (starting with '$' or legacy names)
14094
14174
  if (this.isBuiltInAttribute(targetAttr.key)) {
14175
+ skippedBuiltIns.push({
14176
+ collectionId: collectionId,
14177
+ key: targetAttr.key,
14178
+ type: 'attribute',
14179
+ reason: `Built-in column '${targetAttr.key}' is automatically managed by the system`
14180
+ });
14095
14181
  continue;
14096
14182
  }
14097
14183
  const currentCol = currentColumnsMap.get(targetAttr.key);
@@ -14129,8 +14215,9 @@ class SchemaMigration {
14129
14215
  }
14130
14216
  // Check for columns to delete (columns in current but not in target)
14131
14217
  for (const [key, currentAttr] of currentColumnsMap.entries()) {
14132
- // Skip built-in attributes (id, createdAt, updatedAt)
14218
+ // Skip built-in attributes (starting with '$' or legacy names)
14133
14219
  if (this.isBuiltInAttribute(key)) {
14220
+ // Don't add to skippedBuiltIns here since these are existing columns, not from target schema
14134
14221
  continue;
14135
14222
  }
14136
14223
  const targetAttr = targetCollection.attributes.find(a => a.key === key);
@@ -14157,9 +14244,24 @@ class SchemaMigration {
14157
14244
  });
14158
14245
  // Process target indexes
14159
14246
  for (const targetIndex of targetCollection.indexes) {
14247
+ // Skip built-in indexes (starting with '$')
14248
+ if (this.isBuiltInIndex(targetIndex.key)) {
14249
+ skippedBuiltIns.push({
14250
+ collectionId: collectionId,
14251
+ key: targetIndex.key,
14252
+ type: 'index',
14253
+ reason: `Built-in index '${targetIndex.key}' is automatically managed by the system`
14254
+ });
14255
+ continue;
14256
+ }
14160
14257
  // Skip indexes that contain built-in attributes
14161
14258
  if (this.indexContainsBuiltInAttributes(targetIndex)) {
14162
- console.log(`Skipping index ${targetIndex.key} because it contains built-in attributes`);
14259
+ skippedBuiltIns.push({
14260
+ collectionId: collectionId,
14261
+ key: targetIndex.key,
14262
+ type: 'index',
14263
+ reason: `Index '${targetIndex.key}' references built-in columns and is automatically managed`
14264
+ });
14163
14265
  continue;
14164
14266
  }
14165
14267
  const currentIndex = currentIndexesMap.get(targetIndex.key);
@@ -14197,10 +14299,15 @@ class SchemaMigration {
14197
14299
  }
14198
14300
  // Check for indexes to delete
14199
14301
  for (const [key, currentIndex] of currentIndexesMap.entries()) {
14302
+ // Skip built-in indexes (starting with '$')
14303
+ if (this.isBuiltInIndex(key)) {
14304
+ // Don't add to skippedBuiltIns here since these are existing indexes, not from target schema
14305
+ continue;
14306
+ }
14200
14307
  // Skip indexes that contain built-in attributes
14201
14308
  const indexAttributes = currentIndex.columns || [];
14202
14309
  if (indexAttributes.some((attr) => this.isBuiltInAttribute(attr))) {
14203
- console.log(`Skipping deletion of index ${key} because it contains built-in attributes`);
14310
+ // Don't add to skippedBuiltIns here since these are existing indexes
14204
14311
  continue;
14205
14312
  }
14206
14313
  const targetIndex = targetCollection.indexes.find(i => i.key === key);
@@ -14242,7 +14349,8 @@ class SchemaMigration {
14242
14349
  };
14243
14350
  return {
14244
14351
  operations,
14245
- summary
14352
+ summary,
14353
+ skippedBuiltIns
14246
14354
  };
14247
14355
  });
14248
14356
  }
@@ -14347,22 +14455,60 @@ class SchemaMigration {
14347
14455
  plan.operations.forEach((op, index) => {
14348
14456
  console.log(`${index + 1}. [${op.type}] ${op.reason}`);
14349
14457
  });
14458
+ // Display skipped built-in items
14459
+ if (plan.skippedBuiltIns && plan.skippedBuiltIns.length > 0) {
14460
+ console.log('\n=== SKIPPED BUILT-IN ITEMS ===');
14461
+ console.log('The following items are built-in (starting with "$") and automatically managed by the system:');
14462
+ const skippedAttributes = plan.skippedBuiltIns.filter(item => item.type === 'attribute');
14463
+ const skippedIndexes = plan.skippedBuiltIns.filter(item => item.type === 'index');
14464
+ if (skippedAttributes.length > 0) {
14465
+ console.log('\nBuilt-in Columns:');
14466
+ skippedAttributes.forEach(item => {
14467
+ console.log(` - [${item.collectionId}] ${item.key}: ${item.reason}`);
14468
+ });
14469
+ }
14470
+ if (skippedIndexes.length > 0) {
14471
+ console.log('\nBuilt-in Indexes:');
14472
+ skippedIndexes.forEach(item => {
14473
+ console.log(` - [${item.collectionId}] ${item.key}: ${item.reason}`);
14474
+ });
14475
+ }
14476
+ }
14350
14477
  return;
14351
14478
  }
14352
14479
  // Store schema for use in executeOperation
14353
14480
  this._currentSchema = schema;
14354
- // Execute operations in order
14481
+ // Execute operations in order and collect all failures
14482
+ const failedOperations = [];
14355
14483
  for (const operation of plan.operations) {
14356
14484
  try {
14357
14485
  yield this.executeOperation(operation);
14358
14486
  }
14359
14487
  catch (error) {
14360
14488
  if (error instanceof AppwriteException) {
14361
- throw new Error(`Failed to execute ${operation.type} for collection ${operation.collectionId}: ${error.message}`);
14489
+ // Collect the error instead of throwing immediately
14490
+ const errorMessage = `Failed to execute ${operation.type} for collection ${operation.collectionId}: ${error.message}`;
14491
+ failedOperations.push({
14492
+ operation,
14493
+ error,
14494
+ errorMessage
14495
+ });
14496
+ }
14497
+ else {
14498
+ // For non-AppwriteException errors, still collect but mark as unexpected
14499
+ const errorMessage = error instanceof Error ? error.message : String(error);
14500
+ failedOperations.push({
14501
+ operation,
14502
+ error: new AppwriteException(`Unexpected error: ${errorMessage}`, 500, 'unexpected_error', JSON.stringify(error)),
14503
+ errorMessage: `Unexpected error during ${operation.type} for collection ${operation.collectionId}: ${errorMessage}`
14504
+ });
14362
14505
  }
14363
- throw error;
14364
14506
  }
14365
14507
  }
14508
+ // If there were any failures, throw an exception with all failure details
14509
+ if (failedOperations.length > 0) {
14510
+ throw new MigrationExecutionException(failedOperations, plan.operations.length);
14511
+ }
14366
14512
  });
14367
14513
  }
14368
14514
  /**
@@ -14592,6 +14738,11 @@ class SchemaMigration {
14592
14738
  if (!operation.index) {
14593
14739
  throw new Error('Index definition missing for createIndex operation');
14594
14740
  }
14741
+ // Skip built-in indexes (starting with '$')
14742
+ if (this.isBuiltInIndex(operation.index.key)) {
14743
+ console.log(`Skipping createIndex for built-in index: ${operation.index.key}`);
14744
+ break;
14745
+ }
14595
14746
  // Skip indexes that contain built-in attributes
14596
14747
  if (this.indexContainsBuiltInAttributes(operation.index)) {
14597
14748
  console.log(`Skipping createIndex for index ${operation.index.key} because it contains built-in attributes`);
@@ -14613,6 +14764,11 @@ class SchemaMigration {
14613
14764
  if (!operation.indexKey) {
14614
14765
  throw new Error('Index key missing for deleteIndex operation');
14615
14766
  }
14767
+ // Skip built-in indexes (starting with '$')
14768
+ if (this.isBuiltInIndex(operation.indexKey)) {
14769
+ console.log(`Skipping deleteIndex for built-in index: ${operation.indexKey}`);
14770
+ break;
14771
+ }
14616
14772
  // Check if index exists before deleting
14617
14773
  try {
14618
14774
  const indexesList = yield this.databases.listIndexes({
@@ -25532,6 +25688,27 @@ class Vcs {
25532
25688
  }
25533
25689
  }
25534
25690
 
25691
+ /**
25692
+ * Environment detection helper
25693
+ */
25694
+ const isBrowser = typeof window !== 'undefined';
25695
+ // Memory storage for server-side environment
25696
+ class MemoryStorage {
25697
+ constructor() {
25698
+ this.data = new Map();
25699
+ }
25700
+ getItem(key) {
25701
+ return this.data.get(key) || null;
25702
+ }
25703
+ setItem(key, value) {
25704
+ this.data.set(key, value);
25705
+ }
25706
+ removeItem(key) {
25707
+ this.data.delete(key);
25708
+ }
25709
+ }
25710
+ const memoryStorage = new MemoryStorage();
25711
+ const getStorage = () => isBrowser ? window.localStorage : memoryStorage;
25535
25712
  var RealtimeCode;
25536
25713
  (function (RealtimeCode) {
25537
25714
  RealtimeCode[RealtimeCode["NORMAL_CLOSURE"] = 1000] = "NORMAL_CLOSURE";
@@ -25773,7 +25950,7 @@ class Realtime {
25773
25950
  }
25774
25951
  }
25775
25952
  handleResponseConnected(message) {
25776
- var _a, _b;
25953
+ var _a;
25777
25954
  if (!message.data) {
25778
25955
  return;
25779
25956
  }
@@ -25781,15 +25958,19 @@ class Realtime {
25781
25958
  let session = this.client.config.session;
25782
25959
  if (!session) {
25783
25960
  try {
25784
- const cookie = JSON.parse((_a = window.localStorage.getItem('cookieFallback')) !== null && _a !== void 0 ? _a : '{}');
25785
- session = cookie === null || cookie === void 0 ? void 0 : cookie[`a_session_${this.client.config.project}`];
25961
+ const storage = getStorage();
25962
+ const cookieFallback = storage.getItem('cookieFallback');
25963
+ if (cookieFallback) {
25964
+ const cookie = JSON.parse(cookieFallback);
25965
+ session = cookie === null || cookie === void 0 ? void 0 : cookie[`a_session_${this.client.config.project}`];
25966
+ }
25786
25967
  }
25787
25968
  catch (error) {
25788
25969
  console.error('Failed to parse cookie fallback:', error);
25789
25970
  }
25790
25971
  }
25791
25972
  if (session && !messageData.user) {
25792
- (_b = this.socket) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({
25973
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify({
25793
25974
  type: 'authentication',
25794
25975
  data: {
25795
25976
  session
@@ -27655,16 +27836,8 @@ exports.MessageStatus = void 0;
27655
27836
  MessageStatus["Failed"] = "failed";
27656
27837
  })(exports.MessageStatus || (exports.MessageStatus = {}));
27657
27838
 
27658
- // 全局默认 API endpoint 配置
27659
- let defaultApiEndpoint = null;
27660
- function setDefaultApiEndpoint(endpoint) {
27661
- if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://')) {
27662
- throw new Error('Invalid endpoint URL: ' + endpoint);
27663
- }
27664
- defaultApiEndpoint = endpoint;
27665
- }
27666
27839
  function getApiEndpoint(region) {
27667
- return defaultApiEndpoint || 'https://appbuild.oceanbase.com/v1';
27840
+ return 'https://appbuild.oceanbase.com/v1';
27668
27841
  }
27669
27842
  function createConsoleSdk(client) {
27670
27843
  return {
@@ -27792,6 +27965,7 @@ exports.Health = Health;
27792
27965
  exports.ID = ID;
27793
27966
  exports.Locale = Locale;
27794
27967
  exports.Messaging = Messaging;
27968
+ exports.MigrationExecutionException = MigrationExecutionException;
27795
27969
  exports.Migrations = Migrations;
27796
27970
  exports.Operator = Operator;
27797
27971
  exports.Organizations = Organizations;
@@ -27813,5 +27987,4 @@ exports.Vcs = Vcs;
27813
27987
  exports.getApiEndpoint = getApiEndpoint;
27814
27988
  exports.realtime = realtime;
27815
27989
  exports.sdk = sdk;
27816
- exports.setDefaultApiEndpoint = setDefaultApiEndpoint;
27817
27990
  //# sourceMappingURL=sdk.js.map