appwrite-utils-cli 1.9.5 → 1.9.7
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/adapters/AdapterFactory.d.ts +1 -1
- package/dist/adapters/AdapterFactory.js +52 -37
- package/dist/adapters/DatabaseAdapter.d.ts +1 -0
- package/dist/adapters/LegacyAdapter.js +5 -2
- package/dist/adapters/TablesDBAdapter.js +18 -3
- package/dist/collections/attributes.js +0 -31
- package/dist/collections/methods.js +89 -184
- package/dist/collections/tableOperations.js +25 -12
- package/dist/config/ConfigManager.js +25 -0
- package/dist/shared/attributeMapper.js +1 -1
- package/dist/tables/indexManager.d.ts +65 -0
- package/dist/tables/indexManager.js +294 -0
- package/dist/utilsController.js +10 -1
- package/package.json +1 -1
- package/src/adapters/AdapterFactory.ts +146 -127
- package/src/adapters/DatabaseAdapter.ts +1 -0
- package/src/adapters/LegacyAdapter.ts +5 -2
- package/src/adapters/TablesDBAdapter.ts +18 -10
- package/src/collections/attributes.ts +0 -34
- package/src/collections/methods.ts +361 -406
- package/src/collections/tableOperations.ts +28 -13
- package/src/config/ConfigManager.ts +32 -0
- package/src/shared/attributeMapper.ts +1 -1
- package/src/tables/indexManager.ts +409 -0
- package/src/utilsController.ts +10 -1
- package/dist/shared/indexManager.d.ts +0 -24
- package/dist/shared/indexManager.js +0 -151
- package/src/shared/indexManager.ts +0 -254
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { AppwriteConfig } from "appwrite-utils";
|
|
10
|
-
import { detectAppwriteVersionCached, isVersionAtLeast, type ApiMode, type VersionDetectionResult } from "../utils/versionDetection.js";
|
|
11
|
-
import type
|
|
12
|
-
import { TablesDBAdapter } from './TablesDBAdapter.js';
|
|
13
|
-
import { LegacyAdapter } from './LegacyAdapter.js';
|
|
14
|
-
import { logger } from '../shared/logging.js';
|
|
15
|
-
import { isValidSessionCookie } from '../utils/sessionAuth.js';
|
|
16
|
-
import { MessageFormatter } from '../shared/messageFormatter.js';
|
|
17
|
-
import { Client } from 'node-appwrite';
|
|
10
|
+
import { detectAppwriteVersionCached, isVersionAtLeast, type ApiMode, type VersionDetectionResult } from "../utils/versionDetection.js";
|
|
11
|
+
import { AdapterError, type DatabaseAdapter } from './DatabaseAdapter.js';
|
|
12
|
+
import { TablesDBAdapter } from './TablesDBAdapter.js';
|
|
13
|
+
import { LegacyAdapter } from './LegacyAdapter.js';
|
|
14
|
+
import { logger } from '../shared/logging.js';
|
|
15
|
+
import { isValidSessionCookie } from '../utils/sessionAuth.js';
|
|
16
|
+
import { MessageFormatter } from '../shared/messageFormatter.js';
|
|
17
|
+
import { Client } from 'node-appwrite';
|
|
18
18
|
|
|
19
19
|
export interface AdapterFactoryConfig {
|
|
20
20
|
appwriteEndpoint: string;
|
|
@@ -201,134 +201,153 @@ export class AdapterFactory {
|
|
|
201
201
|
/**
|
|
202
202
|
* Create TablesDB adapter with dynamic import
|
|
203
203
|
*/
|
|
204
|
-
private static async createTablesDBAdapter(
|
|
205
|
-
config: AdapterFactoryConfig
|
|
206
|
-
): Promise<{ adapter: DatabaseAdapter; client: any }> {
|
|
207
|
-
const startTime = Date.now();
|
|
208
|
-
|
|
209
|
-
try {
|
|
210
|
-
logger.info('Creating TablesDB adapter (static SDK imports)', {
|
|
211
|
-
endpoint: config.appwriteEndpoint,
|
|
212
|
-
operation: 'createTablesDBAdapter'
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// Use pre-configured client or create session-aware client with TablesDB Client
|
|
216
|
-
let client: any;
|
|
217
|
-
if (config.preConfiguredClient) {
|
|
218
|
-
client = config.preConfiguredClient;
|
|
219
|
-
} else {
|
|
220
|
-
client = new Client()
|
|
221
|
-
.setEndpoint(config.appwriteEndpoint)
|
|
222
|
-
.setProject(config.appwriteProject);
|
|
223
|
-
|
|
224
|
-
// Set authentication method with mode headers
|
|
225
|
-
// Prefer session with admin mode, fallback to API key with default mode
|
|
226
|
-
if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
|
|
227
|
-
client.setSession(config.sessionCookie);
|
|
228
|
-
client.headers['X-Appwrite-Mode'] = 'admin';
|
|
229
|
-
logger.debug('Using session authentication for TablesDB adapter', {
|
|
230
|
-
project: config.appwriteProject,
|
|
231
|
-
operation: 'createTablesDBAdapter'
|
|
232
|
-
});
|
|
233
|
-
} else if (config.appwriteKey) {
|
|
234
|
-
client.setKey(config.appwriteKey);
|
|
235
|
-
client.headers['X-Appwrite-Mode'] = 'default';
|
|
236
|
-
logger.debug('Using API key authentication for TablesDB adapter', {
|
|
237
|
-
project: config.appwriteProject,
|
|
238
|
-
operation: 'createTablesDBAdapter'
|
|
239
|
-
});
|
|
240
|
-
} else {
|
|
241
|
-
throw new Error("No authentication available for adapter");
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const adapter = new TablesDBAdapter(client);
|
|
246
|
-
|
|
247
|
-
const totalDuration = Date.now() - startTime;
|
|
248
|
-
logger.info('TablesDB adapter created successfully', {
|
|
249
|
-
totalDuration,
|
|
250
|
-
endpoint: config.appwriteEndpoint,
|
|
251
|
-
operation: 'createTablesDBAdapter'
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
return { adapter, client };
|
|
255
|
-
|
|
256
|
-
} catch (error) {
|
|
257
|
-
const errorDuration = Date.now() - startTime;
|
|
258
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
259
|
-
|
|
260
|
-
MessageFormatter.warning('Failed to create TablesDB adapter - falling back to legacy', { prefix: "Adapter" });
|
|
261
|
-
|
|
262
|
-
logger.warn('TablesDB adapter creation failed, falling back to legacy', {
|
|
263
|
-
error: errorMessage,
|
|
264
|
-
errorDuration,
|
|
204
|
+
private static async createTablesDBAdapter(
|
|
205
|
+
config: AdapterFactoryConfig
|
|
206
|
+
): Promise<{ adapter: DatabaseAdapter; client: any }> {
|
|
207
|
+
const startTime = Date.now();
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
logger.info('Creating TablesDB adapter (static SDK imports)', {
|
|
265
211
|
endpoint: config.appwriteEndpoint,
|
|
266
212
|
operation: 'createTablesDBAdapter'
|
|
267
213
|
});
|
|
268
214
|
|
|
269
|
-
|
|
270
|
-
|
|
215
|
+
let client = new Client()
|
|
216
|
+
.setEndpoint(config.appwriteEndpoint)
|
|
217
|
+
.setProject(config.appwriteProject);
|
|
218
|
+
|
|
219
|
+
// Set authentication method with mode headers
|
|
220
|
+
// Prefer session with admin mode, fallback to API key with default mode
|
|
221
|
+
if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
|
|
222
|
+
client.setSession(config.sessionCookie);
|
|
223
|
+
client.headers['X-Appwrite-Mode'] = 'admin';
|
|
224
|
+
logger.debug('Using session authentication for TablesDB adapter', {
|
|
225
|
+
project: config.appwriteProject,
|
|
226
|
+
operation: 'createTablesDBAdapter'
|
|
227
|
+
});
|
|
228
|
+
} else if (config.appwriteKey) {
|
|
229
|
+
client.setKey(config.appwriteKey);
|
|
230
|
+
client.headers['X-Appwrite-Mode'] = 'default';
|
|
231
|
+
logger.debug('Using API key authentication for TablesDB adapter', {
|
|
232
|
+
project: config.appwriteProject,
|
|
233
|
+
operation: 'createTablesDBAdapter'
|
|
234
|
+
});
|
|
235
|
+
} else {
|
|
236
|
+
throw new Error("No authentication available for adapter");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const adapter = new TablesDBAdapter(client);
|
|
240
|
+
|
|
241
|
+
const totalDuration = Date.now() - startTime;
|
|
242
|
+
logger.info('TablesDB adapter created successfully', {
|
|
243
|
+
totalDuration,
|
|
244
|
+
endpoint: config.appwriteEndpoint,
|
|
245
|
+
operation: 'createTablesDBAdapter'
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return { adapter, client };
|
|
249
|
+
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const errorDuration = Date.now() - startTime;
|
|
252
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
253
|
+
|
|
254
|
+
// Analyze the error to determine if fallback is appropriate
|
|
255
|
+
const isAuthError = errorMessage.toLowerCase().includes('unauthorized') ||
|
|
256
|
+
errorMessage.toLowerCase().includes('forbidden') ||
|
|
257
|
+
errorMessage.toLowerCase().includes('invalid') ||
|
|
258
|
+
errorMessage.toLowerCase().includes('authentication');
|
|
259
|
+
|
|
260
|
+
const isVersionError = errorMessage.toLowerCase().includes('not found') ||
|
|
261
|
+
errorMessage.toLowerCase().includes('unsupported') ||
|
|
262
|
+
errorMessage.toLowerCase().includes('tablesdb');
|
|
263
|
+
|
|
264
|
+
// Only fallback to legacy if this is genuinely a TablesDB support issue
|
|
265
|
+
if (isVersionError) {
|
|
266
|
+
MessageFormatter.warning('TablesDB not supported on this server - using legacy adapter', { prefix: "Adapter" });
|
|
267
|
+
logger.warn('TablesDB not supported, falling back to legacy', {
|
|
268
|
+
error: errorMessage,
|
|
269
|
+
errorDuration,
|
|
270
|
+
endpoint: config.appwriteEndpoint,
|
|
271
|
+
operation: 'createTablesDBAdapter'
|
|
272
|
+
});
|
|
273
|
+
return this.createLegacyAdapter(config);
|
|
274
|
+
} else {
|
|
275
|
+
// For auth or other errors, re-throw to surface the real problem
|
|
276
|
+
logger.error('TablesDB adapter creation failed with non-version error', {
|
|
277
|
+
error: errorMessage,
|
|
278
|
+
errorDuration,
|
|
279
|
+
endpoint: config.appwriteEndpoint,
|
|
280
|
+
operation: 'createTablesDBAdapter',
|
|
281
|
+
isAuthError
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
throw new AdapterError(
|
|
285
|
+
`TablesDB adapter creation failed: ${errorMessage}`,
|
|
286
|
+
'TABLESDB_ADAPTER_CREATION_FAILED',
|
|
287
|
+
error instanceof Error ? error : undefined
|
|
288
|
+
);
|
|
289
|
+
}
|
|
271
290
|
}
|
|
272
291
|
}
|
|
273
292
|
|
|
274
293
|
/**
|
|
275
294
|
* Create Legacy adapter with dynamic import
|
|
276
295
|
*/
|
|
277
|
-
private static async createLegacyAdapter(
|
|
278
|
-
config: AdapterFactoryConfig
|
|
279
|
-
): Promise<{ adapter: DatabaseAdapter; client: any }> {
|
|
280
|
-
const startTime = Date.now();
|
|
281
|
-
|
|
282
|
-
try {
|
|
283
|
-
logger.info('Creating legacy adapter (static SDK imports)', {
|
|
284
|
-
endpoint: config.appwriteEndpoint,
|
|
285
|
-
operation: 'createLegacyAdapter'
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
// Use pre-configured client or create session-aware client with Legacy Client
|
|
289
|
-
let client: any;
|
|
290
|
-
if (config.preConfiguredClient) {
|
|
291
|
-
client = config.preConfiguredClient;
|
|
292
|
-
} else {
|
|
293
|
-
client = new Client()
|
|
294
|
-
.setEndpoint(config.appwriteEndpoint)
|
|
295
|
-
.setProject(config.appwriteProject);
|
|
296
|
-
|
|
297
|
-
// Set authentication method with mode headers
|
|
298
|
-
// Prefer session with admin mode, fallback to API key with default mode
|
|
299
|
-
if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
|
|
300
|
-
(client as any).setSession(config.sessionCookie);
|
|
301
|
-
client.headers['X-Appwrite-Mode'] = 'admin';
|
|
302
|
-
logger.debug('Using session authentication for Legacy adapter', {
|
|
303
|
-
project: config.appwriteProject,
|
|
304
|
-
operation: 'createLegacyAdapter'
|
|
305
|
-
});
|
|
306
|
-
} else if (config.appwriteKey) {
|
|
307
|
-
client.setKey(config.appwriteKey);
|
|
308
|
-
client.headers['X-Appwrite-Mode'] = 'default';
|
|
309
|
-
logger.debug('Using API key authentication for Legacy adapter', {
|
|
310
|
-
project: config.appwriteProject,
|
|
311
|
-
operation: 'createLegacyAdapter'
|
|
312
|
-
});
|
|
313
|
-
} else {
|
|
314
|
-
throw new Error("No authentication available for adapter");
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const adapter = new LegacyAdapter(client);
|
|
319
|
-
|
|
320
|
-
const totalDuration = Date.now() - startTime;
|
|
321
|
-
logger.info('Legacy adapter created successfully', {
|
|
322
|
-
totalDuration,
|
|
323
|
-
endpoint: config.appwriteEndpoint,
|
|
324
|
-
operation: 'createLegacyAdapter'
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
return { adapter, client };
|
|
328
|
-
|
|
329
|
-
} catch (error) {
|
|
330
|
-
const errorDuration = Date.now() - startTime;
|
|
331
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
296
|
+
private static async createLegacyAdapter(
|
|
297
|
+
config: AdapterFactoryConfig
|
|
298
|
+
): Promise<{ adapter: DatabaseAdapter; client: any }> {
|
|
299
|
+
const startTime = Date.now();
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
logger.info('Creating legacy adapter (static SDK imports)', {
|
|
303
|
+
endpoint: config.appwriteEndpoint,
|
|
304
|
+
operation: 'createLegacyAdapter'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
// Use pre-configured client or create session-aware client with Legacy Client
|
|
308
|
+
let client: any;
|
|
309
|
+
if (config.preConfiguredClient) {
|
|
310
|
+
client = config.preConfiguredClient;
|
|
311
|
+
} else {
|
|
312
|
+
client = new Client()
|
|
313
|
+
.setEndpoint(config.appwriteEndpoint)
|
|
314
|
+
.setProject(config.appwriteProject);
|
|
315
|
+
|
|
316
|
+
// Set authentication method with mode headers
|
|
317
|
+
// Prefer session with admin mode, fallback to API key with default mode
|
|
318
|
+
if (config.sessionCookie && isValidSessionCookie(config.sessionCookie)) {
|
|
319
|
+
(client as any).setSession(config.sessionCookie);
|
|
320
|
+
client.headers['X-Appwrite-Mode'] = 'admin';
|
|
321
|
+
logger.debug('Using session authentication for Legacy adapter', {
|
|
322
|
+
project: config.appwriteProject,
|
|
323
|
+
operation: 'createLegacyAdapter'
|
|
324
|
+
});
|
|
325
|
+
} else if (config.appwriteKey) {
|
|
326
|
+
client.setKey(config.appwriteKey);
|
|
327
|
+
client.headers['X-Appwrite-Mode'] = 'default';
|
|
328
|
+
logger.debug('Using API key authentication for Legacy adapter', {
|
|
329
|
+
project: config.appwriteProject,
|
|
330
|
+
operation: 'createLegacyAdapter'
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
throw new Error("No authentication available for adapter");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const adapter = new LegacyAdapter(client);
|
|
338
|
+
|
|
339
|
+
const totalDuration = Date.now() - startTime;
|
|
340
|
+
logger.info('Legacy adapter created successfully', {
|
|
341
|
+
totalDuration,
|
|
342
|
+
endpoint: config.appwriteEndpoint,
|
|
343
|
+
operation: 'createLegacyAdapter'
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
return { adapter, client };
|
|
347
|
+
|
|
348
|
+
} catch (error) {
|
|
349
|
+
const errorDuration = Date.now() - startTime;
|
|
350
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
332
351
|
|
|
333
352
|
logger.error('Failed to load legacy Appwrite SDK', {
|
|
334
353
|
error: errorMessage,
|
|
@@ -507,4 +526,4 @@ export async function getApiCapabilities(
|
|
|
507
526
|
terminology: metadata.terminology,
|
|
508
527
|
capabilities
|
|
509
528
|
};
|
|
510
|
-
}
|
|
529
|
+
}
|
|
@@ -597,12 +597,15 @@ export class LegacyAdapter extends BaseAdapter {
|
|
|
597
597
|
|
|
598
598
|
case 'enum':
|
|
599
599
|
const enumAttr = existingAttr as Models.AttributeEnum;
|
|
600
|
-
|
|
600
|
+
// Choose elements to send only when provided, otherwise preserve existing
|
|
601
|
+
const provided = params.elements;
|
|
602
|
+
const existing = (enumAttr as any)?.elements;
|
|
603
|
+
const nextElements = (Array.isArray(provided) && provided.length > 0) ? provided : existing;
|
|
601
604
|
result = await this.databases.updateEnumAttribute({
|
|
602
605
|
databaseId: params.databaseId,
|
|
603
606
|
collectionId: params.tableId,
|
|
604
607
|
key: params.key,
|
|
605
|
-
elements:
|
|
608
|
+
elements: nextElements,
|
|
606
609
|
required: params.required ?? enumAttr.required,
|
|
607
610
|
xdefault: params.default !== undefined ? params.default : enumAttr.default
|
|
608
611
|
});
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
type AdapterMetadata,
|
|
34
34
|
AdapterError
|
|
35
35
|
} from './DatabaseAdapter.js';
|
|
36
|
+
import { type Column } from 'appwrite-utils';
|
|
36
37
|
import { TablesDB, Client } from "node-appwrite";
|
|
37
38
|
|
|
38
39
|
/**
|
|
@@ -256,8 +257,14 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
|
256
257
|
async listIndexes(params: ListIndexesParams): Promise<ApiResponse> {
|
|
257
258
|
try {
|
|
258
259
|
const result = await this.tablesDB.listIndexes(params);
|
|
260
|
+
// Normalize TablesDB response to expose a consistent 'attributes' array
|
|
261
|
+
const normalized = (result.indexes || []).map((idx: any) => ({
|
|
262
|
+
...idx,
|
|
263
|
+
attributes: Array.isArray(idx?.attributes) ? idx.attributes : (Array.isArray(idx?.columns) ? idx.columns : []),
|
|
264
|
+
orders: Array.isArray(idx?.orders) ? idx.orders : (Array.isArray(idx?.directions) ? idx.directions : []),
|
|
265
|
+
}));
|
|
259
266
|
return {
|
|
260
|
-
data:
|
|
267
|
+
data: normalized,
|
|
261
268
|
total: result.total
|
|
262
269
|
};
|
|
263
270
|
} catch (error) {
|
|
@@ -271,14 +278,15 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
|
271
278
|
|
|
272
279
|
async createIndex(params: CreateIndexParams): Promise<ApiResponse> {
|
|
273
280
|
try {
|
|
274
|
-
const result = await this.tablesDB.createIndex(
|
|
275
|
-
params.databaseId,
|
|
276
|
-
params.tableId,
|
|
277
|
-
params.key,
|
|
278
|
-
params.type as IndexType,
|
|
279
|
-
params.attributes,
|
|
280
|
-
params.orders || []
|
|
281
|
-
|
|
281
|
+
const result = await this.tablesDB.createIndex({
|
|
282
|
+
databaseId: params.databaseId,
|
|
283
|
+
tableId: params.tableId,
|
|
284
|
+
key: params.key,
|
|
285
|
+
type: params.type as IndexType,
|
|
286
|
+
columns: params.attributes,
|
|
287
|
+
orders: params.orders || [],
|
|
288
|
+
lengths: params.lengths || [],
|
|
289
|
+
});
|
|
282
290
|
return { data: result };
|
|
283
291
|
} catch (error) {
|
|
284
292
|
throw new AdapterError(
|
|
@@ -494,7 +502,7 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
|
494
502
|
|
|
495
503
|
// Use the appropriate updateXColumn method based on the column type
|
|
496
504
|
// Cast column to proper Models type to access its specific properties
|
|
497
|
-
const columnType = (column
|
|
505
|
+
const columnType = (column.type === 'string' && !('format' in column)) || column.type !== 'string' ? column.type : 'enum';
|
|
498
506
|
|
|
499
507
|
switch (columnType) {
|
|
500
508
|
case 'string':
|
|
@@ -651,13 +651,6 @@ const updateLegacyAttribute = async (
|
|
|
651
651
|
collectionId: string,
|
|
652
652
|
attribute: Attribute
|
|
653
653
|
): Promise<void> => {
|
|
654
|
-
console.log(`DEBUG updateLegacyAttribute before normalizeMinMaxValues:`, {
|
|
655
|
-
key: attribute.key,
|
|
656
|
-
type: attribute.type,
|
|
657
|
-
min: (attribute as any).min,
|
|
658
|
-
max: (attribute as any).max
|
|
659
|
-
});
|
|
660
|
-
|
|
661
654
|
const { min: normalizedMin, max: normalizedMax } =
|
|
662
655
|
normalizeMinMaxValues(attribute);
|
|
663
656
|
|
|
@@ -1515,37 +1508,10 @@ export const createOrUpdateAttribute = async (
|
|
|
1515
1508
|
// `Updating attribute with same key ${attribute.key} but different values`
|
|
1516
1509
|
// );
|
|
1517
1510
|
|
|
1518
|
-
// DEBUG: Log before object merge to detect corruption
|
|
1519
|
-
if ((attribute.key === 'conversationType' || attribute.key === 'messageStreakCount')) {
|
|
1520
|
-
console.log(`[DEBUG] MERGE - key="${attribute.key}"`, {
|
|
1521
|
-
found: {
|
|
1522
|
-
elements: (foundAttribute as any)?.elements,
|
|
1523
|
-
min: (foundAttribute as any)?.min,
|
|
1524
|
-
max: (foundAttribute as any)?.max
|
|
1525
|
-
},
|
|
1526
|
-
desired: {
|
|
1527
|
-
elements: (attribute as any)?.elements,
|
|
1528
|
-
min: (attribute as any)?.min,
|
|
1529
|
-
max: (attribute as any)?.max
|
|
1530
|
-
}
|
|
1531
|
-
});
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
1511
|
finalAttribute = {
|
|
1535
1512
|
...foundAttribute,
|
|
1536
1513
|
...attribute,
|
|
1537
1514
|
};
|
|
1538
|
-
|
|
1539
|
-
// DEBUG: Log after object merge to detect corruption
|
|
1540
|
-
if ((finalAttribute.key === 'conversationType' || finalAttribute.key === 'messageStreakCount')) {
|
|
1541
|
-
console.log(`[DEBUG] AFTER_MERGE - key="${finalAttribute.key}"`, {
|
|
1542
|
-
merged: {
|
|
1543
|
-
elements: finalAttribute?.elements,
|
|
1544
|
-
min: (finalAttribute as any)?.min,
|
|
1545
|
-
max: (finalAttribute as any)?.max
|
|
1546
|
-
}
|
|
1547
|
-
});
|
|
1548
|
-
}
|
|
1549
1515
|
action = "update";
|
|
1550
1516
|
} else if (
|
|
1551
1517
|
!updateEnabled &&
|