@stoker-platform/cli 0.5.138 → 0.5.140
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/lib/package.json +4 -4
- package/lib/src/lint/lintSchema.js +2 -5
- package/lib/src/lint/securityReport.js +9 -33
- package/lib/src/migration/firestore/migrateFirestore.js +2 -0
- package/lib/src/migration/firestore/operations/deleteField.js +1 -1
- package/lib/src/migration/firestore/operations/replayProjections.js +127 -0
- package/lib/src/migration/migrateAll.js +1 -1
- package/lib/src/ops/auditDenormalized.js +53 -48
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/lib/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoker-platform/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.139",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"main": "./lib/src/main.js",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"@google-cloud/secret-manager": "^6.1.2",
|
|
25
25
|
"@google-cloud/storage": "^7.19.0",
|
|
26
26
|
"@inquirer/prompts": "^8.5.2",
|
|
27
|
-
"@stoker-platform/node-client": "0.5.
|
|
28
|
-
"@stoker-platform/types": "0.5.
|
|
29
|
-
"@stoker-platform/utils": "0.5.
|
|
27
|
+
"@stoker-platform/node-client": "0.5.88",
|
|
28
|
+
"@stoker-platform/types": "0.5.65",
|
|
29
|
+
"@stoker-platform/utils": "0.5.79",
|
|
30
30
|
"algoliasearch": "^5.53.0",
|
|
31
31
|
"commander": "^15.0.0",
|
|
32
32
|
"cross-spawn": "^7.0.6",
|
|
@@ -204,11 +204,8 @@ export const lintSchema = async (noLog = false) => {
|
|
|
204
204
|
if (!groupKeyRegex.test(groupKey)) {
|
|
205
205
|
errors.push(`Collection ${collectionName} has a field access group key ${groupKey} that is invalid. Keys must start with a letter and contain only letters, digits and hyphens.`);
|
|
206
206
|
}
|
|
207
|
-
if (
|
|
208
|
-
errors.push(`Collection ${collectionName} has a field access group key ${groupKey} that
|
|
209
|
-
}
|
|
210
|
-
if (roles.includes(groupKey)) {
|
|
211
|
-
errors.push(`Collection ${collectionName} has a field access group key ${groupKey} that collides with a role name`);
|
|
207
|
+
if (/-\d+$/.test(groupKey)) {
|
|
208
|
+
errors.push(`Collection ${collectionName} has a field access group key ${groupKey} that ends with a hyphen followed by digits.`);
|
|
212
209
|
}
|
|
213
210
|
// eslint-disable-next-line security/detect-object-injection
|
|
214
211
|
if (!groupFields[groupKey]?.length) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateSchema } from "../deploy/schema/generateSchema.js";
|
|
2
|
-
import { getAccessFields, getField, getDependencyIndexFields, getFieldAccessGroupFields, getFieldAccessGroupIndexFields,
|
|
2
|
+
import { getAccessFields, getField, getDependencyIndexFields, getFieldAccessGroupFields, getFieldAccessGroupIndexFields, isDependencyField, isRelationField, getRoleGroups, getFieldCustomization, roleHasOperationAccess, } from "@stoker-platform/utils";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
/* eslint-disable security/detect-object-injection */
|
|
@@ -27,15 +27,20 @@ export const securityReport = async () => {
|
|
|
27
27
|
writeRuleReads[collectionName].batch.add("User Document Lookup");
|
|
28
28
|
writeRuleReads[collectionName].batch.add("Latest Deploy Document");
|
|
29
29
|
writeRuleReads[collectionName].batch.add("Maintenance Mode Document");
|
|
30
|
-
const roleGroups = getRoleGroups(collectionSchema, schema);
|
|
30
|
+
const roleGroups = Array.from(getRoleGroups(collectionSchema, schema));
|
|
31
31
|
roleGroups.forEach(() => {
|
|
32
32
|
writeRuleReads[collectionName].batch.add("Main Document");
|
|
33
33
|
});
|
|
34
34
|
const fieldAccessGroups = getFieldAccessGroupFields(collectionSchema);
|
|
35
|
-
Object.
|
|
35
|
+
Object.entries(fieldAccessGroups).forEach(([groupKey, groupFields]) => {
|
|
36
36
|
if (groupFields.length === 0)
|
|
37
37
|
return;
|
|
38
|
-
|
|
38
|
+
for (const roleGroup of roleGroups) {
|
|
39
|
+
const overlayFields = getFieldAccessGroupIndexFields(groupKey, collectionSchema, roleGroup);
|
|
40
|
+
if (overlayFields.length === 0)
|
|
41
|
+
continue;
|
|
42
|
+
writeRuleReads[collectionName].batch.add("Main Document");
|
|
43
|
+
}
|
|
39
44
|
});
|
|
40
45
|
if (auth) {
|
|
41
46
|
writeRuleReads[collectionName].main.add("Document Lock Lookup");
|
|
@@ -154,34 +159,6 @@ export const securityReport = async () => {
|
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
}
|
|
157
|
-
if (roleHasOperationAccess(collectionSchema, role, "read")) {
|
|
158
|
-
const fieldAccessGroups = getFieldAccessGroupFields(collectionSchema);
|
|
159
|
-
const roleFields = getRoleFields(collectionSchema, role);
|
|
160
|
-
const roleFieldNames = new Set(roleFields.map((field) => field.name));
|
|
161
|
-
for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
|
|
162
|
-
if (groupFields.length === 0)
|
|
163
|
-
continue;
|
|
164
|
-
// eslint-disable-next-line security/detect-object-injection
|
|
165
|
-
if (!collectionSchema.fieldAccessGroups?.[groupKey]?.applicableRoles.includes(role))
|
|
166
|
-
continue;
|
|
167
|
-
const groupFieldNames = new Set(groupFields.map((field) => field.name));
|
|
168
|
-
const overlayFields = getFieldAccessGroupIndexFields(groupKey, collectionSchema);
|
|
169
|
-
for (const overlayField of overlayFields) {
|
|
170
|
-
if (overlayField.name === "id" || overlayField.name === "Collection_Path") {
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
if (groupFieldNames.has(overlayField.name))
|
|
174
|
-
continue;
|
|
175
|
-
if (roleFieldNames.has(overlayField.name))
|
|
176
|
-
continue;
|
|
177
|
-
roles[role][collectionName] ||= {};
|
|
178
|
-
if (!roles[role][collectionName][overlayField.name]) {
|
|
179
|
-
roles[role][collectionName][overlayField.name] = new Set();
|
|
180
|
-
}
|
|
181
|
-
roles[role][collectionName][overlayField.name].add(`Field Access Group ${groupKey}- Index`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
162
|
}
|
|
186
163
|
}
|
|
187
164
|
console.log("Security Rule Write Reads:\n");
|
|
@@ -212,7 +189,6 @@ export const securityReport = async () => {
|
|
|
212
189
|
console.log("\n");
|
|
213
190
|
}
|
|
214
191
|
console.log("\n\nPossible Excess Permissions:\n");
|
|
215
|
-
console.log("(Includes fields on field access group overlays that are not on the role's mirror, after filtering overlay metadata to the roles declared on each field access group.)\n");
|
|
216
192
|
for (const [role, collections] of Object.entries(roles)) {
|
|
217
193
|
console.log(`${role.toUpperCase()}\n`);
|
|
218
194
|
for (const [collection, fields] of Object.entries(collections)) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { deleteField } from "./operations/deleteField.js";
|
|
2
|
+
import { replayProjections } from "./operations/replayProjections.js";
|
|
2
3
|
export const migrateFirestore = async (currentSchema, lastSchema) => {
|
|
3
4
|
console.log("Migrating Firestore...");
|
|
4
5
|
if (lastSchema) {
|
|
5
6
|
await deleteField(currentSchema, lastSchema);
|
|
7
|
+
await replayProjections(currentSchema, lastSchema);
|
|
6
8
|
}
|
|
7
9
|
return;
|
|
8
10
|
};
|
|
@@ -46,7 +46,7 @@ export const deleteField = async (currentSchema, lastSchema) => {
|
|
|
46
46
|
.doc(tenantId)
|
|
47
47
|
.collection("system_migration")
|
|
48
48
|
.doc(currentSchema.version.toString())
|
|
49
|
-
.collection(collection)
|
|
49
|
+
.collection(`Migration-${collection}`)
|
|
50
50
|
.doc(doc.id), {
|
|
51
51
|
[fieldName]: doc.get(fieldName),
|
|
52
52
|
}, { merge: true });
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { getFirestorePathRef, getStokerFirestore } from "@stoker-platform/node-client";
|
|
2
|
+
import { addDenormalized, getAllRoleGroups, getDependencyIndexFields, getFieldAccessGroupFields, getRoleGroups, isDependencyField, } from "@stoker-platform/utils";
|
|
3
|
+
import { FieldValue } from "firebase-admin/firestore";
|
|
4
|
+
import isEqual from "lodash/isEqual.js";
|
|
5
|
+
const getUniqueFieldNames = (collectionSchema) => collectionSchema.fields
|
|
6
|
+
.filter((field) => "unique" in field && field.unique)
|
|
7
|
+
.map((field) => field.name)
|
|
8
|
+
.sort();
|
|
9
|
+
const getDependencyIndexShape = (collectionSchema, schema) => {
|
|
10
|
+
const shape = {};
|
|
11
|
+
for (const field of collectionSchema.fields) {
|
|
12
|
+
if (isDependencyField(field, collectionSchema, schema)) {
|
|
13
|
+
shape[field.name] = getDependencyIndexFields(field, collectionSchema, schema)
|
|
14
|
+
.map((indexField) => indexField.name)
|
|
15
|
+
.sort();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return shape;
|
|
19
|
+
};
|
|
20
|
+
const getRoleGroupShape = (collectionSchema, schema) => Array.from(getRoleGroups(collectionSchema, schema))
|
|
21
|
+
.map((group) => ({
|
|
22
|
+
key: group.key,
|
|
23
|
+
roles: [...group.roles].sort(),
|
|
24
|
+
fields: group.fields.map((field) => field.name).sort(),
|
|
25
|
+
}))
|
|
26
|
+
.sort((a, b) => a.key.localeCompare(b.key));
|
|
27
|
+
const getFieldAccessGroupFieldShape = (collectionSchema) => {
|
|
28
|
+
const shape = {};
|
|
29
|
+
for (const [groupKey, groupFields] of Object.entries(getFieldAccessGroupFields(collectionSchema))) {
|
|
30
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
31
|
+
shape[groupKey] = groupFields.map((field) => field.name).sort();
|
|
32
|
+
}
|
|
33
|
+
return shape;
|
|
34
|
+
};
|
|
35
|
+
const replayProjectionsForCollection = async (collection, currentSchema, lastSchema) => {
|
|
36
|
+
console.log(`Projections for collection ${collection} have changed. Replaying...`);
|
|
37
|
+
const db = getStokerFirestore();
|
|
38
|
+
const bulkWriter = db.bulkWriter();
|
|
39
|
+
bulkWriter.onWriteError((error) => {
|
|
40
|
+
console.log(error);
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
44
|
+
const lastCollectionSchema = lastSchema.collections[collection];
|
|
45
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
46
|
+
const currentCollectionSchema = currentSchema.collections[collection];
|
|
47
|
+
const lastRoleGroups = getAllRoleGroups(lastSchema);
|
|
48
|
+
const currentRoleGroups = getAllRoleGroups(currentSchema);
|
|
49
|
+
const querySnapshot = await db.collectionGroup(collection).get();
|
|
50
|
+
for (const doc of querySnapshot.docs) {
|
|
51
|
+
const tenantId = doc.ref.path.split("/")[1];
|
|
52
|
+
const record = { id: doc.id, ...doc.data() };
|
|
53
|
+
const path = record.Collection_Path;
|
|
54
|
+
if (!path) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const dependencyRef = (field) => db
|
|
58
|
+
.collection("tenants")
|
|
59
|
+
.doc(tenantId)
|
|
60
|
+
.collection("system_fields")
|
|
61
|
+
.doc(collection)
|
|
62
|
+
.collection(`${collection}-${field.name}`)
|
|
63
|
+
.doc(doc.id);
|
|
64
|
+
const uniqueRef = (field, uniqueValue) => db
|
|
65
|
+
.collection("tenants")
|
|
66
|
+
.doc(tenantId)
|
|
67
|
+
.collection("system_unique")
|
|
68
|
+
.doc(collection)
|
|
69
|
+
.collection(`Unique-${collection}-${field.name}`)
|
|
70
|
+
.doc(uniqueValue);
|
|
71
|
+
const privateRef = (role) => db
|
|
72
|
+
.collection("tenants")
|
|
73
|
+
.doc(tenantId)
|
|
74
|
+
.collection("system_fields")
|
|
75
|
+
.doc(collection)
|
|
76
|
+
.collection(`${collection}-${role}`)
|
|
77
|
+
.doc(doc.id);
|
|
78
|
+
const twoWayIncludeRef = (relationPath, id) => {
|
|
79
|
+
const ref = getFirestorePathRef(db, relationPath, tenantId);
|
|
80
|
+
return ref.doc(id);
|
|
81
|
+
};
|
|
82
|
+
const twoWayDependencyRef = (field, dependencyField, id) => db
|
|
83
|
+
.collection("tenants")
|
|
84
|
+
.doc(tenantId)
|
|
85
|
+
.collection("system_fields")
|
|
86
|
+
.doc(field.collection)
|
|
87
|
+
.collection(`${field.collection}-${dependencyField}`)
|
|
88
|
+
.doc(id);
|
|
89
|
+
const twoWayPrivateRef = (field, role, id) => db
|
|
90
|
+
.collection("tenants")
|
|
91
|
+
.doc(tenantId)
|
|
92
|
+
.collection("system_fields")
|
|
93
|
+
.doc(field.collection)
|
|
94
|
+
.collection(`${field.collection}-${role.replaceAll(" ", "-")}`)
|
|
95
|
+
.doc(id);
|
|
96
|
+
for (const field of lastCollectionSchema.fields) {
|
|
97
|
+
if ("unique" in field &&
|
|
98
|
+
field.unique &&
|
|
99
|
+
(typeof record[field.name] === "string" || typeof record[field.name] === "number")) {
|
|
100
|
+
bulkWriter.delete(uniqueRef(field, record[field.name].toString().toLowerCase().replace(/\s/g, "---").replaceAll("/", "|||")));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
addDenormalized("delete", bulkWriter, path, doc.id, record, lastSchema, lastCollectionSchema, { noTwoWay: true }, lastRoleGroups, FieldValue.arrayUnion, FieldValue.arrayRemove, FieldValue.delete, dependencyRef, uniqueRef, privateRef, twoWayIncludeRef, twoWayDependencyRef, twoWayPrivateRef);
|
|
104
|
+
addDenormalized("create", bulkWriter, path, doc.id, record, currentSchema, currentCollectionSchema, { noTwoWay: true }, currentRoleGroups, FieldValue.arrayUnion, FieldValue.arrayRemove, FieldValue.delete, dependencyRef, uniqueRef, privateRef, twoWayIncludeRef, twoWayDependencyRef, twoWayPrivateRef);
|
|
105
|
+
}
|
|
106
|
+
await bulkWriter.close();
|
|
107
|
+
};
|
|
108
|
+
export const replayProjections = async (currentSchema, lastSchema) => {
|
|
109
|
+
const currentSchemaKeys = Object.keys(currentSchema.collections);
|
|
110
|
+
for (const collection of currentSchemaKeys) {
|
|
111
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
112
|
+
if (!lastSchema.collections[collection])
|
|
113
|
+
continue;
|
|
114
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
115
|
+
const lastCollectionSchema = lastSchema.collections[collection];
|
|
116
|
+
// eslint-disable-next-line security/detect-object-injection
|
|
117
|
+
const currentCollectionSchema = currentSchema.collections[collection];
|
|
118
|
+
const roleGroupsChanged = !isEqual(getRoleGroupShape(lastCollectionSchema, lastSchema), getRoleGroupShape(currentCollectionSchema, currentSchema));
|
|
119
|
+
const fieldAccessGroupsChanged = !isEqual(lastCollectionSchema.fieldAccessGroups, currentCollectionSchema.fieldAccessGroups) ||
|
|
120
|
+
!isEqual(getFieldAccessGroupFieldShape(lastCollectionSchema), getFieldAccessGroupFieldShape(currentCollectionSchema));
|
|
121
|
+
const uniqueFieldsChanged = !isEqual(getUniqueFieldNames(lastCollectionSchema), getUniqueFieldNames(currentCollectionSchema));
|
|
122
|
+
const dependenciesChanged = !isEqual(getDependencyIndexShape(lastCollectionSchema, lastSchema), getDependencyIndexShape(currentCollectionSchema, currentSchema));
|
|
123
|
+
if (roleGroupsChanged || fieldAccessGroupsChanged || uniqueFieldsChanged || dependenciesChanged) {
|
|
124
|
+
await replayProjectionsForCollection(collection, currentSchema, lastSchema);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -6,7 +6,7 @@ import { migrateFirestore } from "./firestore/migrateFirestore.js";
|
|
|
6
6
|
import { generateSchema } from "../deploy/schema/generateSchema.js";
|
|
7
7
|
export const migrateAll = async () => {
|
|
8
8
|
await initializeFirebase();
|
|
9
|
-
const currentSchema = await generateSchema();
|
|
9
|
+
const currentSchema = await generateSchema(true);
|
|
10
10
|
const lastSchema = await fetchLastSchema();
|
|
11
11
|
console.log("Migration started...");
|
|
12
12
|
if (isNaN(currentSchema.version)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fetchCurrentSchema, initializeStoker, getStokerFirestore } from "@stoker-platform/node-client";
|
|
2
|
-
import { getDependencyIndexFields, getFieldAccessGroupFields, getFieldAccessGroupIndexFields, getLowercaseFields, getRoleGroups, getSingleFieldRelations, isDependencyField, isRelationField, } from "@stoker-platform/utils";
|
|
2
|
+
import { getDependencyIndexFields, getFieldAccessGroupFields, getFieldAccessGroupIndexFields, getFieldAccessGroupKey, getLowercaseFields, getRoleGroups, getSingleFieldRelations, isDependencyField, isRelationField, } from "@stoker-platform/utils";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import isEqual from "lodash/isEqual.js";
|
|
5
5
|
import isEmpty from "lodash/isEmpty.js";
|
|
@@ -121,57 +121,62 @@ export const auditDenormalized = async (options) => {
|
|
|
121
121
|
for (const [groupKey, groupFields] of Object.entries(fieldAccessGroups)) {
|
|
122
122
|
if (groupFields.length === 0)
|
|
123
123
|
continue;
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
.
|
|
127
|
-
|
|
128
|
-
.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
overlayIds
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
124
|
+
for (const roleGroup of roleGroups) {
|
|
125
|
+
const overlayIndexFields = getFieldAccessGroupIndexFields(groupKey, collectionSchema, roleGroup);
|
|
126
|
+
if (overlayIndexFields.length === 0)
|
|
127
|
+
continue;
|
|
128
|
+
const overlayKey = getFieldAccessGroupKey(groupKey, roleGroup.key);
|
|
129
|
+
const overlaySnapshot = await db
|
|
130
|
+
.collection("tenants")
|
|
131
|
+
.doc(options.tenant)
|
|
132
|
+
.collection("system_fields")
|
|
133
|
+
.doc(collectionName)
|
|
134
|
+
.collection(`${collectionName}-${overlayKey}`)
|
|
135
|
+
.get();
|
|
136
|
+
const overlayIds = new Set();
|
|
137
|
+
const lowercaseFields = getLowercaseFields(collectionSchema, overlayIndexFields);
|
|
138
|
+
const lowercaseFieldNames = Array.from(lowercaseFields).map((field) => field.name);
|
|
139
|
+
overlaySnapshot.forEach((overlay) => {
|
|
140
|
+
overlayIds.add(overlay.id);
|
|
141
|
+
const overlayData = overlay.data();
|
|
142
|
+
for (const indexField of overlayIndexFields) {
|
|
143
|
+
if (indexField.name === "Collection_Path_String")
|
|
144
|
+
continue;
|
|
145
|
+
if (isRelationField(indexField)) {
|
|
146
|
+
const overlayValue = {
|
|
147
|
+
[indexField.name]: overlayData[indexField.name],
|
|
148
|
+
[`${indexField.name}_Array`]: overlayData[`${indexField.name}_Array`],
|
|
149
|
+
};
|
|
150
|
+
const collectionValue = {
|
|
151
|
+
[indexField.name]: collectionData[overlay.id]?.[indexField.name],
|
|
152
|
+
[`${indexField.name}_Array`]: collectionData[overlay.id]?.[`${indexField.name}_Array`],
|
|
153
|
+
};
|
|
154
|
+
if (singleFieldRelationNames.includes(indexField.name)) {
|
|
155
|
+
overlayValue[`${indexField.name}_Single`] = overlayData[`${indexField.name}_Single`];
|
|
156
|
+
collectionValue[`${indexField.name}_Single`] =
|
|
157
|
+
collectionData[overlay.id]?.[`${indexField.name}_Single`];
|
|
158
|
+
}
|
|
159
|
+
if (!isEqual(overlayValue, collectionValue)) {
|
|
160
|
+
console.log(`${collectionName} ${overlay.id} Field Access Group ${overlayKey}: ${indexField.name} - ${JSON.stringify(overlayValue)} !== ${JSON.stringify(collectionValue)}`);
|
|
161
|
+
}
|
|
157
162
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
else {
|
|
164
|
+
const overlayValue = overlayData[indexField.name];
|
|
165
|
+
const collectionValue = collectionData[overlay.id]?.[indexField.name];
|
|
166
|
+
if (!isEqual(overlayValue, collectionValue)) {
|
|
167
|
+
console.log(`${collectionName} ${overlay.id} Field Access Group ${overlayKey}: ${indexField.name} - ${JSON.stringify(overlayValue)} !== ${JSON.stringify(collectionValue)}`);
|
|
168
|
+
}
|
|
164
169
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
if (lowercaseFieldNames.includes(indexField.name)) {
|
|
171
|
+
const overlayValue = overlayData[`${indexField.name}_Lowercase`];
|
|
172
|
+
const collectionValue = collectionData[overlay.id]?.[`${indexField.name}_Lowercase`];
|
|
173
|
+
if (!isEqual(overlayValue, collectionValue)) {
|
|
174
|
+
console.log(`${collectionName} ${overlay.id} Field Access Group ${overlayKey}: ${indexField.name}_Lowercase - ${JSON.stringify(overlayValue)} !== ${JSON.stringify(collectionValue)}`);
|
|
175
|
+
}
|
|
171
176
|
}
|
|
172
177
|
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
175
180
|
}
|
|
176
181
|
console.log(`${collectionName} audited.\n`);
|
|
177
182
|
}
|
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/main.ts","../src/data/exporttobigquery.ts","../src/data/seeddata.ts","../src/deploy/deployproject.ts","../src/deploy/cloud-functions/getfunctionsdata.ts","../src/deploy/firestore-export/exportfirestoredata.ts","../src/deploy/firestore-ttl/deployttls.ts","../src/deploy/live-update/liveupdate.ts","../src/deploy/maintenance/activatemaintenancemode.ts","../src/deploy/maintenance/disablemaintenancemode.ts","../src/deploy/maintenance/setdeploymentstatus.ts","../src/deploy/rules-indexes/generatefirestoreindexes.ts","../src/deploy/rules-indexes/generatefirestorerules.ts","../src/deploy/rules-indexes/generatestoragerules.ts","../src/deploy/schema/applyschema.ts","../src/deploy/schema/generateschema.ts","../src/deploy/schema/persistschema.ts","../src/deploy/schema/updateliveschema.ts","../src/lint/lintschema.ts","../src/lint/securityreport.ts","../src/migration/migrateall.ts","../src/migration/firestore/migratefirestore.ts","../src/migration/firestore/operations/deletefield.ts","../src/ops/auditdenormalized.ts","../src/ops/auditpermissions.ts","../src/ops/auditrelations.ts","../src/ops/explainpreloadqueries.ts","../src/ops/getuser.ts","../src/ops/getuserpermissions.ts","../src/ops/getuserrecord.ts","../src/ops/listprojects.ts","../src/ops/mfastatus.ts","../src/ops/setusercollection.ts","../src/ops/setuserdocument.ts","../src/ops/setuserrole.ts","../src/project/addproject.ts","../src/project/addrecord.ts","../src/project/addrecordprompt.ts","../src/project/addtenant.ts","../src/project/buildwebapp.ts","../src/project/customdomain.ts","../src/project/deleteproject.ts","../src/project/deleterecord.ts","../src/project/deletetenant.ts","../src/project/getone.ts","../src/project/getsome.ts","../src/project/initproject.ts","../src/project/prepareemulatordata.ts","../src/project/setproject.ts","../src/project/startemulators.ts","../src/project/updaterecord.ts","../src/types/generatetypes.ts"],"version":"6.0.3"}
|
|
1
|
+
{"root":["../src/main.ts","../src/data/exporttobigquery.ts","../src/data/seeddata.ts","../src/deploy/deployproject.ts","../src/deploy/cloud-functions/getfunctionsdata.ts","../src/deploy/firestore-export/exportfirestoredata.ts","../src/deploy/firestore-ttl/deployttls.ts","../src/deploy/live-update/liveupdate.ts","../src/deploy/maintenance/activatemaintenancemode.ts","../src/deploy/maintenance/disablemaintenancemode.ts","../src/deploy/maintenance/setdeploymentstatus.ts","../src/deploy/rules-indexes/generatefirestoreindexes.ts","../src/deploy/rules-indexes/generatefirestorerules.ts","../src/deploy/rules-indexes/generatestoragerules.ts","../src/deploy/schema/applyschema.ts","../src/deploy/schema/generateschema.ts","../src/deploy/schema/persistschema.ts","../src/deploy/schema/updateliveschema.ts","../src/lint/lintschema.ts","../src/lint/securityreport.ts","../src/migration/migrateall.ts","../src/migration/firestore/migratefirestore.ts","../src/migration/firestore/operations/deletefield.ts","../src/migration/firestore/operations/replayprojections.ts","../src/ops/auditdenormalized.ts","../src/ops/auditpermissions.ts","../src/ops/auditrelations.ts","../src/ops/explainpreloadqueries.ts","../src/ops/getuser.ts","../src/ops/getuserpermissions.ts","../src/ops/getuserrecord.ts","../src/ops/listprojects.ts","../src/ops/mfastatus.ts","../src/ops/setusercollection.ts","../src/ops/setuserdocument.ts","../src/ops/setuserrole.ts","../src/project/addproject.ts","../src/project/addrecord.ts","../src/project/addrecordprompt.ts","../src/project/addtenant.ts","../src/project/buildwebapp.ts","../src/project/customdomain.ts","../src/project/deleteproject.ts","../src/project/deleterecord.ts","../src/project/deletetenant.ts","../src/project/getone.ts","../src/project/getsome.ts","../src/project/initproject.ts","../src/project/prepareemulatordata.ts","../src/project/setproject.ts","../src/project/startemulators.ts","../src/project/updaterecord.ts","../src/types/generatetypes.ts"],"version":"6.0.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoker-platform/cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.140",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"main": "./lib/src/main.js",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"@google-cloud/secret-manager": "^6.1.2",
|
|
25
25
|
"@google-cloud/storage": "^7.19.0",
|
|
26
26
|
"@inquirer/prompts": "^8.5.2",
|
|
27
|
-
"@stoker-platform/node-client": "0.5.
|
|
27
|
+
"@stoker-platform/node-client": "0.5.88",
|
|
28
28
|
"@stoker-platform/types": "0.5.65",
|
|
29
|
-
"@stoker-platform/utils": "0.5.
|
|
29
|
+
"@stoker-platform/utils": "0.5.79",
|
|
30
30
|
"algoliasearch": "^5.53.0",
|
|
31
31
|
"commander": "^15.0.0",
|
|
32
32
|
"cross-spawn": "^7.0.6",
|