@pbvision/firestore-orm 0.0.25 → 0.0.27

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": "@pbvision/firestore-orm",
3
- "version": "0.0.25",
3
+ "version": "0.0.27",
4
4
  "description": "Firestore ORM Library",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/src/context.js CHANGED
@@ -405,10 +405,23 @@ export class Context {
405
405
  await model.__write(this)
406
406
  }
407
407
 
408
- __throwIfWritesNotAllowed (data) {
409
- if (this.options.readOnly) {
410
- throw new WriteAttemptedInReadOnlyTxError(data)
408
+ __throwIfWritesNotAllowed (modelOrKey) {
409
+ if (!this.options.readOnly) {
410
+ return
411
+ }
412
+ let key = modelOrKey
413
+ let fieldNames = []
414
+ if (modelOrKey instanceof Model) {
415
+ key = modelOrKey.__key
416
+ fieldNames = Object.values(modelOrKey.__cached_attrs)
417
+ .filter(field => field.hasChangesToCommit(false))
418
+ .map(field => field.name)
411
419
  }
420
+ // delete() checks for read-only before it checks its args
421
+ const doc = key instanceof Key
422
+ ? `${key.Cls.collectionName} _id=${key.encodedKey}`
423
+ : 'an unknown doc'
424
+ throw new WriteAttemptedInReadOnlyTxError(doc, fieldNames)
412
425
  }
413
426
 
414
427
  /**
@@ -678,7 +691,16 @@ function parseFirestoreError (err) {
678
691
  }
679
692
  }
680
693
 
694
+ // production Firestore names the document's full resource path, e.g.
695
+ // "Document already exists: projects/p/databases/(default)/documents/Type/id"
696
+ const PRODUCTION_ALREADY_EXISTS_PATH =
697
+ /Document already exists: projects\/[^/]+\/databases\/[^/]+\/documents\/(.+)$/s
698
+
681
699
  function parseFirestoreErrorPath (err) {
700
+ const docPath = PRODUCTION_ALREADY_EXISTS_PATH.exec(err.message)?.[1]
701
+ if (docPath) {
702
+ return splitDocPath(docPath)
703
+ }
682
704
  const startIdx = err.message.indexOf('Element {')
683
705
  if (startIdx >= 0) {
684
706
  const endIdx = err.message.indexOf('}', startIdx)
@@ -714,9 +736,13 @@ function parseFirestoreErrorPathAlternate (err) {
714
736
  if (endIdx < startIdx) {
715
737
  return
716
738
  }
717
- const path = err.message.substring(startIdx + 5, endIdx)
718
- const pieces = path.split('/', 2)
719
- if (pieces.length === 2) {
739
+ return splitDocPath(err.message.substring(startIdx + 5, endIdx))
740
+ }
741
+
742
+ // "Type/id", with or without a leading slash
743
+ function splitDocPath (path) {
744
+ const pieces = path.replace(/^\//, '').split('/')
745
+ if (pieces.length === 2 && pieces[0] && pieces[1]) {
720
746
  return { collection: pieces[0], id: pieces[1] }
721
747
  }
722
748
  }
package/src/errors.js CHANGED
@@ -135,12 +135,20 @@ export class DeletedTwiceError extends GenericModelError {
135
135
 
136
136
  /**
137
137
  * Thrown when a tx tries to write when it was marked read-only.
138
+ *
139
+ * Names the doc and the fields it would have changed, never their values: a
140
+ * model can hold secrets, and this message ends up in logs and error reports
141
+ * (and, through an error handler that returns crash messages, in API
142
+ * responses).
138
143
  * @memberof Errors
139
144
  */
140
145
  export class WriteAttemptedInReadOnlyTxError extends Error {
141
- constructor (dataToWrite) {
142
- super(`Tried to write model in a read-only transaction with the following
143
- changes ${JSON.stringify(dataToWrite)}`)
146
+ constructor (doc, fieldNames) {
147
+ const fields = fieldNames.length
148
+ ? ` (changed fields: ${fieldNames.join(', ')})`
149
+ : ''
150
+ super(`Tried to write ${doc} in a read-only transaction${fields}`)
151
+ this.name = this.constructor.name
144
152
  }
145
153
  }
146
154