backend-manager 5.0.99 → 5.0.100

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.0.99",
3
+ "version": "5.0.100",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -79,14 +79,17 @@ class FirestoreIndexesRequiredTest extends BaseTest {
79
79
  return false;
80
80
  }
81
81
 
82
+ // Strip implicit __name__ fields that Firebase adds to live indexes
83
+ const existingFields = (existing.fields || []).filter(f => f.fieldPath !== '__name__');
84
+
82
85
  // Must have same number of fields
83
- if (!existing.fields || existing.fields.length !== required.fields.length) {
86
+ if (existingFields.length !== required.fields.length) {
84
87
  return false;
85
88
  }
86
89
 
87
90
  // Each field must match
88
91
  return required.fields.every((reqField, i) => {
89
- const exField = existing.fields[i];
92
+ const exField = existingFields[i];
90
93
 
91
94
  if (exField.fieldPath !== reqField.fieldPath) {
92
95
  return false;
@@ -25,10 +25,63 @@ class FirestoreIndexesSyncedTest extends BaseTest {
25
25
  if (localIndexes_exists) {
26
26
  localIndexes = require(`${self.firebaseProjectPath}/firestore.indexes.json`);
27
27
  }
28
- const equal = _.isEqual(liveIndexes, localIndexes);
28
+
29
+ // Firebase adds implicit properties to live indexes (__name__ fields, density, etc.)
30
+ // and returns them in a different order. Normalize before comparing.
31
+ const normalizeIndexes = (indexes) => {
32
+ if (!indexes?.indexes) {
33
+ return indexes;
34
+ }
35
+ return {
36
+ ...indexes,
37
+ indexes: _.sortBy(indexes.indexes.map(idx => {
38
+ const { density, ...rest } = idx;
39
+ return {
40
+ ...rest,
41
+ fields: (rest.fields || []).filter(f => f.fieldPath !== '__name__'),
42
+ };
43
+ }), idx => `${idx.collectionGroup}:${(idx.fields || []).map(f => f.fieldPath).join(',')}`),
44
+ };
45
+ };
46
+
47
+ const equal = _.isEqual(normalizeIndexes(liveIndexes), normalizeIndexes(localIndexes));
29
48
 
30
49
  jetpack.remove(`${self.firebaseProjectPath}/${tempPath}`);
31
50
 
51
+ if (!equal && localIndexes_exists) {
52
+ // Log what differs so the user can see why (use stripped versions for accurate comparison)
53
+ const strippedLocal = normalizeIndexes(localIndexes);
54
+ const strippedLive = normalizeIndexes(liveIndexes);
55
+ const localOnly = _.differenceWith(strippedLocal?.indexes || [], strippedLive?.indexes || [], _.isEqual);
56
+ const liveOnly = _.differenceWith(strippedLive?.indexes || [], strippedLocal?.indexes || [], _.isEqual);
57
+
58
+ if (localOnly.length > 0) {
59
+ console.log(chalk.yellow(` Indexes in local but not live:`));
60
+ for (const idx of localOnly) {
61
+ console.log(chalk.gray(` - ${idx.collectionGroup} [${(idx.fields || []).map(f => `${f.fieldPath} ${f.order || f.arrayConfig}`).join(', ')}]`));
62
+ }
63
+ }
64
+ if (liveOnly.length > 0) {
65
+ console.log(chalk.yellow(` Indexes in live but not local:`));
66
+ for (const idx of liveOnly) {
67
+ console.log(chalk.gray(` - ${idx.collectionGroup} [${(idx.fields || []).map(f => `${f.fieldPath} ${f.order || f.arrayConfig}`).join(', ')}]`));
68
+ }
69
+ }
70
+ if (localOnly.length === 0 && liveOnly.length === 0) {
71
+ // Indexes arrays match but fieldOverrides or other top-level keys differ
72
+ const localKeys = Object.keys(localIndexes || {});
73
+ const liveKeys = Object.keys(liveIndexes || {});
74
+ const allKeys = _.union(localKeys, liveKeys);
75
+ for (const key of allKeys) {
76
+ if (!_.isEqual(localIndexes?.[key], liveIndexes?.[key])) {
77
+ console.log(chalk.yellow(` Difference in "${key}":`));
78
+ console.log(chalk.gray(` Local: ${JSON.stringify(localIndexes?.[key])}`));
79
+ console.log(chalk.gray(` Live: ${JSON.stringify(liveIndexes?.[key])}`));
80
+ }
81
+ }
82
+ }
83
+ }
84
+
32
85
  return !localIndexes_exists || equal;
33
86
  }
34
87
 
@@ -41,14 +94,14 @@ class FirestoreIndexesSyncedTest extends BaseTest {
41
94
  name: 'direction',
42
95
  message: 'Firestore indexes are out of sync. Which direction?',
43
96
  choices: [
44
- {
45
- name: `Live → Local (replace ${chalk.bold('local')} indexes with ${chalk.bold('live')})`,
46
- value: 'live-to-local',
47
- },
48
97
  {
49
98
  name: `Local → Live (replace ${chalk.bold('live')} indexes with ${chalk.bold('local')})`,
50
99
  value: 'local-to-live',
51
100
  },
101
+ {
102
+ name: `Live → Local (replace ${chalk.bold('local')} indexes with ${chalk.bold('live')})`,
103
+ value: 'live-to-local',
104
+ },
52
105
  {
53
106
  name: 'Skip',
54
107
  value: 'skip',