@dereekb/firebase-server 12.7.0 → 13.0.1

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.
Files changed (343) hide show
  1. package/LICENSE +1 -1
  2. package/index.cjs.default.js +1 -0
  3. package/index.cjs.js +2859 -0
  4. package/index.cjs.mjs +2 -0
  5. package/index.esm.js +2699 -0
  6. package/mailgun/index.cjs.default.js +1 -0
  7. package/mailgun/{src/lib/auth.mailgun.js → index.cjs.js} +6 -6
  8. package/mailgun/index.cjs.mjs +2 -0
  9. package/mailgun/index.esm.js +39 -0
  10. package/mailgun/package.json +20 -5
  11. package/model/index.cjs.default.js +1 -0
  12. package/model/index.cjs.js +4767 -0
  13. package/model/index.cjs.mjs +2 -0
  14. package/model/index.d.ts +1 -0
  15. package/model/index.esm.js +4630 -0
  16. package/model/package.json +28 -4
  17. package/model/src/lib/notification/notification.module.d.ts +10 -10
  18. package/model/src/lib/storagefile/storagefile.task.service.handler.d.ts +3 -14
  19. package/package.json +49 -47
  20. package/src/lib/auth/auth.context.d.ts +1 -1
  21. package/src/lib/auth/auth.service.d.ts +1 -1
  22. package/src/lib/function/assert.d.ts +2 -2
  23. package/src/lib/function/context.d.ts +1 -1
  24. package/src/lib/function/error.d.ts +0 -8
  25. package/src/lib/index.d.ts +1 -0
  26. package/src/lib/nest/app.d.ts +1 -1
  27. package/src/lib/nest/development/development.app.function.d.ts +1 -2
  28. package/src/lib/nest/function/call.d.ts +1 -1
  29. package/src/lib/nest/function/context.d.ts +0 -4
  30. package/src/lib/nest/function/index.d.ts +0 -1
  31. package/src/lib/nest/function/nest.d.ts +1 -1
  32. package/src/lib/nest/function/v2/blocking.d.ts +3 -2
  33. package/src/lib/nest/model/crud.assert.function.d.ts +0 -4
  34. package/src/lib/storage/storage.d.ts +1 -1
  35. package/src/lib/type.d.ts +9 -0
  36. package/test/index.cjs.default.js +1 -0
  37. package/test/index.cjs.js +1258 -0
  38. package/test/index.cjs.mjs +2 -0
  39. package/test/index.d.ts +1 -0
  40. package/test/index.esm.js +1181 -0
  41. package/test/package.json +31 -4
  42. package/test/src/lib/firebase/firebase.admin.auth.d.ts +22 -13
  43. package/test/src/lib/firebase/firebase.admin.collection.d.ts +6 -6
  44. package/test/src/lib/firebase/firebase.admin.d.ts +10 -10
  45. package/test/src/lib/firebase/firebase.admin.function.d.ts +9 -9
  46. package/test/src/lib/firebase/firebase.admin.nest.d.ts +8 -8
  47. package/test/src/lib/firebase/firebase.admin.nest.function.d.ts +9 -9
  48. package/test/src/lib/firebase/firebase.test.d.ts +30 -0
  49. package/test/src/lib/firebase/index.d.ts +1 -1
  50. package/test/src/lib/firestore/firestore.admin.d.ts +3 -3
  51. package/test/src/lib/firestore/firestore.d.ts +2 -2
  52. package/test/src/lib/storage/storage.admin.d.ts +3 -3
  53. package/test/src/lib/storage/storage.d.ts +2 -2
  54. package/zoho/LICENSE +1 -1
  55. package/zoho/index.cjs.default.js +1 -0
  56. package/zoho/index.cjs.js +82 -85
  57. package/zoho/index.cjs.mjs +2 -0
  58. package/zoho/index.d.ts +1 -0
  59. package/zoho/index.esm.js +84 -87
  60. package/zoho/package.json +15 -15
  61. package/CHANGELOG.md +0 -2237
  62. package/mailgun/src/index.js +0 -5
  63. package/mailgun/src/index.js.map +0 -1
  64. package/mailgun/src/lib/auth.mailgun.js.map +0 -1
  65. package/mailgun/src/lib/index.js +0 -5
  66. package/mailgun/src/lib/index.js.map +0 -1
  67. package/model/src/index.js +0 -5
  68. package/model/src/index.js.map +0 -1
  69. package/model/src/lib/index.js +0 -7
  70. package/model/src/lib/index.js.map +0 -1
  71. package/model/src/lib/mailgun/index.js +0 -5
  72. package/model/src/lib/mailgun/index.js.map +0 -1
  73. package/model/src/lib/mailgun/notification.send.service.mailgun.js +0 -68
  74. package/model/src/lib/mailgun/notification.send.service.mailgun.js.map +0 -1
  75. package/model/src/lib/notification/index.js +0 -20
  76. package/model/src/lib/notification/index.js.map +0 -1
  77. package/model/src/lib/notification/notification.action.init.service.js +0 -230
  78. package/model/src/lib/notification/notification.action.init.service.js.map +0 -1
  79. package/model/src/lib/notification/notification.action.service.js +0 -1487
  80. package/model/src/lib/notification/notification.action.service.js.map +0 -1
  81. package/model/src/lib/notification/notification.config.js +0 -13
  82. package/model/src/lib/notification/notification.config.js.map +0 -1
  83. package/model/src/lib/notification/notification.config.service.js +0 -60
  84. package/model/src/lib/notification/notification.config.service.js.map +0 -1
  85. package/model/src/lib/notification/notification.create.run.js +0 -59
  86. package/model/src/lib/notification/notification.create.run.js.map +0 -1
  87. package/model/src/lib/notification/notification.error.js +0 -87
  88. package/model/src/lib/notification/notification.error.js.map +0 -1
  89. package/model/src/lib/notification/notification.expedite.service.js +0 -112
  90. package/model/src/lib/notification/notification.expedite.service.js.map +0 -1
  91. package/model/src/lib/notification/notification.module.js +0 -106
  92. package/model/src/lib/notification/notification.module.js.map +0 -1
  93. package/model/src/lib/notification/notification.send.js +0 -3
  94. package/model/src/lib/notification/notification.send.js.map +0 -1
  95. package/model/src/lib/notification/notification.send.service.js +0 -10
  96. package/model/src/lib/notification/notification.send.service.js.map +0 -1
  97. package/model/src/lib/notification/notification.send.service.notificationsummary.js +0 -104
  98. package/model/src/lib/notification/notification.send.service.notificationsummary.js.map +0 -1
  99. package/model/src/lib/notification/notification.send.service.text.js +0 -29
  100. package/model/src/lib/notification/notification.send.service.text.js.map +0 -1
  101. package/model/src/lib/notification/notification.task.service.handler.js +0 -65
  102. package/model/src/lib/notification/notification.task.service.handler.js.map +0 -1
  103. package/model/src/lib/notification/notification.task.service.js +0 -10
  104. package/model/src/lib/notification/notification.task.service.js.map +0 -1
  105. package/model/src/lib/notification/notification.task.service.util.js +0 -27
  106. package/model/src/lib/notification/notification.task.service.util.js.map +0 -1
  107. package/model/src/lib/notification/notification.task.subtask.handler.js +0 -256
  108. package/model/src/lib/notification/notification.task.subtask.handler.js.map +0 -1
  109. package/model/src/lib/notification/notification.util.js +0 -478
  110. package/model/src/lib/notification/notification.util.js.map +0 -1
  111. package/model/src/lib/storagefile/index.js +0 -12
  112. package/model/src/lib/storagefile/index.js.map +0 -1
  113. package/model/src/lib/storagefile/storagefile.action.init.service.js +0 -155
  114. package/model/src/lib/storagefile/storagefile.action.init.service.js.map +0 -1
  115. package/model/src/lib/storagefile/storagefile.action.server.js +0 -797
  116. package/model/src/lib/storagefile/storagefile.action.server.js.map +0 -1
  117. package/model/src/lib/storagefile/storagefile.error.js +0 -106
  118. package/model/src/lib/storagefile/storagefile.error.js.map +0 -1
  119. package/model/src/lib/storagefile/storagefile.module.js +0 -64
  120. package/model/src/lib/storagefile/storagefile.module.js.map +0 -1
  121. package/model/src/lib/storagefile/storagefile.task.service.handler.js +0 -287
  122. package/model/src/lib/storagefile/storagefile.task.service.handler.js.map +0 -1
  123. package/model/src/lib/storagefile/storagefile.upload.service.initializer.js +0 -180
  124. package/model/src/lib/storagefile/storagefile.upload.service.initializer.js.map +0 -1
  125. package/model/src/lib/storagefile/storagefile.upload.service.js +0 -10
  126. package/model/src/lib/storagefile/storagefile.upload.service.js.map +0 -1
  127. package/model/src/lib/storagefile/storagefile.util.js +0 -54
  128. package/model/src/lib/storagefile/storagefile.util.js.map +0 -1
  129. package/src/index.js +0 -5
  130. package/src/index.js.map +0 -1
  131. package/src/lib/auth/auth.context.js +0 -13
  132. package/src/lib/auth/auth.context.js.map +0 -1
  133. package/src/lib/auth/auth.service.error.js +0 -34
  134. package/src/lib/auth/auth.service.error.js.map +0 -1
  135. package/src/lib/auth/auth.service.js +0 -427
  136. package/src/lib/auth/auth.service.js.map +0 -1
  137. package/src/lib/auth/auth.util.js +0 -23
  138. package/src/lib/auth/auth.util.js.map +0 -1
  139. package/src/lib/auth/index.js +0 -8
  140. package/src/lib/auth/index.js.map +0 -1
  141. package/src/lib/env/env.service.js +0 -7
  142. package/src/lib/env/env.service.js.map +0 -1
  143. package/src/lib/env/index.js +0 -5
  144. package/src/lib/env/index.js.map +0 -1
  145. package/src/lib/firestore/array.js +0 -34
  146. package/src/lib/firestore/array.js.map +0 -1
  147. package/src/lib/firestore/driver.accessor.batch.js +0 -93
  148. package/src/lib/firestore/driver.accessor.batch.js.map +0 -1
  149. package/src/lib/firestore/driver.accessor.default.js +0 -62
  150. package/src/lib/firestore/driver.accessor.default.js.map +0 -1
  151. package/src/lib/firestore/driver.accessor.js +0 -50
  152. package/src/lib/firestore/driver.accessor.js.map +0 -1
  153. package/src/lib/firestore/driver.accessor.transaction.js +0 -96
  154. package/src/lib/firestore/driver.accessor.transaction.js.map +0 -1
  155. package/src/lib/firestore/driver.js +0 -14
  156. package/src/lib/firestore/driver.js.map +0 -1
  157. package/src/lib/firestore/driver.query.js +0 -55
  158. package/src/lib/firestore/driver.query.js.map +0 -1
  159. package/src/lib/firestore/firestore.js +0 -10
  160. package/src/lib/firestore/firestore.js.map +0 -1
  161. package/src/lib/firestore/increment.js +0 -17
  162. package/src/lib/firestore/increment.js.map +0 -1
  163. package/src/lib/firestore/index.js +0 -9
  164. package/src/lib/firestore/index.js.map +0 -1
  165. package/src/lib/function/assert.js +0 -68
  166. package/src/lib/function/assert.js.map +0 -1
  167. package/src/lib/function/context.js +0 -14
  168. package/src/lib/function/context.js.map +0 -1
  169. package/src/lib/function/error.auth.js +0 -25
  170. package/src/lib/function/error.auth.js.map +0 -1
  171. package/src/lib/function/error.js +0 -221
  172. package/src/lib/function/error.js.map +0 -1
  173. package/src/lib/function/index.js +0 -9
  174. package/src/lib/function/index.js.map +0 -1
  175. package/src/lib/function/type.js +0 -3
  176. package/src/lib/function/type.js.map +0 -1
  177. package/src/lib/index.js +0 -11
  178. package/src/lib/index.js.map +0 -1
  179. package/src/lib/nest/app.js +0 -114
  180. package/src/lib/nest/app.js.map +0 -1
  181. package/src/lib/nest/auth/auth.module.js +0 -60
  182. package/src/lib/nest/auth/auth.module.js.map +0 -1
  183. package/src/lib/nest/auth/auth.util.js +0 -72
  184. package/src/lib/nest/auth/auth.util.js.map +0 -1
  185. package/src/lib/nest/auth/index.js +0 -6
  186. package/src/lib/nest/auth/index.js.map +0 -1
  187. package/src/lib/nest/development/development.app.function.js +0 -38
  188. package/src/lib/nest/development/development.app.function.js.map +0 -1
  189. package/src/lib/nest/development/development.assert.function.js +0 -3
  190. package/src/lib/nest/development/development.assert.function.js.map +0 -1
  191. package/src/lib/nest/development/development.function.js +0 -41
  192. package/src/lib/nest/development/development.function.js.map +0 -1
  193. package/src/lib/nest/development/development.schedule.function.error.js +0 -35
  194. package/src/lib/nest/development/development.schedule.function.error.js.map +0 -1
  195. package/src/lib/nest/development/development.schedule.function.js +0 -54
  196. package/src/lib/nest/development/development.schedule.function.js.map +0 -1
  197. package/src/lib/nest/development/index.js +0 -9
  198. package/src/lib/nest/development/index.js.map +0 -1
  199. package/src/lib/nest/env/env.service.js +0 -19
  200. package/src/lib/nest/env/env.service.js.map +0 -1
  201. package/src/lib/nest/env/env.util.js +0 -12
  202. package/src/lib/nest/env/env.util.js.map +0 -1
  203. package/src/lib/nest/env/index.js +0 -6
  204. package/src/lib/nest/env/index.js.map +0 -1
  205. package/src/lib/nest/firebase/firebase.module.js +0 -17
  206. package/src/lib/nest/firebase/firebase.module.js.map +0 -1
  207. package/src/lib/nest/firebase/index.js +0 -5
  208. package/src/lib/nest/firebase/index.js.map +0 -1
  209. package/src/lib/nest/firestore/firestore.module.js +0 -86
  210. package/src/lib/nest/firestore/firestore.module.js.map +0 -1
  211. package/src/lib/nest/firestore/index.js +0 -5
  212. package/src/lib/nest/firestore/index.js.map +0 -1
  213. package/src/lib/nest/function/call.js +0 -46
  214. package/src/lib/nest/function/call.js.map +0 -1
  215. package/src/lib/nest/function/context.js +0 -79
  216. package/src/lib/nest/function/context.js.map +0 -1
  217. package/src/lib/nest/function/index.js +0 -10
  218. package/src/lib/nest/function/index.js.map +0 -1
  219. package/src/lib/nest/function/nest.js +0 -17
  220. package/src/lib/nest/function/nest.js.map +0 -1
  221. package/src/lib/nest/function/schedule.js +0 -8
  222. package/src/lib/nest/function/schedule.js.map +0 -1
  223. package/src/lib/nest/function/v1/call.d.ts +0 -59
  224. package/src/lib/nest/function/v1/call.js +0 -55
  225. package/src/lib/nest/function/v1/call.js.map +0 -1
  226. package/src/lib/nest/function/v1/event.d.ts +0 -80
  227. package/src/lib/nest/function/v1/event.js +0 -52
  228. package/src/lib/nest/function/v1/event.js.map +0 -1
  229. package/src/lib/nest/function/v1/index.d.ts +0 -3
  230. package/src/lib/nest/function/v1/index.js +0 -7
  231. package/src/lib/nest/function/v1/index.js.map +0 -1
  232. package/src/lib/nest/function/v1/schedule.d.ts +0 -47
  233. package/src/lib/nest/function/v1/schedule.js +0 -68
  234. package/src/lib/nest/function/v1/schedule.js.map +0 -1
  235. package/src/lib/nest/function/v2/blocking.js +0 -38
  236. package/src/lib/nest/function/v2/blocking.js.map +0 -1
  237. package/src/lib/nest/function/v2/call.js +0 -31
  238. package/src/lib/nest/function/v2/call.js.map +0 -1
  239. package/src/lib/nest/function/v2/event.js +0 -25
  240. package/src/lib/nest/function/v2/event.js.map +0 -1
  241. package/src/lib/nest/function/v2/index.js +0 -9
  242. package/src/lib/nest/function/v2/index.js.map +0 -1
  243. package/src/lib/nest/function/v2/schedule.js +0 -56
  244. package/src/lib/nest/function/v2/schedule.js.map +0 -1
  245. package/src/lib/nest/function/v2/taskqueue.js +0 -26
  246. package/src/lib/nest/function/v2/taskqueue.js.map +0 -1
  247. package/src/lib/nest/index.js +0 -15
  248. package/src/lib/nest/index.js.map +0 -1
  249. package/src/lib/nest/middleware/appcheck.decorator.js +0 -12
  250. package/src/lib/nest/middleware/appcheck.decorator.js.map +0 -1
  251. package/src/lib/nest/middleware/appcheck.js +0 -3
  252. package/src/lib/nest/middleware/appcheck.js.map +0 -1
  253. package/src/lib/nest/middleware/appcheck.middleware.js +0 -74
  254. package/src/lib/nest/middleware/appcheck.middleware.js.map +0 -1
  255. package/src/lib/nest/middleware/appcheck.module.js +0 -21
  256. package/src/lib/nest/middleware/appcheck.module.js.map +0 -1
  257. package/src/lib/nest/middleware/globalprefix.js +0 -11
  258. package/src/lib/nest/middleware/globalprefix.js.map +0 -1
  259. package/src/lib/nest/middleware/index.js +0 -10
  260. package/src/lib/nest/middleware/index.js.map +0 -1
  261. package/src/lib/nest/middleware/rawbody.middleware.js +0 -16
  262. package/src/lib/nest/middleware/rawbody.middleware.js.map +0 -1
  263. package/src/lib/nest/middleware/webhook.js +0 -24
  264. package/src/lib/nest/middleware/webhook.js.map +0 -1
  265. package/src/lib/nest/model/call.model.function.js +0 -73
  266. package/src/lib/nest/model/call.model.function.js.map +0 -1
  267. package/src/lib/nest/model/create.model.function.js +0 -27
  268. package/src/lib/nest/model/create.model.function.js.map +0 -1
  269. package/src/lib/nest/model/crud.assert.function.js +0 -3
  270. package/src/lib/nest/model/crud.assert.function.js.map +0 -1
  271. package/src/lib/nest/model/delete.model.function.js +0 -27
  272. package/src/lib/nest/model/delete.model.function.js.map +0 -1
  273. package/src/lib/nest/model/index.js +0 -11
  274. package/src/lib/nest/model/index.js.map +0 -1
  275. package/src/lib/nest/model/permission.error.js +0 -24
  276. package/src/lib/nest/model/permission.error.js.map +0 -1
  277. package/src/lib/nest/model/read.model.function.js +0 -27
  278. package/src/lib/nest/model/read.model.function.js.map +0 -1
  279. package/src/lib/nest/model/specifier.function.js +0 -35
  280. package/src/lib/nest/model/specifier.function.js.map +0 -1
  281. package/src/lib/nest/model/update.model.function.js +0 -27
  282. package/src/lib/nest/model/update.model.function.js.map +0 -1
  283. package/src/lib/nest/nest.provider.js +0 -89
  284. package/src/lib/nest/nest.provider.js.map +0 -1
  285. package/src/lib/nest/storage/index.js +0 -5
  286. package/src/lib/nest/storage/index.js.map +0 -1
  287. package/src/lib/nest/storage/storage.module.js +0 -112
  288. package/src/lib/nest/storage/storage.module.js.map +0 -1
  289. package/src/lib/storage/driver.accessor.js +0 -299
  290. package/src/lib/storage/driver.accessor.js.map +0 -1
  291. package/src/lib/storage/driver.js +0 -12
  292. package/src/lib/storage/driver.js.map +0 -1
  293. package/src/lib/storage/index.js +0 -8
  294. package/src/lib/storage/index.js.map +0 -1
  295. package/src/lib/storage/storage.js +0 -20
  296. package/src/lib/storage/storage.js.map +0 -1
  297. package/src/lib/storage/storage.service.js +0 -26
  298. package/src/lib/storage/storage.service.js.map +0 -1
  299. package/test/src/index.js +0 -5
  300. package/test/src/index.js.map +0 -1
  301. package/test/src/lib/firebase/firebase.admin.auth.js +0 -260
  302. package/test/src/lib/firebase/firebase.admin.auth.js.map +0 -1
  303. package/test/src/lib/firebase/firebase.admin.collection.js +0 -108
  304. package/test/src/lib/firebase/firebase.admin.collection.js.map +0 -1
  305. package/test/src/lib/firebase/firebase.admin.function.js +0 -132
  306. package/test/src/lib/firebase/firebase.admin.function.js.map +0 -1
  307. package/test/src/lib/firebase/firebase.admin.js +0 -174
  308. package/test/src/lib/firebase/firebase.admin.js.map +0 -1
  309. package/test/src/lib/firebase/firebase.admin.nest.function.callable.context.js +0 -42
  310. package/test/src/lib/firebase/firebase.admin.nest.function.callable.context.js.map +0 -1
  311. package/test/src/lib/firebase/firebase.admin.nest.function.cloud.context.js +0 -40
  312. package/test/src/lib/firebase/firebase.admin.nest.function.cloud.context.js.map +0 -1
  313. package/test/src/lib/firebase/firebase.admin.nest.function.js +0 -64
  314. package/test/src/lib/firebase/firebase.admin.nest.function.js.map +0 -1
  315. package/test/src/lib/firebase/firebase.admin.nest.js +0 -107
  316. package/test/src/lib/firebase/firebase.admin.nest.js.map +0 -1
  317. package/test/src/lib/firebase/firebase.admin.test.server.js +0 -37
  318. package/test/src/lib/firebase/firebase.admin.test.server.js.map +0 -1
  319. package/test/src/lib/firebase/firebase.function.js +0 -58
  320. package/test/src/lib/firebase/firebase.function.js.map +0 -1
  321. package/test/src/lib/firebase/firebase.jest.d.ts +0 -21
  322. package/test/src/lib/firebase/firebase.jest.js +0 -45
  323. package/test/src/lib/firebase/firebase.jest.js.map +0 -1
  324. package/test/src/lib/firebase/firebase.js +0 -74
  325. package/test/src/lib/firebase/firebase.js.map +0 -1
  326. package/test/src/lib/firebase/index.js +0 -15
  327. package/test/src/lib/firebase/index.js.map +0 -1
  328. package/test/src/lib/firestore/firestore.admin.js +0 -21
  329. package/test/src/lib/firestore/firestore.admin.js.map +0 -1
  330. package/test/src/lib/firestore/firestore.js +0 -57
  331. package/test/src/lib/firestore/firestore.js.map +0 -1
  332. package/test/src/lib/firestore/index.js +0 -6
  333. package/test/src/lib/firestore/index.js.map +0 -1
  334. package/test/src/lib/index.js +0 -7
  335. package/test/src/lib/index.js.map +0 -1
  336. package/test/src/lib/storage/index.js +0 -6
  337. package/test/src/lib/storage/index.js.map +0 -1
  338. package/test/src/lib/storage/storage.admin.js +0 -21
  339. package/test/src/lib/storage/storage.admin.js.map +0 -1
  340. package/test/src/lib/storage/storage.js +0 -59
  341. package/test/src/lib/storage/storage.js.map +0 -1
  342. /package/{zoho/index.cjs.d.ts → index.d.ts} +0 -0
  343. /package/{zoho/index.esm.d.ts → mailgun/index.d.ts} +0 -0
package/index.esm.js ADDED
@@ -0,0 +1,2699 @@
1
+ import { DBX_FIREBASE_SERVER_NO_AUTH_ERROR_CODE, FIREBASE_AUTH_USER_NOT_FOUND_ERROR, FIREBASE_SERVER_AUTH_CLAIMS_RESET_LAST_COM_DATE_KEY, FIREBASE_SERVER_AUTH_CLAIMS_RESET_PASSWORD_KEY, FIREBASE_SERVER_AUTH_CLAIMS_SETUP_PASSWORD_KEY, FIREBASE_SERVER_AUTH_CLAIMS_SETUP_LAST_COM_DATE_KEY, FirestoreDocumentContextType, streamFromOnSnapshot, makeFirestoreQueryConstraintFunctionsDriver, FIRESTORE_END_BEFORE_QUERY_CONSTRAINT_TYPE, FIRESTORE_END_AT_VALUE_QUERY_CONSTRAINT_TYPE, FIRESTORE_END_AT_QUERY_CONSTRAINT_TYPE, FIRESTORE_START_AFTER_QUERY_CONSTRAINT_TYPE, FIRESTORE_START_AT_VALUE_QUERY_CONSTRAINT_TYPE, FIRESTORE_START_AT_QUERY_CONSTRAINT_TYPE, FIRESTORE_OFFSET_QUERY_CONSTRAINT_TYPE, FIRESTORE_WHERE_DOCUMENT_ID_QUERY_CONSTRAINT_TYPE, FIRESTORE_WHERE_QUERY_CONSTRAINT_TYPE, FIRESTORE_ORDER_BY_DOCUMENT_ID_QUERY_CONSTRAINT_TYPE, FIRESTORE_ORDER_BY_QUERY_CONSTRAINT_TYPE, FIRESTORE_LIMIT_TO_LAST_QUERY_CONSTRAINT_TYPE, FIRESTORE_LIMIT_QUERY_CONSTRAINT_TYPE, firestoreContextFactory, setIdAndKeyFromKeyIdRefOnDocumentData, SCHEDULED_FUNCTION_DEV_FUNCTION_SPECIFIER, MODEL_FUNCTION_FIREBASE_CRUD_FUNCTION_SPECIFIER_DEFAULT, storageListFilesResultFactory, assertStorageUploadOptionsStringFormat, firebaseStorageContextFactory, inContextFirebaseModelsServiceFactory, useFirebaseModelsService } from '@dereekb/firebase';
2
+ import { partialServerError, isServerError, randomNumberFactory, cachedGetter, AUTH_ADMIN_ROLE, AUTH_TOS_SIGNED_ROLE, forEachKeyValue, KeyValueTypleValueFilter, filterNullAndUndefinedValues, asSet, filterUndefinedValues, isThrottled, mapObjectMap, batch, asArray, containsAllValues, serverError, mergeObjects, cronExpressionRepeatingEveryNMinutes, mapIdentityFunction, objectToMap, slashPathName, SLASH_PATH_SEPARATOR, toRelativeSlashPathStartType, fixMultiSlashesInSlashPath, objectHasNoKeys, makeGetter, asGetter, pushItemOrArrayItemsIntoArray, build } from '@dereekb/util';
3
+ import { HttpsError } from 'firebase-functions/https';
4
+ import { hoursToMs, toISODateString } from '@dereekb/date';
5
+ import { BaseError } from 'make-error';
6
+ import { from } from 'rxjs';
7
+ import { FieldValue, FieldPath } from '@google-cloud/firestore';
8
+ import { Module, Injectable, ValidationPipe, Optional, Inject, Logger, ForbiddenException, createParamDecorator } from '@nestjs/common';
9
+ import { mergeModuleMetadata, ServerEnvironmentService, DEFAULT_BASE_WEBHOOK_PATH, DEFAULT_WEBHOOK_MIDDLEWARE_ROUTE_INFO, isTestNodeEnv, injectionTokensFromProviders, serverEnvTokenProvider } from '@dereekb/nestjs';
10
+ import { https, scheduler } from 'firebase-functions/v2';
11
+ import { toTransformAndValidateFunctionResultFactory, transformAndValidateObjectFactory } from '@dereekb/model';
12
+ import admin from 'firebase-admin';
13
+ import { ApiError } from '@google-cloud/storage';
14
+ import { addMilliseconds, addHours } from 'date-fns';
15
+ import { isUint8Array, isArrayBuffer } from 'util/types';
16
+ import { NestFactory } from '@nestjs/core';
17
+ import { ExpressAdapter } from '@nestjs/platform-express';
18
+ import express from 'express';
19
+
20
+ function unauthenticatedContextHasNoAuthData() {
21
+ return unauthenticatedError({
22
+ message: 'expected auth',
23
+ code: DBX_FIREBASE_SERVER_NO_AUTH_ERROR_CODE
24
+ });
25
+ }
26
+ function unauthenticatedContextHasNoUidError() {
27
+ return unauthenticatedError({
28
+ message: 'no user uid',
29
+ code: DBX_FIREBASE_SERVER_NO_AUTH_ERROR_CODE
30
+ });
31
+ }
32
+ // MARK: General Errors
33
+ const UNAUTHENTICATED_ERROR_CODE = 'UNAUTHENTICATED';
34
+ function unauthenticatedError(messageOrError) {
35
+ const serverError = partialServerError(messageOrError);
36
+ return new HttpsError('unauthenticated', serverError?.message || 'unauthenticated', {
37
+ status: 401,
38
+ code: UNAUTHENTICATED_ERROR_CODE,
39
+ ...serverError,
40
+ _error: undefined
41
+ });
42
+ }
43
+ const FORBIDDEN_ERROR_CODE = 'FORBIDDEN';
44
+ function forbiddenError(messageOrError) {
45
+ const serverError = partialServerError(messageOrError);
46
+ return new HttpsError('permission-denied', serverError?.message || 'forbidden', {
47
+ status: 403,
48
+ code: FORBIDDEN_ERROR_CODE,
49
+ ...serverError,
50
+ _error: undefined
51
+ });
52
+ }
53
+ const PERMISSION_DENIED_ERROR_CODE = 'PERMISSION_DENIED';
54
+ function permissionDeniedError(messageOrError) {
55
+ const serverError = partialServerError(messageOrError);
56
+ return new HttpsError('permission-denied', serverError?.message || 'permission denied', {
57
+ status: 403,
58
+ code: PERMISSION_DENIED_ERROR_CODE,
59
+ ...serverError,
60
+ _error: undefined
61
+ });
62
+ }
63
+ const NOT_FOUND_ERROR_CODE = 'NOT_FOUND';
64
+ function notFoundError(messageOrError) {
65
+ const serverError = partialServerError(messageOrError);
66
+ return new HttpsError('not-found', serverError?.message || 'not found', {
67
+ status: 404,
68
+ code: NOT_FOUND_ERROR_CODE,
69
+ ...serverError,
70
+ _error: undefined
71
+ });
72
+ }
73
+ const MODEL_NOT_AVAILABLE_ERROR_CODE = 'MODEL_NOT_AVAILABLE';
74
+ function modelNotAvailableError(messageOrError) {
75
+ const serverError = partialServerError(messageOrError);
76
+ return new HttpsError('not-found', serverError?.message || 'model was not available', {
77
+ status: 404,
78
+ code: MODEL_NOT_AVAILABLE_ERROR_CODE,
79
+ ...serverError,
80
+ _error: undefined
81
+ });
82
+ }
83
+ const BAD_REQUEST_ERROR_CODE = 'BAD_REQUEST';
84
+ function badRequestError(messageOrError) {
85
+ const serverError = partialServerError(messageOrError);
86
+ return new HttpsError('invalid-argument', serverError?.message || 'bad request', {
87
+ status: 400,
88
+ code: BAD_REQUEST_ERROR_CODE,
89
+ ...serverError,
90
+ _error: undefined
91
+ });
92
+ }
93
+ const CONFLICT_ERROR_CODE = 'CONFLICT';
94
+ function preconditionConflictError(messageOrError) {
95
+ const serverError = partialServerError(messageOrError);
96
+ return new HttpsError('failed-precondition', serverError?.message || 'conflict', {
97
+ status: 409,
98
+ code: CONFLICT_ERROR_CODE,
99
+ ...serverError,
100
+ _error: undefined
101
+ });
102
+ }
103
+ const ALREADY_EXISTS_ERROR_CODE = 'ALREADY_EXISTS';
104
+ function alreadyExistsError(messageOrError) {
105
+ const serverError = partialServerError(messageOrError);
106
+ return new HttpsError('already-exists', serverError?.message || 'already exists', {
107
+ status: 409,
108
+ code: ALREADY_EXISTS_ERROR_CODE,
109
+ ...serverError,
110
+ _error: undefined
111
+ });
112
+ }
113
+ const UNAVAILABLE_ERROR_CODE = 'UNAVAILABLE';
114
+ function unavailableError(messageOrError) {
115
+ const serverError = partialServerError(messageOrError);
116
+ return new HttpsError('unavailable', serverError?.message || 'service unavailable', {
117
+ status: 503,
118
+ code: UNAVAILABLE_ERROR_CODE,
119
+ ...serverError,
120
+ _error: undefined
121
+ });
122
+ }
123
+ const UNAVAILABLE_OR_DEACTIVATED_FUNCTION_ERROR_CODE = 'UNAVAILABLE_OR_DEACTIVATED_FUNCTION';
124
+ function unavailableOrDeactivatedFunctionError(messageOrError) {
125
+ const serverError = partialServerError(messageOrError);
126
+ return new HttpsError('unimplemented', serverError?.message || 'the requested function is not available or has been deactivated for use', {
127
+ status: 501,
128
+ code: UNAVAILABLE_OR_DEACTIVATED_FUNCTION_ERROR_CODE,
129
+ ...serverError,
130
+ _error: undefined
131
+ });
132
+ }
133
+ const INTERNAL_SERVER_ERROR_CODE = 'INTERNAL_ERROR';
134
+ function internalServerError(messageOrError) {
135
+ const serverError = partialServerError(messageOrError);
136
+ return new HttpsError('internal', serverError?.message || 'internal error', {
137
+ status: 500,
138
+ code: INTERNAL_SERVER_ERROR_CODE,
139
+ ...serverError,
140
+ _error: undefined
141
+ });
142
+ }
143
+ function isFirebaseHttpsError(input) {
144
+ return typeof input === 'object' && input.code != null && input.httpErrorCode != null && input.toJSON != null;
145
+ }
146
+ function isFirebaseError(input) {
147
+ return typeof input === 'object' && input.code != null && input.message != null && input.toJSON != null;
148
+ }
149
+ /**
150
+ * Creates a FirebaseServerErrorInfo from the input.
151
+ *
152
+ * @param e
153
+ * @returns
154
+ */
155
+ function firebaseServerErrorInfo(e) {
156
+ let type = 'unknown';
157
+ let httpsError;
158
+ let firebaseError;
159
+ let firebaseErrorCode;
160
+ let httpsErrorDetailsServerError;
161
+ let serverErrorCode;
162
+ if (e != null) {
163
+ if (isFirebaseHttpsError(e)) {
164
+ type = 'httpsError';
165
+ httpsError = e;
166
+ firebaseErrorCode = httpsError.code;
167
+ if (httpsError.details && isServerError(httpsError.details)) {
168
+ httpsErrorDetailsServerError = httpsError.details;
169
+ serverErrorCode = httpsErrorDetailsServerError.code;
170
+ }
171
+ }
172
+ else if (isFirebaseError(e)) {
173
+ type = 'firebaseError';
174
+ firebaseError = e;
175
+ firebaseErrorCode = firebaseError.code;
176
+ }
177
+ }
178
+ return {
179
+ httpsError,
180
+ firebaseError,
181
+ firebaseErrorCode,
182
+ httpsErrorDetailsServerError,
183
+ serverErrorCode,
184
+ type,
185
+ e
186
+ };
187
+ }
188
+ function firebaseServerErrorInfoCodePair(e) {
189
+ const info = firebaseServerErrorInfo(e);
190
+ return [info.firebaseErrorCode, info];
191
+ }
192
+ function firebaseServerErrorInfoServerErrorPair(e) {
193
+ const info = firebaseServerErrorInfo(e);
194
+ return [info.httpsErrorDetailsServerError, info];
195
+ }
196
+ function firebaseServerErrorInfoServerErrorCodePair(e) {
197
+ const info = firebaseServerErrorInfo(e);
198
+ return [info.serverErrorCode, info];
199
+ }
200
+ function handleFirebaseError(e, handleFirebaseErrorFn) {
201
+ const firebaseError = e.code ? e : undefined;
202
+ if (firebaseError) {
203
+ handleFirebaseErrorFn(firebaseError);
204
+ }
205
+ }
206
+
207
+ function isContextWithAuthData(context) {
208
+ return Boolean(context.auth !== null && context.auth?.uid);
209
+ }
210
+ function assertIsContextWithAuthData(context) {
211
+ if (!isContextWithAuthData(context)) {
212
+ throw unauthenticatedContextHasNoAuthData();
213
+ }
214
+ }
215
+
216
+ function firebaseAuthTokenFromDecodedIdToken(token) {
217
+ return {
218
+ email: token.email,
219
+ emailVerified: token.email_verified,
220
+ phoneNumber: token.phone_number,
221
+ lastSignInTime: new Date(token.auth_time).toISOString(),
222
+ lastRefreshTime: new Date(token.iat).toISOString()
223
+ };
224
+ }
225
+
226
+ /**
227
+ * Awaits the load result from the input promise. If it encounters a FIREBASE_AUTH_USER_NOT_FOUND_ERROR, then returns undefined. Throws the error otherwise.
228
+ * @param promise
229
+ * @returns
230
+ */
231
+ async function getAuthUserOrUndefined(promise) {
232
+ try {
233
+ return await promise;
234
+ }
235
+ catch (error) {
236
+ if (error?.code === FIREBASE_AUTH_USER_NOT_FOUND_ERROR) {
237
+ return undefined;
238
+ }
239
+ else {
240
+ throw error;
241
+ }
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Thrown by sendSetupDetails() if the user has no setup configuration available, meaning they probably already have accepted their invite or is in an invalid state.
247
+ */
248
+ class FirebaseServerAuthNewUserSendSetupDetailsNoSetupConfigError extends BaseError {
249
+ constructor() {
250
+ super(`This user has no setup configuration available.`);
251
+ }
252
+ }
253
+ /**
254
+ * Thrown by sendSetupDetails() if the user was recently sent details.
255
+ */
256
+ class FirebaseServerAuthNewUserSendSetupDetailsThrottleError extends BaseError {
257
+ lastSentAt;
258
+ constructor(lastSentAt) {
259
+ super(`This user was recently sent details. Try again later.`);
260
+ this.lastSentAt = lastSentAt;
261
+ }
262
+ }
263
+ /**
264
+ * Thrown by sendSetupDetails() if the user was recently sent details.
265
+ */
266
+ class FirebaseServerAuthNewUserSendSetupDetailsSendOnceError extends BaseError {
267
+ constructor() {
268
+ super(`The user has been sent details before and the sendSetupDetailsOnce configuration was true.`);
269
+ }
270
+ }
271
+
272
+ const DEFAULT_FIREBASE_PASSWORD_NUMBER_GENERATOR = randomNumberFactory({ min: 100000, max: 1000000, round: 'floor' }); // 6 digits
273
+ class AbstractFirebaseServerAuthUserContext {
274
+ _service;
275
+ _uid;
276
+ _loadRecord = cachedGetter(() => this._service.auth.getUser(this._uid));
277
+ constructor(service, uid) {
278
+ this._service = service;
279
+ this._uid = uid;
280
+ }
281
+ get service() {
282
+ return this._service;
283
+ }
284
+ get uid() {
285
+ return this._uid;
286
+ }
287
+ async exists() {
288
+ return getAuthUserOrUndefined(this._loadRecord()).then((x) => Boolean(x));
289
+ }
290
+ loadRecord() {
291
+ return this._loadRecord();
292
+ }
293
+ loadDetails() {
294
+ return this.loadRecord().then((record) => this.service.authDetailsForRecord(record));
295
+ }
296
+ _generateResetPasswordKey() {
297
+ return String(DEFAULT_FIREBASE_PASSWORD_NUMBER_GENERATOR());
298
+ }
299
+ async beginResetPassword() {
300
+ const password = this._generateResetPasswordKey();
301
+ const passwordClaimsData = {
302
+ [FIREBASE_SERVER_AUTH_CLAIMS_RESET_PASSWORD_KEY]: password,
303
+ [FIREBASE_SERVER_AUTH_CLAIMS_RESET_LAST_COM_DATE_KEY]: toISODateString(new Date())
304
+ };
305
+ // set the claims
306
+ await this.updateClaims(passwordClaimsData);
307
+ // update the user
308
+ await this.updateUser({ password });
309
+ return passwordClaimsData;
310
+ }
311
+ async loadResetPasswordClaims() {
312
+ const claims = await this.loadClaims();
313
+ if (claims.resetPassword != null) {
314
+ return claims;
315
+ }
316
+ else {
317
+ return undefined;
318
+ }
319
+ }
320
+ /**
321
+ * Sets the user's password.
322
+ */
323
+ async setPassword(password) {
324
+ const record = await this.updateUser({ password });
325
+ // clear password reset claims
326
+ await this.updateClaims({
327
+ [FIREBASE_SERVER_AUTH_CLAIMS_RESET_PASSWORD_KEY]: null,
328
+ [FIREBASE_SERVER_AUTH_CLAIMS_RESET_LAST_COM_DATE_KEY]: null
329
+ });
330
+ return record;
331
+ }
332
+ async updateUser(template) {
333
+ return this.service.auth.updateUser(this.uid, template);
334
+ }
335
+ async loadRoles() {
336
+ const claims = await this.loadClaims();
337
+ return this.service.readRoles(claims);
338
+ }
339
+ async addRoles(roles) {
340
+ const claims = this._claimsForRolesChange(roles);
341
+ return this.updateClaims(claims);
342
+ }
343
+ async removeRoles(roles) {
344
+ const baseClaims = this._claimsForRolesChange(roles);
345
+ const claims = {};
346
+ forEachKeyValue(baseClaims, {
347
+ forEach: ([key]) => {
348
+ claims[key] = null; // set null on every key
349
+ },
350
+ filter: KeyValueTypleValueFilter.NONE // don't skip any key/value
351
+ });
352
+ return this.updateClaims(claims);
353
+ }
354
+ /**
355
+ * Sets the claims using the input roles and roles set.
356
+ *
357
+ * All other claims are cleared.
358
+ *
359
+ * Use the claimsToRetain input to retain other claims that are outside of the roles.
360
+ *
361
+ * @param roles
362
+ * @param claimsToRetain
363
+ * @returns
364
+ */
365
+ async setRoles(roles, claimsToRetain) {
366
+ const claims = {
367
+ ...claimsToRetain,
368
+ ...this._claimsForRolesChange(Array.from(roles))
369
+ };
370
+ return this.setClaims(claims);
371
+ }
372
+ _claimsForRolesChange(roles) {
373
+ // filter null/undefined since the claims will contain null values for claims that are not related.
374
+ return filterNullAndUndefinedValues(this.service.claimsForRoles(asSet(roles)));
375
+ }
376
+ loadClaims() {
377
+ return this.loadRecord().then((x) => (x.customClaims ?? {}));
378
+ }
379
+ async updateClaims(claims) {
380
+ const currentClaims = await this.loadClaims();
381
+ let newClaims;
382
+ if (currentClaims) {
383
+ newClaims = {
384
+ ...currentClaims,
385
+ ...filterUndefinedValues(claims, false)
386
+ };
387
+ newClaims = filterNullAndUndefinedValues(newClaims);
388
+ }
389
+ else {
390
+ newClaims = claims;
391
+ }
392
+ return this.setClaims(newClaims);
393
+ }
394
+ clearClaims() {
395
+ return this.setClaims(null);
396
+ }
397
+ setClaims(claims) {
398
+ return this.service.auth.setCustomUserClaims(this.uid, claims).then(() => {
399
+ this._loadRecord.reset(); // reset the cache
400
+ });
401
+ }
402
+ }
403
+ class AbstractFirebaseServerAuthContext {
404
+ _service;
405
+ _context;
406
+ _authRoles = cachedGetter(() => this.service.readRoles(this.claims));
407
+ _isAdmin = cachedGetter(() => this.service.isAdminInRoles(this._authRoles()));
408
+ _hasSignedTos = cachedGetter(() => this.service.hasSignedTosInRoles(this._authRoles()));
409
+ _userContext = cachedGetter(() => this.service.userContext(this.context.auth.uid));
410
+ constructor(service, context) {
411
+ this._service = service;
412
+ this._context = context;
413
+ }
414
+ get service() {
415
+ return this._service;
416
+ }
417
+ get context() {
418
+ return this._context;
419
+ }
420
+ get userContext() {
421
+ return this._userContext();
422
+ }
423
+ get isAdmin() {
424
+ return this._isAdmin();
425
+ }
426
+ get hasSignedTos() {
427
+ return this._hasSignedTos();
428
+ }
429
+ get authRoles() {
430
+ return this._authRoles();
431
+ }
432
+ get token() {
433
+ return this.context.auth.token;
434
+ }
435
+ get claims() {
436
+ return this.context.auth.token;
437
+ }
438
+ // MARK: FirebaseServerAuthUserContext
439
+ get uid() {
440
+ return this.userContext.uid;
441
+ }
442
+ }
443
+ /**
444
+ * 1 hour
445
+ */
446
+ const DEFAULT_SETUP_COM_THROTTLE_TIME = hoursToMs(1);
447
+ function userContextFromUid(authService, userContextOrUid) {
448
+ const userContext = typeof userContextOrUid === 'string' ? authService.userContext(userContextOrUid) : userContextOrUid;
449
+ return userContext;
450
+ }
451
+ class AbstractFirebaseServerNewUserService {
452
+ _authService;
453
+ setupThrottleTime = DEFAULT_SETUP_COM_THROTTLE_TIME;
454
+ constructor(authService) {
455
+ this._authService = authService;
456
+ }
457
+ get authService() {
458
+ return this._authService;
459
+ }
460
+ async initializeNewUser(input) {
461
+ const { uid, email, phone, sendSetupContent, sendSetupContentIfUserExists, sendSetupDetailsOnce, sendSetupIgnoreThrottle, sendSetupThrowErrors, data, sendDetailsInTestEnvironment } = input;
462
+ let userRecordPromise;
463
+ if (uid) {
464
+ userRecordPromise = this.authService.auth.getUser(uid);
465
+ }
466
+ else if (email) {
467
+ userRecordPromise = this.authService.auth.getUserByEmail(email);
468
+ }
469
+ else if (phone) {
470
+ userRecordPromise = this.authService.auth.getUserByPhoneNumber(phone);
471
+ }
472
+ else {
473
+ throw new Error('email or phone is required to initialize a new user.');
474
+ }
475
+ let userRecord = await getAuthUserOrUndefined(userRecordPromise);
476
+ let userRecordId;
477
+ let createdUser = false;
478
+ if (!userRecord) {
479
+ const createResult = await this.createNewUser(input);
480
+ // add the setup password to the user's credentials
481
+ const userContext = this.authService.userContext(createResult.user.uid);
482
+ await this.addNewUserSetupClaims(userContext, createResult.password);
483
+ createdUser = true;
484
+ userRecordId = userContext.uid;
485
+ userRecord = await userContext.loadRecord();
486
+ }
487
+ else {
488
+ userRecordId = userRecord.uid;
489
+ }
490
+ // send content if necessary
491
+ if ((createdUser && sendSetupContent === true) || sendSetupContentIfUserExists) {
492
+ const sentEmail = await this.sendSetupContent(userRecordId, { data, sendSetupDetailsOnce, ignoreSendThrottleTime: sendSetupIgnoreThrottle, throwErrors: sendSetupThrowErrors, sendDetailsInTestEnvironment });
493
+ // reload the user record
494
+ if (sentEmail) {
495
+ const userContext = this.authService.userContext(userRecordId);
496
+ userRecord = await userContext.loadRecord();
497
+ }
498
+ }
499
+ return userRecord;
500
+ }
501
+ async addNewUserSetupClaims(userContextOrUid, setupPassword) {
502
+ const password = setupPassword ?? this.generateRandomSetupPassword();
503
+ const userContext = userContextFromUid(this.authService, userContextOrUid);
504
+ await userContext.updateClaims({
505
+ [FIREBASE_SERVER_AUTH_CLAIMS_SETUP_PASSWORD_KEY]: password
506
+ });
507
+ return userContext;
508
+ }
509
+ async sendSetupContent(userContextOrUid, config) {
510
+ const setupDetails = await this.loadSetupDetails(userContextOrUid, config);
511
+ let sentContent = false;
512
+ if (setupDetails) {
513
+ const { setupCommunicationAt } = setupDetails.claims;
514
+ const hasSentCommunication = Boolean(setupCommunicationAt);
515
+ if (config?.sendSetupDetailsOnce && hasSentCommunication) {
516
+ // do not send.
517
+ if (config?.throwErrors) {
518
+ throw new FirebaseServerAuthNewUserSendSetupDetailsSendOnceError();
519
+ }
520
+ }
521
+ else {
522
+ const lastSentAt = setupCommunicationAt ? new Date(setupCommunicationAt) : undefined;
523
+ const sendIsThrottled = hasSentCommunication && !config?.ignoreSendThrottleTime && isThrottled(this.setupThrottleTime, lastSentAt);
524
+ if (!sendIsThrottled) {
525
+ await this.sendSetupContentToUser(setupDetails);
526
+ await this.updateSetupContentSentTime(setupDetails);
527
+ sentContent = true;
528
+ }
529
+ else if (config?.throwErrors) {
530
+ throw new FirebaseServerAuthNewUserSendSetupDetailsThrottleError(lastSentAt);
531
+ }
532
+ }
533
+ }
534
+ else if (config?.throwErrors) {
535
+ throw new FirebaseServerAuthNewUserSendSetupDetailsNoSetupConfigError();
536
+ }
537
+ return sentContent;
538
+ }
539
+ async loadSetupDetails(userContextOrUid, config) {
540
+ const userContext = userContextFromUid(this.authService, userContextOrUid);
541
+ const userExists = await userContext.exists();
542
+ let details;
543
+ if (userExists) {
544
+ details = await this.loadSetupDetailsForUserContext(userContext, config);
545
+ }
546
+ return details;
547
+ }
548
+ async loadSetupDetailsForUserContext(userContext, config) {
549
+ let details;
550
+ const { setupPassword, setupCommunicationAt } = await userContext.loadClaims();
551
+ if (setupPassword) {
552
+ details = {
553
+ userContext,
554
+ claims: {
555
+ setupPassword,
556
+ setupCommunicationAt
557
+ },
558
+ data: config?.data,
559
+ sendDetailsInTestEnvironment: config?.sendDetailsInTestEnvironment
560
+ };
561
+ }
562
+ return details;
563
+ }
564
+ async updateSetupContentSentTime(details) {
565
+ const setupCommunicationAt = toISODateString(new Date());
566
+ await details.userContext.updateClaims({
567
+ setupCommunicationAt
568
+ });
569
+ }
570
+ /**
571
+ * Update a user's claims to clear any setup-related content.
572
+ *
573
+ * Returns true if a user was updated.
574
+ *
575
+ * @param uid
576
+ */
577
+ async markUserSetupAsComplete(uid) {
578
+ const userContext = this.authService.userContext(uid);
579
+ const userExists = await userContext.exists();
580
+ if (userExists) {
581
+ await this.updateClaimsToClearUser(userContext);
582
+ }
583
+ return userExists;
584
+ }
585
+ async createNewUser(input) {
586
+ const { uid, displayName, email, phone: phoneNumber, setupPassword: inputPassword } = input;
587
+ const password = inputPassword ?? this.generateRandomSetupPassword();
588
+ const user = await this.authService.auth.createUser({
589
+ uid,
590
+ displayName,
591
+ email,
592
+ phoneNumber,
593
+ password
594
+ });
595
+ return {
596
+ user,
597
+ password
598
+ };
599
+ }
600
+ generateRandomSetupPassword() {
601
+ return `${DEFAULT_FIREBASE_PASSWORD_NUMBER_GENERATOR()}`;
602
+ }
603
+ async updateClaimsToClearUser(userContext) {
604
+ await userContext.updateClaims({
605
+ [FIREBASE_SERVER_AUTH_CLAIMS_SETUP_PASSWORD_KEY]: null,
606
+ [FIREBASE_SERVER_AUTH_CLAIMS_SETUP_LAST_COM_DATE_KEY]: null
607
+ });
608
+ }
609
+ }
610
+ class NoSetupContentFirebaseServerNewUserService extends AbstractFirebaseServerNewUserService {
611
+ async sendSetupContentToUser(user) {
612
+ // send nothing.
613
+ }
614
+ }
615
+ /**
616
+ * FirebaseServer auth service that provides accessors to auth-related components.
617
+ */
618
+ class FirebaseServerAuthService {
619
+ }
620
+ /**
621
+ * Abstract FirebaseServerAuthService implementation.
622
+ */
623
+ class AbstractFirebaseServerAuthService {
624
+ _auth;
625
+ constructor(auth) {
626
+ this._auth = auth;
627
+ }
628
+ get auth() {
629
+ return this._auth;
630
+ }
631
+ context(context) {
632
+ assertIsContextWithAuthData(context);
633
+ return this._context(context);
634
+ }
635
+ isAdmin(claims) {
636
+ return this.isAdminInRoles(this.readRoles(claims));
637
+ }
638
+ isAdminInRoles(roles) {
639
+ return roles.has(AUTH_ADMIN_ROLE);
640
+ }
641
+ hasSignedTos(claims) {
642
+ return this.hasSignedTosInRoles(this.readRoles(claims));
643
+ }
644
+ hasSignedTosInRoles(roles) {
645
+ return roles.has(AUTH_TOS_SIGNED_ROLE);
646
+ }
647
+ newUser() {
648
+ return new NoSetupContentFirebaseServerNewUserService(this);
649
+ }
650
+ authContextInfo(context) {
651
+ const { auth } = context;
652
+ let result;
653
+ if (auth) {
654
+ const _roles = cachedGetter(() => this.readRoles(auth.token));
655
+ const getClaims = () => auth.token;
656
+ result = {
657
+ uid: auth.uid,
658
+ isAdmin: () => this.isAdminInRoles(_roles()),
659
+ getClaims,
660
+ getAuthRoles: _roles,
661
+ token: firebaseAuthTokenFromDecodedIdToken(auth.token)
662
+ };
663
+ }
664
+ return result;
665
+ }
666
+ authDetailsForRecord(record) {
667
+ return {
668
+ uid: record.uid,
669
+ email: record.email,
670
+ emailVerified: record.emailVerified,
671
+ phoneNumber: record.phoneNumber,
672
+ disabled: record.disabled,
673
+ displayName: record.displayName,
674
+ photoURL: record.photoURL,
675
+ creationTime: record.metadata.creationTime ? new Date(record.metadata.creationTime).toISOString() : undefined,
676
+ lastSignInTime: record.metadata.lastSignInTime ? new Date(record.metadata.lastSignInTime).toISOString() : undefined,
677
+ lastRefreshTime: record.metadata.lastRefreshTime ? new Date(record.metadata.lastRefreshTime).toISOString() : undefined
678
+ };
679
+ }
680
+ }
681
+
682
+ class FirebaseServerEnvService {
683
+ }
684
+
685
+ /**
686
+ * Creates UpdateData corresponding to the input increment update.
687
+ *
688
+ * @param input
689
+ * @returns
690
+ */
691
+ function firestoreServerIncrementUpdateToUpdateData(input) {
692
+ return mapObjectMap(input, (incrementValue) => {
693
+ return FieldValue.increment(incrementValue ?? 0);
694
+ });
695
+ }
696
+
697
+ /**
698
+ * Creates UpdateData corresponding to the input array update.
699
+ *
700
+ * @param input
701
+ * @returns
702
+ */
703
+ function firestoreServerArrayUpdateToUpdateData(input) {
704
+ const union = input?.union;
705
+ const remove = input?.remove;
706
+ function createUpdatesWithArrayFunction(fieldUpdate, arrayUpdateFunction) {
707
+ let result;
708
+ if (fieldUpdate) {
709
+ result = mapObjectMap(fieldUpdate, (arrayUpdate) => {
710
+ let result;
711
+ if (arrayUpdate) {
712
+ result = arrayUpdateFunction(...arrayUpdate); // use spread operator to insert each value as an argument, as "nested arrays" are not allowed in the Firestore
713
+ }
714
+ return result;
715
+ });
716
+ }
717
+ return result;
718
+ }
719
+ const updateData = {
720
+ ...createUpdatesWithArrayFunction(union, FieldValue.arrayUnion),
721
+ ...createUpdatesWithArrayFunction(remove, FieldValue.arrayRemove)
722
+ };
723
+ return updateData;
724
+ }
725
+
726
+ // MARK: Accessor
727
+ /**
728
+ * FirestoreDocumentDataAccessor implementation for a batch.
729
+ */
730
+ class WriteBatchFirestoreDocumentDataAccessor {
731
+ documentRef;
732
+ _batch;
733
+ constructor(batch, documentRef) {
734
+ this.documentRef = documentRef;
735
+ this._batch = batch;
736
+ }
737
+ get batch() {
738
+ return this._batch;
739
+ }
740
+ stream() {
741
+ return from(this.get()); // todo
742
+ }
743
+ create(data) {
744
+ this.batch.create(this.documentRef, data);
745
+ return Promise.resolve();
746
+ }
747
+ exists() {
748
+ return this.get().then((x) => x.exists);
749
+ }
750
+ get() {
751
+ return this.documentRef.get();
752
+ }
753
+ getWithConverter(converter) {
754
+ return this.documentRef.withConverter(converter).get();
755
+ }
756
+ delete(params) {
757
+ this.batch.delete(this.documentRef, params?.precondition);
758
+ return Promise.resolve();
759
+ }
760
+ set(data) {
761
+ this.batch.set(this.documentRef, data);
762
+ return Promise.resolve();
763
+ }
764
+ increment(data, params) {
765
+ return this.update(firestoreServerIncrementUpdateToUpdateData(data), params);
766
+ }
767
+ arrayUpdate(data, params) {
768
+ return this.update(firestoreServerArrayUpdateToUpdateData(data), params);
769
+ }
770
+ update(data, params) {
771
+ if (params?.precondition != null) {
772
+ this.batch.update(this.documentRef, data, params?.precondition);
773
+ }
774
+ else {
775
+ this.batch.update(this.documentRef, data);
776
+ }
777
+ return Promise.resolve();
778
+ }
779
+ }
780
+ /**
781
+ * Creates a new FirestoreDocumentDataAccessorFactory for a Batch.
782
+ *
783
+ * @param batch
784
+ * @returns
785
+ */
786
+ function writeBatchAccessorFactory(writeBatch) {
787
+ return {
788
+ accessorFor: (ref) => new WriteBatchFirestoreDocumentDataAccessor(writeBatch, ref)
789
+ };
790
+ }
791
+ // MARK: Context
792
+ class WriteBatchFirestoreDocumentContext {
793
+ _batch;
794
+ contextType = FirestoreDocumentContextType.BATCH;
795
+ accessorFactory;
796
+ constructor(batch) {
797
+ this._batch = batch;
798
+ this.accessorFactory = writeBatchAccessorFactory(batch);
799
+ }
800
+ get batch() {
801
+ return this._batch;
802
+ }
803
+ }
804
+ function writeBatchDocumentContext(batch) {
805
+ return new WriteBatchFirestoreDocumentContext(batch);
806
+ }
807
+
808
+ // MARK: Accessor
809
+ class DefaultFirestoreDocumentDataAccessor {
810
+ _documentRef;
811
+ constructor(documentRef) {
812
+ this._documentRef = documentRef;
813
+ }
814
+ get documentRef() {
815
+ return this._documentRef;
816
+ }
817
+ stream() {
818
+ return streamFromOnSnapshot(({ next, error }) => this.documentRef.onSnapshot(next, error));
819
+ }
820
+ create(data) {
821
+ return this.documentRef.create(data);
822
+ }
823
+ exists() {
824
+ return this.get().then((x) => x.exists);
825
+ }
826
+ get() {
827
+ return this.documentRef.get();
828
+ }
829
+ getWithConverter(converter) {
830
+ return this.documentRef.withConverter(converter).get();
831
+ }
832
+ delete(params) {
833
+ return this.documentRef.delete(params?.precondition);
834
+ }
835
+ set(data, options) {
836
+ return options ? this.documentRef.set(data, options) : this.documentRef.set(data);
837
+ }
838
+ increment(data, params) {
839
+ return this.update(firestoreServerIncrementUpdateToUpdateData(data), params);
840
+ }
841
+ arrayUpdate(data, params) {
842
+ return this.update(firestoreServerArrayUpdateToUpdateData(data), params);
843
+ }
844
+ update(data, params) {
845
+ return params?.precondition ? this.documentRef.update(data, params.precondition) : this.documentRef.update(data);
846
+ }
847
+ }
848
+ function defaultFirestoreAccessorFactory() {
849
+ return {
850
+ accessorFor: (ref) => new DefaultFirestoreDocumentDataAccessor(ref)
851
+ };
852
+ }
853
+ // MARK: Context
854
+ function defaultFirestoreDocumentContext() {
855
+ return {
856
+ contextType: FirestoreDocumentContextType.NONE,
857
+ accessorFactory: defaultFirestoreAccessorFactory()
858
+ };
859
+ }
860
+
861
+ // MARK: Accessor
862
+ /**
863
+ * FirestoreDocumentDataAccessor implementation for a transaction.
864
+ */
865
+ class TransactionFirestoreDocumentDataAccessor {
866
+ _transaction;
867
+ _documentRef;
868
+ constructor(transaction, documentRef) {
869
+ this._transaction = transaction;
870
+ this._documentRef = documentRef;
871
+ }
872
+ get transaction() {
873
+ return this._transaction;
874
+ }
875
+ get documentRef() {
876
+ return this._documentRef;
877
+ }
878
+ stream() {
879
+ return from(this.get());
880
+ }
881
+ create(data) {
882
+ this.transaction.create(this.documentRef, data);
883
+ return Promise.resolve();
884
+ }
885
+ exists() {
886
+ return this.get().then((x) => x.exists);
887
+ }
888
+ get() {
889
+ return this.transaction.get(this.documentRef);
890
+ }
891
+ getWithConverter(converter) {
892
+ return this.transaction.get(this.documentRef.withConverter(converter));
893
+ }
894
+ delete() {
895
+ this.transaction.delete(this.documentRef);
896
+ return Promise.resolve();
897
+ }
898
+ set(data, options) {
899
+ this.transaction.set(this.documentRef, data, options);
900
+ return Promise.resolve();
901
+ }
902
+ increment(data, params) {
903
+ return this.update(firestoreServerIncrementUpdateToUpdateData(data), params);
904
+ }
905
+ arrayUpdate(data, params) {
906
+ return this.update(firestoreServerArrayUpdateToUpdateData(data), params);
907
+ }
908
+ update(data, params) {
909
+ if (params?.precondition) {
910
+ this.transaction.update(this.documentRef, data, params?.precondition);
911
+ }
912
+ else {
913
+ this.transaction.update(this.documentRef, data);
914
+ }
915
+ return Promise.resolve();
916
+ }
917
+ }
918
+ /**
919
+ * Creates a new FirestoreDocumentDataAccessorFactory for a Transaction.
920
+ *
921
+ * @param transaction
922
+ * @returns
923
+ */
924
+ function transactionAccessorFactory(transaction) {
925
+ return {
926
+ accessorFor: (ref) => new TransactionFirestoreDocumentDataAccessor(transaction, ref)
927
+ };
928
+ }
929
+ // MARK: Context
930
+ class TransactionFirestoreDocumentContext {
931
+ _transaction;
932
+ contextType = FirestoreDocumentContextType.TRANSACTION;
933
+ accessorFactory;
934
+ constructor(transaction) {
935
+ this._transaction = transaction;
936
+ this.accessorFactory = transactionAccessorFactory(transaction);
937
+ }
938
+ get transaction() {
939
+ return this._transaction;
940
+ }
941
+ }
942
+ function transactionDocumentContext(transaction) {
943
+ return new TransactionFirestoreDocumentContext(transaction);
944
+ }
945
+
946
+ function collectionRefForPath(start, path, pathSegments) {
947
+ let ref = start.collection(path);
948
+ if (pathSegments?.length) {
949
+ if (pathSegments?.length % 2 !== 0) {
950
+ throw new Error(`Invalid number of path segments provided for collection. Path: "${path}" + "${pathSegments}"`);
951
+ }
952
+ const batches = batch(pathSegments, 2); // batch to tuple [string, string]
953
+ batches.forEach((x) => {
954
+ const [first, second] = x;
955
+ ref = ref.doc(first).collection(second);
956
+ });
957
+ }
958
+ return ref;
959
+ }
960
+ function docRefForPath(start, path, pathSegments) {
961
+ let doc = (path ? start.doc(path) : start.doc());
962
+ if (pathSegments?.length) {
963
+ const batches = batch(pathSegments, 2); // batch to tuple [string, string]
964
+ batches.forEach((x) => {
965
+ const [first, second] = x;
966
+ const collection = doc.collection(first);
967
+ doc = second ? collection.doc(second) : collection.doc();
968
+ });
969
+ }
970
+ return doc;
971
+ }
972
+ function googleCloudFirestoreAccessorDriver() {
973
+ return {
974
+ doc: (collection, path, ...pathSegments) => docRefForPath(collection, path, pathSegments),
975
+ docAtPath: (firestore, fullPath) => firestore.doc(fullPath),
976
+ collectionGroup: (firestore, collectionId) => firestore.collectionGroup(collectionId),
977
+ collection: (firestore, path, ...pathSegments) => collectionRefForPath(firestore, path, pathSegments),
978
+ subcollection: (document, path, ...pathSegments) => collectionRefForPath(document, path, pathSegments),
979
+ transactionFactoryForFirestore: (firestore) => async (fn) => await firestore.runTransaction(fn),
980
+ writeBatchFactoryForFirestore: (firestore) => () => firestore.batch(),
981
+ defaultContextFactory: defaultFirestoreDocumentContext,
982
+ transactionContextFactory: transactionDocumentContext,
983
+ writeBatchContextFactory: writeBatchDocumentContext
984
+ };
985
+ }
986
+
987
+ const FIRESTORE_CLIENT_QUERY_CONSTRAINT_HANDLER_MAPPING = {
988
+ [FIRESTORE_LIMIT_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.limit(data.limit),
989
+ [FIRESTORE_LIMIT_TO_LAST_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.limitToLast(data.limit),
990
+ [FIRESTORE_ORDER_BY_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.orderBy(data.fieldPath, data.directionStr),
991
+ [FIRESTORE_ORDER_BY_DOCUMENT_ID_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.orderBy(FieldPath.documentId(), data.directionStr),
992
+ [FIRESTORE_WHERE_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.where(data.fieldPath, data.opStr, data.value),
993
+ [FIRESTORE_WHERE_DOCUMENT_ID_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.where(FieldPath.documentId(), data.opStr, data.value),
994
+ [FIRESTORE_OFFSET_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.offset(data.offset),
995
+ [FIRESTORE_START_AT_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.startAt(data.snapshot),
996
+ [FIRESTORE_START_AT_VALUE_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.startAt(...data.fieldValues),
997
+ [FIRESTORE_START_AFTER_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.startAfter(data.snapshot),
998
+ [FIRESTORE_END_AT_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.endAt(data.snapshot),
999
+ [FIRESTORE_END_AT_VALUE_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.endAt(...data.fieldValues),
1000
+ [FIRESTORE_END_BEFORE_QUERY_CONSTRAINT_TYPE]: (builder, data) => builder.endBefore(data.snapshot)
1001
+ };
1002
+ function firestoreClientQueryConstraintFunctionsDriver() {
1003
+ return makeFirestoreQueryConstraintFunctionsDriver({
1004
+ mapping: FIRESTORE_CLIENT_QUERY_CONSTRAINT_HANDLER_MAPPING,
1005
+ init: (query) => query,
1006
+ build: (query) => query,
1007
+ documentIdFieldPath: () => FieldPath.documentId()
1008
+ });
1009
+ }
1010
+ function googleCloudFirestoreQueryDriver() {
1011
+ return {
1012
+ ...firestoreClientQueryConstraintFunctionsDriver(),
1013
+ countDocs(query) {
1014
+ return query
1015
+ .count()
1016
+ .get()
1017
+ .then((x) => x.data().count);
1018
+ },
1019
+ getDocs(query, transaction) {
1020
+ let result;
1021
+ if (transaction) {
1022
+ result = transaction.get(query);
1023
+ }
1024
+ else {
1025
+ result = query.get();
1026
+ }
1027
+ return result;
1028
+ },
1029
+ streamDocs(query) {
1030
+ return streamFromOnSnapshot(({ next, error }) => query.onSnapshot(next, error));
1031
+ }
1032
+ };
1033
+ }
1034
+
1035
+ function googleCloudFirestoreDrivers() {
1036
+ return {
1037
+ firestoreDriverIdentifier: '@google-cloud/firestore',
1038
+ firestoreDriverType: 'production',
1039
+ firestoreAccessorDriver: googleCloudFirestoreAccessorDriver(),
1040
+ firestoreQueryDriver: googleCloudFirestoreQueryDriver()
1041
+ };
1042
+ }
1043
+
1044
+ /**
1045
+ * Creates a FirestoreContextFactory that uses the @'@google-cloud/firestore package.
1046
+ */
1047
+ const googleCloudFirestoreContextFactory = firestoreContextFactory(googleCloudFirestoreDrivers());
1048
+
1049
+ function assertContextHasAuth(context) {
1050
+ if (!isContextWithAuthData(context)) {
1051
+ throw unauthenticatedContextHasNoUidError();
1052
+ }
1053
+ }
1054
+ /**
1055
+ * Attempts to load data from the document. A modelNotAvailableError is thrown if the snapshot data is null/undefined (the document does not exist).
1056
+ *
1057
+ * @param document
1058
+ * @param message
1059
+ * @returns
1060
+ */
1061
+ async function assertSnapshotData(document, message) {
1062
+ const data = await document.snapshotData();
1063
+ if (data == null) {
1064
+ throw modelNotAvailableError({
1065
+ message: message ?? `The ${document.modelType} was unavailable.`
1066
+ });
1067
+ }
1068
+ return data;
1069
+ }
1070
+ /**
1071
+ * Convenience function for assertSnapshotData that also attaches the id and key of the document to the data.
1072
+ *
1073
+ * @param document
1074
+ * @param message
1075
+ * @returns
1076
+ */
1077
+ async function assertSnapshotDataWithKey(document, message) {
1078
+ const data = await assertSnapshotData(document, message);
1079
+ return setIdAndKeyFromKeyIdRefOnDocumentData(data, document);
1080
+ }
1081
+ /**
1082
+ * Asserts that the document exists. A modelNotAvailableError is thrown if the document does not exist.
1083
+ *
1084
+ * @param document
1085
+ * @param message
1086
+ * @returns
1087
+ */
1088
+ async function assertDocumentExists(document, message) {
1089
+ const exists = await document.exists();
1090
+ if (!exists) {
1091
+ throw documentModelNotAvailableError(document, message);
1092
+ }
1093
+ }
1094
+ /**
1095
+ * Error thrown by assertDocumentExists().
1096
+ *
1097
+ * @param document
1098
+ * @param message
1099
+ * @returns
1100
+ */
1101
+ function documentModelNotAvailableError(document, message) {
1102
+ return modelNotAvailableError({
1103
+ message: message ?? `The ${document.modelType} was unavailable.`
1104
+ });
1105
+ }
1106
+
1107
+ const PHONE_NUMBER_ALREADY_EXISTS_ERROR_CODE = 'PHONE_NUMBER_ALREADY_EXISTS';
1108
+ function phoneNumberAlreadyExistsError() {
1109
+ return preconditionConflictError({
1110
+ code: PHONE_NUMBER_ALREADY_EXISTS_ERROR_CODE,
1111
+ message: 'This phone number already exists in the system.'
1112
+ });
1113
+ }
1114
+ function handleFirebaseAuthError(e, handleUnknownCode) {
1115
+ handleFirebaseError(e, (firebaseError) => {
1116
+ switch (firebaseError.code) {
1117
+ case 'auth/phone-number-already-exists':
1118
+ throw phoneNumberAlreadyExistsError();
1119
+ default:
1120
+ handleUnknownCode?.(firebaseError);
1121
+ break;
1122
+ }
1123
+ });
1124
+ }
1125
+
1126
+ /******************************************************************************
1127
+ Copyright (c) Microsoft Corporation.
1128
+
1129
+ Permission to use, copy, modify, and/or distribute this software for any
1130
+ purpose with or without fee is hereby granted.
1131
+
1132
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1133
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1134
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1135
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1136
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1137
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1138
+ PERFORMANCE OF THIS SOFTWARE.
1139
+ ***************************************************************************** */
1140
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
1141
+
1142
+
1143
+ function __decorate(decorators, target, key, desc) {
1144
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1145
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1146
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1147
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1148
+ }
1149
+
1150
+ function __param(paramIndex, decorator) {
1151
+ return function (target, key) { decorator(target, key, paramIndex); }
1152
+ }
1153
+
1154
+ function __metadata(metadataKey, metadataValue) {
1155
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
1156
+ }
1157
+
1158
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1159
+ var e = new Error(message);
1160
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1161
+ };
1162
+
1163
+ // MARK: Tokens
1164
+ /**
1165
+ * Nest Injection Token to access the
1166
+ */
1167
+ const FIREBASE_APP_TOKEN = 'FIREBASE_APP_TOKEN';
1168
+ // MARK: Firebase Admin Provider
1169
+ function firebaseServerAppTokenProvider(useFactory) {
1170
+ return {
1171
+ provide: FIREBASE_APP_TOKEN,
1172
+ useFactory
1173
+ };
1174
+ }
1175
+
1176
+ // MARK: Tokens
1177
+ /**
1178
+ * Token to access the Auth for the app.
1179
+ */
1180
+ const FIREBASE_AUTH_TOKEN = 'FIREBASE_AUTH_TOKEN';
1181
+ /**
1182
+ * Nest provider module for Firebase that provides a firestore, etc. from the firestore token.
1183
+ */
1184
+ let FirebaseServerAuthModule = class FirebaseServerAuthModule {
1185
+ };
1186
+ FirebaseServerAuthModule = __decorate([
1187
+ Module({
1188
+ providers: [
1189
+ {
1190
+ provide: FIREBASE_AUTH_TOKEN,
1191
+ useFactory: (app) => app.auth(),
1192
+ inject: [FIREBASE_APP_TOKEN]
1193
+ }
1194
+ ],
1195
+ exports: [FIREBASE_AUTH_TOKEN]
1196
+ })
1197
+ ], FirebaseServerAuthModule);
1198
+ function provideFirebaseServerAuthService(provider) {
1199
+ return [
1200
+ {
1201
+ ...provider,
1202
+ inject: provider.inject ?? [FIREBASE_AUTH_TOKEN]
1203
+ },
1204
+ {
1205
+ provide: FirebaseServerAuthService,
1206
+ useExisting: provider.provide
1207
+ }
1208
+ ];
1209
+ }
1210
+ /**
1211
+ * Convenience function used to generate ModuleMetadata for an app's Auth related modules and FirebaseServerAuthService provider.
1212
+ *
1213
+ * @param provide
1214
+ * @param useFactory
1215
+ * @returns
1216
+ */
1217
+ function firebaseServerAuthModuleMetadata(config) {
1218
+ return mergeModuleMetadata({
1219
+ imports: [FirebaseServerAuthModule],
1220
+ exports: [FirebaseServerAuthModule, config.serviceProvider.provide],
1221
+ providers: provideFirebaseServerAuthService(config.serviceProvider)
1222
+ }, config);
1223
+ }
1224
+
1225
+ function assertIsAdminInRequest(request) {
1226
+ if (!isAdminInRequest(request)) {
1227
+ throw forbiddenError();
1228
+ }
1229
+ }
1230
+ function isAdminInRequest(request) {
1231
+ return request.nest.authService.context(request).isAdmin;
1232
+ }
1233
+ function assertIsAdminOrTargetUserInRequestData(request, requireUid) {
1234
+ if (!isAdminOrTargetUserInRequestData(request, requireUid)) {
1235
+ throw forbiddenError();
1236
+ }
1237
+ return request.data.uid ?? request.auth?.uid;
1238
+ }
1239
+ function isAdminOrTargetUserInRequestData(request, requireUid = false) {
1240
+ const uid = request.data.uid;
1241
+ const authUid = request.auth?.uid;
1242
+ let isAdminOrTargetUser = true;
1243
+ if ((requireUid && uid == null) || (uid != null && uid !== authUid)) {
1244
+ isAdminOrTargetUser = request.nest.authService.context(request).isAdmin;
1245
+ }
1246
+ return isAdminOrTargetUser;
1247
+ }
1248
+ function assertHasSignedTosInRequest(request) {
1249
+ if (!hasSignedTosInRequest(request)) {
1250
+ throw forbiddenError({
1251
+ message: 'ToS has not been signed.'
1252
+ });
1253
+ }
1254
+ }
1255
+ function hasSignedTosInRequest(request) {
1256
+ return request.nest.authService.context(request).hasSignedTos;
1257
+ }
1258
+ function assertHasRolesInRequest(request, authRoles) {
1259
+ if (!hasAuthRolesInRequest(request, authRoles)) {
1260
+ throw forbiddenError({
1261
+ message: 'Missing required auth roles.',
1262
+ data: {
1263
+ roles: asArray(authRoles)
1264
+ }
1265
+ });
1266
+ }
1267
+ }
1268
+ function hasAuthRolesInRequest(request, authRoles) {
1269
+ return containsAllValues(request.nest.authService.context(request).authRoles, authRoles);
1270
+ }
1271
+ /**
1272
+ * Returns true if the claims have a FIREBASE_SERVER_AUTH_CLAIMS_SETUP_PASSWORD_KEY claims value, indicating they are a newly invited user.
1273
+ *
1274
+ * This may be used to filter out new users that were not invited from finishing their onboarding.
1275
+ *
1276
+ * @param request
1277
+ */
1278
+ function hasNewUserSetupPasswordInRequest(request) {
1279
+ const claims = request.nest.authService.context(request).claims;
1280
+ return claims[FIREBASE_SERVER_AUTH_CLAIMS_SETUP_PASSWORD_KEY] != null;
1281
+ }
1282
+
1283
+ /**
1284
+ * Creates a OnCallWithAuthorizedNestContext function for creating a model.
1285
+ *
1286
+ * @param map
1287
+ * @returns
1288
+ */
1289
+ function onCallDevelopmentFunction(map, config = {}) {
1290
+ const { preAssert = () => undefined } = config;
1291
+ return (request) => {
1292
+ const specifier = request.data.specifier;
1293
+ const devFn = map[specifier];
1294
+ if (devFn) {
1295
+ preAssert({ request, specifier });
1296
+ return devFn({
1297
+ ...request,
1298
+ specifier,
1299
+ data: request.data.data
1300
+ });
1301
+ }
1302
+ else {
1303
+ throw developmentUnknownSpecifierError(specifier);
1304
+ }
1305
+ };
1306
+ }
1307
+ function developmentUnknownSpecifierError(specifier) {
1308
+ return badRequestError(serverError({
1309
+ status: 400,
1310
+ code: 'UNKNOWN_SPECIFIER_ERROR',
1311
+ message: `Invalid specifier "${specifier}" to run.`,
1312
+ data: {
1313
+ specifier
1314
+ }
1315
+ }));
1316
+ }
1317
+
1318
+ const NO_RUN_NAME_SPECIFIED_FOR_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_CODE = 'NO_RUN_NAME_SPECIFIED_FOR_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION';
1319
+ function noRunNameSpecifiedForScheduledFunctionDevelopmentFunction() {
1320
+ return badRequestError({
1321
+ code: NO_RUN_NAME_SPECIFIED_FOR_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_CODE,
1322
+ message: `Must specify run parameter.`
1323
+ });
1324
+ }
1325
+ const UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_NAME_CODE = 'UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_NAME';
1326
+ function unknownScheduledFunctionDevelopmentFunctionName(name) {
1327
+ return badRequestError({
1328
+ code: UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_NAME_CODE,
1329
+ message: `Unknown function with name "${name}"`,
1330
+ data: {
1331
+ name
1332
+ }
1333
+ });
1334
+ }
1335
+ const UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_TYPE_CODE = 'UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_TYPE';
1336
+ function unknownScheduledFunctionDevelopmentFunctionType(type) {
1337
+ return badRequestError({
1338
+ code: UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_TYPE_CODE,
1339
+ message: `Unknown type "${type}"`,
1340
+ data: {
1341
+ type
1342
+ }
1343
+ });
1344
+ }
1345
+
1346
+ function makeScheduledFunctionDevelopmentFunction(config) {
1347
+ const { allScheduledFunctions } = config;
1348
+ const getListValues = cachedGetter(() => {
1349
+ const result = [];
1350
+ forEachKeyValue(allScheduledFunctions, {
1351
+ forEach: (x) => {
1352
+ const [functionName, config] = x;
1353
+ result.push({
1354
+ name: functionName.toString()
1355
+ });
1356
+ }
1357
+ });
1358
+ return result;
1359
+ });
1360
+ return async (request) => {
1361
+ const { data } = request;
1362
+ const { type } = data;
1363
+ switch (type) {
1364
+ case 'run':
1365
+ const targetRunName = data.run;
1366
+ if (!targetRunName) {
1367
+ throw noRunNameSpecifiedForScheduledFunctionDevelopmentFunction();
1368
+ }
1369
+ const targetFunction = allScheduledFunctions[targetRunName];
1370
+ if (!targetFunction) {
1371
+ throw unknownScheduledFunctionDevelopmentFunctionName(targetRunName);
1372
+ }
1373
+ try {
1374
+ await targetFunction._runNow();
1375
+ }
1376
+ catch (e) {
1377
+ console.error(`Failed manually running task "${targetRunName}".`, e);
1378
+ throw e;
1379
+ }
1380
+ return {
1381
+ type: 'run',
1382
+ success: true
1383
+ };
1384
+ case 'list':
1385
+ return {
1386
+ type: 'list',
1387
+ list: getListValues()
1388
+ };
1389
+ default:
1390
+ throw unknownScheduledFunctionDevelopmentFunctionType(type);
1391
+ }
1392
+ };
1393
+ }
1394
+
1395
+ function setNestContextOnRequest(makeNestContext, request) {
1396
+ request.nest = makeNestContext(request.nestApplication);
1397
+ return request;
1398
+ }
1399
+ /**
1400
+ * Wraps the input OnCallWithNestContext function to flag it as optional to have auth data.
1401
+ *
1402
+ * @param fn
1403
+ * @returns
1404
+ */
1405
+ function optionalAuthContext(fn) {
1406
+ const fnWithOptionalAuth = ((request) => fn(request));
1407
+ fnWithOptionalAuth._requireAuth = false;
1408
+ return fnWithOptionalAuth;
1409
+ }
1410
+ /**
1411
+ * Asserts that the input request has auth data if the inputOnCallWithAuthAwareNestRequireAuthRef object is flagged to require auth.
1412
+ *
1413
+ * @param fn
1414
+ * @param request
1415
+ */
1416
+ function assertRequestRequiresAuthForFunction(fn, request) {
1417
+ if (fn._requireAuth !== false) {
1418
+ assertIsContextWithAuthData(request);
1419
+ }
1420
+ }
1421
+ /**
1422
+ * Creates an OnCallWithNestContext wrapper that validates the input CallableContext to assert the context has auth data before entering the function.
1423
+ *
1424
+ * @param fn
1425
+ * @returns
1426
+ */
1427
+ function inAuthContext(fn) {
1428
+ return (request) => {
1429
+ assertIsContextWithAuthData(request);
1430
+ return fn(request);
1431
+ };
1432
+ }
1433
+
1434
+ function firebaseServerDevFunctions(config) {
1435
+ const { enabled, secure, nest, developerFunctionsMap, onCallFactory, allScheduledFunctions, disableDevelopmentScheduleFunction } = config;
1436
+ let dev;
1437
+ if (enabled) {
1438
+ const fullFunctionsMap = {
1439
+ ...developerFunctionsMap
1440
+ };
1441
+ if (allScheduledFunctions && disableDevelopmentScheduleFunction !== false) {
1442
+ fullFunctionsMap[SCHEDULED_FUNCTION_DEV_FUNCTION_SPECIFIER] = makeScheduledFunctionDevelopmentFunction({
1443
+ allScheduledFunctions
1444
+ });
1445
+ }
1446
+ let onCallFunction = onCallDevelopmentFunction(fullFunctionsMap);
1447
+ if (secure != false) {
1448
+ onCallFunction = inAuthContext(onCallFunction);
1449
+ }
1450
+ dev = onCallFactory(onCallFunction)(nest);
1451
+ }
1452
+ else {
1453
+ dev = onCallFactory(async (x) => {
1454
+ throw unavailableError({
1455
+ message: 'developer tools service is not enabled.'
1456
+ });
1457
+ })(nest);
1458
+ }
1459
+ return {
1460
+ dev
1461
+ };
1462
+ }
1463
+
1464
+ let DefaultFirebaseServerEnvService = class DefaultFirebaseServerEnvService extends ServerEnvironmentService {
1465
+ /**
1466
+ * Enabled when not in production and not in a testing environment.
1467
+ */
1468
+ get developmentSchedulerEnabled() {
1469
+ return !this.isProduction && !this.isTestingEnv;
1470
+ }
1471
+ };
1472
+ DefaultFirebaseServerEnvService = __decorate([
1473
+ Injectable()
1474
+ ], DefaultFirebaseServerEnvService);
1475
+
1476
+ function nestAppIsProductionEnvironment(nest) {
1477
+ return () => nest().then((x) => x.get(FirebaseServerEnvService).isProduction);
1478
+ }
1479
+ function nestAppHasDevelopmentSchedulerEnabled(nest) {
1480
+ return () => nest().then((x) => x.get(FirebaseServerEnvService).developmentSchedulerEnabled);
1481
+ }
1482
+
1483
+ // MARK: Tokens
1484
+ /**
1485
+ * Token to access the Firestore.
1486
+ */
1487
+ const FIREBASE_FIRESTORE_TOKEN = 'FIREBASE_FIRESTORE_TOKEN';
1488
+ /**
1489
+ * Token to access the root FirestoreContext for a server.
1490
+ */
1491
+ const FIREBASE_FIRESTORE_CONTEXT_TOKEN = 'FIREBASE_FIRESTORE_CONTEXT_TOKEN';
1492
+ /**
1493
+ * Nest provider module for Firebase that provides a firestore, etc. from the firestore token.
1494
+ */
1495
+ let FirebaseServerFirestoreModule = class FirebaseServerFirestoreModule {
1496
+ };
1497
+ FirebaseServerFirestoreModule = __decorate([
1498
+ Module({
1499
+ providers: [
1500
+ {
1501
+ provide: FIREBASE_FIRESTORE_TOKEN,
1502
+ useFactory: (app) => app.firestore(),
1503
+ inject: [FIREBASE_APP_TOKEN]
1504
+ }
1505
+ ],
1506
+ exports: [FIREBASE_FIRESTORE_TOKEN]
1507
+ })
1508
+ ], FirebaseServerFirestoreModule);
1509
+ /**
1510
+ * Nest provider module for firebase that includes the FirebaseServerFirestoreModule and provides a value for FIRESTORE_CONTEXT_TOKEN using the googleCloudFirestoreContextFactory.
1511
+ */
1512
+ let FirebaseServerFirestoreContextModule = class FirebaseServerFirestoreContextModule {
1513
+ };
1514
+ FirebaseServerFirestoreContextModule = __decorate([
1515
+ Module({
1516
+ imports: [FirebaseServerFirestoreModule],
1517
+ providers: [
1518
+ {
1519
+ provide: FIREBASE_FIRESTORE_CONTEXT_TOKEN,
1520
+ useFactory: googleCloudFirestoreContextFactory,
1521
+ inject: [FIREBASE_FIRESTORE_TOKEN]
1522
+ }
1523
+ ],
1524
+ exports: [FirebaseServerFirestoreModule, FIREBASE_FIRESTORE_CONTEXT_TOKEN]
1525
+ })
1526
+ ], FirebaseServerFirestoreContextModule);
1527
+ /**
1528
+ * Used to configure a Nestjs provider for a FirestoreCollections-type object that is initialized with a FirestoreContext.
1529
+ *
1530
+ * @param type
1531
+ * @param useFactory
1532
+ * @returns
1533
+ */
1534
+ function provideAppFirestoreCollections({ provide, useFactory }) {
1535
+ return [
1536
+ {
1537
+ provide,
1538
+ useFactory,
1539
+ inject: [FIREBASE_FIRESTORE_CONTEXT_TOKEN]
1540
+ }
1541
+ ];
1542
+ }
1543
+ /**
1544
+ * Convenience function used to generate ModuleMetadata for an app's Firestore related modules and an appFirestoreCollection
1545
+ *
1546
+ * @param provide
1547
+ * @param useFactory
1548
+ * @returns
1549
+ */
1550
+ function appFirestoreModuleMetadata(config) {
1551
+ return {
1552
+ imports: [FirebaseServerFirestoreContextModule, ...(config.imports ?? [])],
1553
+ exports: [FirebaseServerFirestoreContextModule, config.provide, ...(config.exports ?? [])],
1554
+ providers: [...provideAppFirestoreCollections(config), ...(config.providers ?? [])]
1555
+ };
1556
+ }
1557
+
1558
+ /**
1559
+ * Creates a BlockingFunctionWithHandler from the input.
1560
+ *
1561
+ * @param blockingFunctionBuilder
1562
+ * @param handler
1563
+ * @returns
1564
+ */
1565
+ function makeBlockingFunctionWithHandler(blockingFunctionBuilder, handler, opts) {
1566
+ const blockingFn = opts != null ? blockingFunctionBuilder(opts, handler) : blockingFunctionBuilder(handler);
1567
+ blockingFn.__handler = handler;
1568
+ return blockingFn;
1569
+ }
1570
+ /**
1571
+ * Creates a BlockingFunctionHandlerWithNestContextFactory.
1572
+ *
1573
+ * @param appFactory
1574
+ * @param makeNestContext
1575
+ * @returns
1576
+ */
1577
+ function blockingFunctionHandlerWithNestContextFactory(makeNestContext) {
1578
+ return (fn) => {
1579
+ return (nestAppPromiseGetter) => {
1580
+ const handlerBuilder = (handler) => {
1581
+ const fnHandler = (event) => nestAppPromiseGetter().then((nestApplication) => handler({
1582
+ ...event,
1583
+ nest: makeNestContext(nestApplication)
1584
+ }));
1585
+ return fnHandler;
1586
+ };
1587
+ return fn(handlerBuilder);
1588
+ };
1589
+ };
1590
+ }
1591
+
1592
+ /**
1593
+ * Creates a factory for generating OnCallWithNestApplication (firebase-functions v2) functions.
1594
+ *
1595
+ * @param opts
1596
+ * @returns
1597
+ */
1598
+ function onCallHandlerWithNestApplicationFactory(defaultOpts = {}) {
1599
+ return (fn, opts) => {
1600
+ return (nestAppPromiseGetter) => https.onCall({ ...defaultOpts, ...opts }, (request) => nestAppPromiseGetter().then((nestApplication) => fn({
1601
+ ...request,
1602
+ nestApplication
1603
+ })));
1604
+ };
1605
+ }
1606
+ /**
1607
+ * Creates a factory for generating OnCallWithNestContext functions with a nest context object that is generated by the input function.
1608
+ *
1609
+ * @param appFactory
1610
+ * @param makeNestContext
1611
+ * @returns
1612
+ */
1613
+ function onCallHandlerWithNestContextFactory(appFactory, makeNestContext) {
1614
+ return (fn, opts) => appFactory((request) => fn(setNestContextOnRequest(makeNestContext, request)), opts);
1615
+ }
1616
+
1617
+ /**
1618
+ * Creates a CloudEventHandlerWithNestContextFactory.
1619
+ *
1620
+ * @param appFactory
1621
+ * @param makeNestContext
1622
+ * @returns
1623
+ */
1624
+ function cloudEventHandlerWithNestContextFactory(makeNestContext) {
1625
+ return (fn) => {
1626
+ return (nestAppPromiseGetter) => {
1627
+ const handlerBuilder = (handler) => {
1628
+ const fnHandler = (event) => nestAppPromiseGetter().then((nestApplication) => handler({
1629
+ ...event,
1630
+ nest: makeNestContext(nestApplication)
1631
+ }));
1632
+ return fnHandler;
1633
+ };
1634
+ return fn(handlerBuilder);
1635
+ };
1636
+ };
1637
+ }
1638
+
1639
+ function setNestContextOnScheduleRequest(makeNestContext, request) {
1640
+ request.nest = makeNestContext(request.nestApplication);
1641
+ return request;
1642
+ }
1643
+
1644
+ function makeOnScheduleHandlerWithNestApplicationRequest(nestApplication, scheduleContext) {
1645
+ return {
1646
+ nestApplication,
1647
+ scheduleContext
1648
+ };
1649
+ }
1650
+ /**
1651
+ * Creates a factory for generating OnCallWithNestApplication functions.
1652
+ *
1653
+ * @param nestAppPromiseGetter
1654
+ * @returns
1655
+ */
1656
+ function onScheduleHandlerWithNestApplicationFactory(baseScheduleConfig) {
1657
+ return (inputSchedule, fn) => {
1658
+ const schedule = mergeObjects([baseScheduleConfig, inputSchedule]);
1659
+ if (!schedule.schedule) {
1660
+ if (schedule.cron) {
1661
+ if (typeof schedule.cron === 'number') {
1662
+ schedule.schedule = cronExpressionRepeatingEveryNMinutes(schedule.cron);
1663
+ }
1664
+ else {
1665
+ schedule.schedule = schedule.cron;
1666
+ }
1667
+ }
1668
+ else {
1669
+ throw new Error('Missing required "cron" or "schedule" variable for configuration.');
1670
+ }
1671
+ }
1672
+ return (nestAppPromiseGetter) => {
1673
+ const runNow = (scheduleContext) => nestAppPromiseGetter().then((x) => fn(makeOnScheduleHandlerWithNestApplicationRequest(x, scheduleContext)));
1674
+ const fnn = scheduler.onSchedule(schedule, runNow);
1675
+ fnn._schedule = schedule;
1676
+ fnn._runNow = runNow;
1677
+ return fnn;
1678
+ };
1679
+ };
1680
+ }
1681
+ /**
1682
+ * Creates a factory for generating OnCallWithNestContext functions with a nest context object that is generated by the input function.
1683
+ *
1684
+ * @param appFactory
1685
+ * @param makeNestContext
1686
+ * @returns
1687
+ */
1688
+ function onScheduleHandlerWithNestContextFactory(appFactory, makeNestContext) {
1689
+ return (schedule, fn) => appFactory(schedule, (request) => fn(setNestContextOnScheduleRequest(makeNestContext, request)));
1690
+ }
1691
+
1692
+ /**
1693
+ * Creates a TaskQueueFunctionHandlerWithNestContextFactory.
1694
+ *
1695
+ * @param appFactory
1696
+ * @param makeNestContext
1697
+ * @returns
1698
+ */
1699
+ function taskQueueFunctionHandlerWithNestContextFactory(makeNestContext) {
1700
+ return (fn) => {
1701
+ return (nestAppPromiseGetter) => {
1702
+ const handlerBuilder = (handler) => {
1703
+ const fnHandler = (taskRequest) => nestAppPromiseGetter().then((nestApplication) => handler({
1704
+ ...taskRequest,
1705
+ nest: makeNestContext(nestApplication)
1706
+ }));
1707
+ return fnHandler;
1708
+ };
1709
+ return fn(handlerBuilder);
1710
+ };
1711
+ };
1712
+ }
1713
+ // TODO(FUTURE): Add factory that also adds onTaskDispatched usage, as the above is incomplete for full usage and only sets up a function for the request.
1714
+
1715
+ class AbstractFirebaseServerActionsContext {
1716
+ }
1717
+ function firebaseServerActionsContext(options) {
1718
+ return {
1719
+ ...firebaseServerActionsTransformContext(options)
1720
+ };
1721
+ }
1722
+ const defaultFirebaseServerActionsTransformFactoryLogErrorFunction = (details) => {
1723
+ console.log('firebaseServerActionsTransformFactory() encountered validation error: ', details);
1724
+ };
1725
+ function firebaseServerActionsTransformContext(options) {
1726
+ const firebaseServerActionTransformFactory = firebaseServerActionsTransformFactory(options);
1727
+ const firebaseServerActionTransformFunctionFactory = toTransformAndValidateFunctionResultFactory(firebaseServerActionTransformFactory);
1728
+ return {
1729
+ firebaseServerActionTransformFactory,
1730
+ firebaseServerActionTransformFunctionFactory
1731
+ };
1732
+ }
1733
+ const FIREBASE_SERVER_VALIDATION_ERROR_CODE = 'VALIDATION_ERROR';
1734
+ /**
1735
+ *
1736
+ * @param validationError
1737
+ * @returns
1738
+ */
1739
+ function firebaseServerValidationServerError(validationError) {
1740
+ const nestValidationExceptionFactory = new ValidationPipe({
1741
+ forbidUnknownValues: false
1742
+ }).createExceptionFactory();
1743
+ const nestError = nestValidationExceptionFactory(validationError);
1744
+ const data = nestError.getResponse();
1745
+ return {
1746
+ message: 'One or more data/form validation errors occurred.',
1747
+ code: FIREBASE_SERVER_VALIDATION_ERROR_CODE,
1748
+ data
1749
+ };
1750
+ }
1751
+ /**
1752
+ * Creates a new badRequestError with the validation error details as the response data.
1753
+ *
1754
+ * @param validationError
1755
+ * @returns
1756
+ */
1757
+ function firebaseServerValidationError(validationError) {
1758
+ const serverError = firebaseServerValidationServerError(validationError);
1759
+ return badRequestError(serverError);
1760
+ }
1761
+ function firebaseServerActionsTransformFactory(options) {
1762
+ const { logError, defaultValidationOptions } = options ?? {};
1763
+ const logErrorFunction = logError !== false ? (typeof logError === 'function' ? logError : defaultFirebaseServerActionsTransformFactoryLogErrorFunction) : mapIdentityFunction;
1764
+ return transformAndValidateObjectFactory({
1765
+ handleValidationError: (validationError) => {
1766
+ const serverError = firebaseServerValidationServerError(validationError);
1767
+ const { data } = serverError;
1768
+ logErrorFunction(data);
1769
+ throw badRequestError(serverError);
1770
+ },
1771
+ defaultValidationOptions
1772
+ });
1773
+ }
1774
+
1775
+ function injectNestIntoRequest(nest, request) {
1776
+ return {
1777
+ ...request,
1778
+ nest
1779
+ };
1780
+ }
1781
+ function injectNestApplicationContextIntoRequest(nestContext, request) {
1782
+ return {
1783
+ ...request,
1784
+ nestApplication: nestContext
1785
+ };
1786
+ }
1787
+
1788
+ /**
1789
+ * Can be injected to retrieve information about the global prefix configured for the app.
1790
+ */
1791
+ class GlobalRoutePrefixConfig {
1792
+ globalApiRoutePrefix;
1793
+ }
1794
+
1795
+ /**
1796
+ * Middleware that verifies the X-Firebase-AppCheck header using admin.
1797
+ *
1798
+ * It ignores all webhook paths by default.
1799
+ */
1800
+ let FirebaseAppCheckMiddleware = class FirebaseAppCheckMiddleware {
1801
+ globalRoutePrefixConfig;
1802
+ logger = new Logger('FirebaseAppCheckMiddleware');
1803
+ _ignoredWebhookPath;
1804
+ constructor(globalRoutePrefixConfig) {
1805
+ this.globalRoutePrefixConfig = globalRoutePrefixConfig;
1806
+ this._ignoredWebhookPath = this.globalRoutePrefixConfig?.globalApiRoutePrefix ? `${this.globalRoutePrefixConfig.globalApiRoutePrefix}${DEFAULT_BASE_WEBHOOK_PATH}` : DEFAULT_BASE_WEBHOOK_PATH;
1807
+ }
1808
+ async use(req, res, next) {
1809
+ const isIgnoredRoute = this.isIgnoredRequest(req);
1810
+ let error;
1811
+ if (!isIgnoredRoute) {
1812
+ error = await verifyAppCheckInRequest(req);
1813
+ if (error) {
1814
+ this.logger.error('app check token failed verify');
1815
+ }
1816
+ }
1817
+ next(error);
1818
+ }
1819
+ isIgnoredRequest(req) {
1820
+ const isIgnoredRoute = req.skipAppCheck || this.isIgnoredPath(req.baseUrl);
1821
+ return isIgnoredRoute;
1822
+ }
1823
+ isIgnoredPath(path) {
1824
+ return path.startsWith(this._ignoredWebhookPath);
1825
+ }
1826
+ };
1827
+ FirebaseAppCheckMiddleware = __decorate([
1828
+ Injectable(),
1829
+ __param(0, Optional()),
1830
+ __param(0, Inject(GlobalRoutePrefixConfig)),
1831
+ __metadata("design:paramtypes", [Object])
1832
+ ], FirebaseAppCheckMiddleware);
1833
+ /**
1834
+ * Verifies the AppCheck parameter. If it fails, a value is returned.
1835
+ *
1836
+ * @param req
1837
+ * @param res
1838
+ * @param next
1839
+ * @returns
1840
+ */
1841
+ async function verifyAppCheckInRequest(req) {
1842
+ const appCheckToken = req.header('X-Firebase-AppCheck');
1843
+ let error;
1844
+ if (!appCheckToken) {
1845
+ error = new ForbiddenException();
1846
+ }
1847
+ else {
1848
+ // verify the token
1849
+ try {
1850
+ await admin.appCheck().verifyToken(appCheckToken);
1851
+ }
1852
+ catch (e) {
1853
+ error = new ForbiddenException();
1854
+ }
1855
+ }
1856
+ return error;
1857
+ }
1858
+
1859
+ /**
1860
+ * Convenience class that mirrors the ConfigureAppCheckMiddlewareModule class in @dereekb/nestjs, but for Firebase apps.
1861
+ */
1862
+ let ConfigureFirebaseAppCheckMiddlewareModule = class ConfigureFirebaseAppCheckMiddlewareModule {
1863
+ logger = new Logger('ConfigureFirebaseAppCheckMiddlewareModule');
1864
+ configure(consumer) {
1865
+ consumer.apply(FirebaseAppCheckMiddleware).forRoutes('*');
1866
+ this.logger.debug('Configured firebase webhook routes with proper middleware.');
1867
+ }
1868
+ };
1869
+ ConfigureFirebaseAppCheckMiddlewareModule = __decorate([
1870
+ Module({})
1871
+ ], ConfigureFirebaseAppCheckMiddlewareModule);
1872
+
1873
+ /**
1874
+ * nestjs decorator that will instruct FirebaseAppCheckMiddleware to skip AppCheck for related requests.
1875
+ */
1876
+ const SkipAppCheck = createParamDecorator(async (_, context) => {
1877
+ const req = context.switchToHttp().getRequest();
1878
+ req.skipAppCheck = true;
1879
+ });
1880
+
1881
+ let FirebaseRawBodyMiddleware = class FirebaseRawBodyMiddleware {
1882
+ use(req, res, next) {
1883
+ req.body = req.rawBody;
1884
+ next();
1885
+ }
1886
+ };
1887
+ FirebaseRawBodyMiddleware = __decorate([
1888
+ Injectable()
1889
+ ], FirebaseRawBodyMiddleware);
1890
+
1891
+ /**
1892
+ * Convenience class that mirrors the ConfigureWebhookMiddlewareModule class in @dereekb/nestjs, but for Firebase apps.
1893
+ *
1894
+ * Requests to /webhook/* have their request.body value set to the rawBody.
1895
+ */
1896
+ let ConfigureFirebaseWebhookMiddlewareModule = class ConfigureFirebaseWebhookMiddlewareModule {
1897
+ logger = new Logger('ConfigureFirebaseWebhookMiddlewareModule');
1898
+ configure(consumer) {
1899
+ consumer.apply(FirebaseRawBodyMiddleware).forRoutes(DEFAULT_WEBHOOK_MIDDLEWARE_ROUTE_INFO);
1900
+ this.logger.debug('Configured firebase webhook routes with proper middleware.');
1901
+ }
1902
+ };
1903
+ ConfigureFirebaseWebhookMiddlewareModule = __decorate([
1904
+ Module({})
1905
+ ], ConfigureFirebaseWebhookMiddlewareModule);
1906
+
1907
+ const nestFirebaseDoesNotExistError = (firebaseContextGrantedModelRoles) => {
1908
+ return modelNotAvailableError({
1909
+ data: {
1910
+ id: firebaseContextGrantedModelRoles.data?.document.key,
1911
+ type: firebaseContextGrantedModelRoles.data?.document.modelType
1912
+ }
1913
+ });
1914
+ };
1915
+ const nestFirebaseForbiddenPermissionError = (firebaseContextGrantedModelRoles, roles) => {
1916
+ return forbiddenError({
1917
+ data: {
1918
+ id: firebaseContextGrantedModelRoles.data?.document.key,
1919
+ type: firebaseContextGrantedModelRoles.data?.document.modelType,
1920
+ roles
1921
+ }
1922
+ });
1923
+ };
1924
+
1925
+ function onCallSpecifierHandler(config) {
1926
+ const map = objectToMap(config);
1927
+ const fn = (request) => {
1928
+ const { specifier = MODEL_FUNCTION_FIREBASE_CRUD_FUNCTION_SPECIFIER_DEFAULT } = request;
1929
+ const handler = map.get(specifier);
1930
+ if (handler != null) {
1931
+ assertRequestRequiresAuthForFunction(handler, request);
1932
+ return handler(request);
1933
+ }
1934
+ else {
1935
+ throw unknownModelCrudFunctionSpecifierError(specifier);
1936
+ }
1937
+ };
1938
+ fn._requireAuth = false;
1939
+ return fn;
1940
+ }
1941
+ function unknownModelCrudFunctionSpecifierError(specifier) {
1942
+ return badRequestError(serverError({
1943
+ status: 400,
1944
+ code: 'UNKNOWN_SPECIFIER_ERROR',
1945
+ message: 'Invalid/unknown specifier for this function.',
1946
+ data: {
1947
+ specifier
1948
+ }
1949
+ }));
1950
+ }
1951
+
1952
+ /**
1953
+ * Creates a OnCallWithAuthorizedNestContext function for creating a model.
1954
+ *
1955
+ * @param map
1956
+ * @returns
1957
+ */
1958
+ function onCallModel(map, config = {}) {
1959
+ const { preAssert = () => undefined } = config;
1960
+ return (request) => {
1961
+ const call = request.data?.call;
1962
+ if (call) {
1963
+ const callFn = map[call];
1964
+ if (callFn) {
1965
+ const { specifier, modelType } = request.data;
1966
+ preAssert({ call, request, modelType, specifier });
1967
+ return callFn(request);
1968
+ }
1969
+ else {
1970
+ throw onCallModelUnknownCallTypeError(call);
1971
+ }
1972
+ }
1973
+ else {
1974
+ throw onCallModelMissingCallTypeError();
1975
+ }
1976
+ };
1977
+ }
1978
+ function onCallModelMissingCallTypeError() {
1979
+ return badRequestError(serverError({
1980
+ status: 400,
1981
+ code: 'CALL_TYPE_MISSING_ERROR',
1982
+ message: `The call type was missing from the request.`
1983
+ }));
1984
+ }
1985
+ function onCallModelUnknownCallTypeError(call) {
1986
+ return badRequestError(serverError({
1987
+ status: 400,
1988
+ code: 'UNKNOWN_CALL_TYPE_ERROR',
1989
+ message: `Unknown call type "${call}".`,
1990
+ data: {
1991
+ call
1992
+ }
1993
+ }));
1994
+ }
1995
+ function _onCallWithCallTypeFunction(map, config) {
1996
+ const { callType, crudType, preAssert = () => undefined, throwOnUnknownModelType } = config;
1997
+ return (request) => {
1998
+ const modelType = request.data?.modelType;
1999
+ const crudFn = map[modelType];
2000
+ if (crudFn) {
2001
+ const specifier = request.data.specifier;
2002
+ assertRequestRequiresAuthForFunction(crudFn, request);
2003
+ preAssert({ call: callType, request, modelType, specifier });
2004
+ return crudFn({
2005
+ ...request,
2006
+ specifier,
2007
+ data: request.data.data
2008
+ });
2009
+ }
2010
+ else {
2011
+ throw throwOnUnknownModelType(modelType);
2012
+ }
2013
+ };
2014
+ }
2015
+
2016
+ function onCallCreateModel(map, config = {}) {
2017
+ const { preAssert } = config;
2018
+ return _onCallWithCallTypeFunction(map, {
2019
+ callType: 'create',
2020
+ crudType: 'create',
2021
+ preAssert,
2022
+ throwOnUnknownModelType: createModelUnknownModelTypeError
2023
+ });
2024
+ }
2025
+ function createModelUnknownModelTypeError(modelType) {
2026
+ return badRequestError(serverError({
2027
+ status: 400,
2028
+ code: 'UNKNOWN_TYPE_ERROR',
2029
+ message: `Invalid type "${modelType}" to create.`,
2030
+ data: {
2031
+ modelType
2032
+ }
2033
+ }));
2034
+ }
2035
+
2036
+ function onCallReadModel(map, config = {}) {
2037
+ const { preAssert } = config;
2038
+ return _onCallWithCallTypeFunction(map, {
2039
+ callType: 'read',
2040
+ crudType: 'read',
2041
+ preAssert,
2042
+ throwOnUnknownModelType: readModelUnknownModelTypeError
2043
+ });
2044
+ }
2045
+ function readModelUnknownModelTypeError(modelType) {
2046
+ return badRequestError(serverError({
2047
+ status: 400,
2048
+ code: 'UNKNOWN_TYPE_ERROR',
2049
+ message: 'Invalid type to read.',
2050
+ data: {
2051
+ modelType
2052
+ }
2053
+ }));
2054
+ }
2055
+
2056
+ function onCallUpdateModel(map, config = {}) {
2057
+ const { preAssert } = config;
2058
+ return _onCallWithCallTypeFunction(map, {
2059
+ callType: 'update',
2060
+ crudType: 'update',
2061
+ preAssert,
2062
+ throwOnUnknownModelType: updateModelUnknownModelTypeError
2063
+ });
2064
+ }
2065
+ function updateModelUnknownModelTypeError(modelType) {
2066
+ return badRequestError(serverError({
2067
+ status: 400,
2068
+ code: 'UNKNOWN_TYPE_ERROR',
2069
+ message: 'Invalid type to update.',
2070
+ data: {
2071
+ modelType
2072
+ }
2073
+ }));
2074
+ }
2075
+
2076
+ function onCallDeleteModel(map, config = {}) {
2077
+ const { preAssert } = config;
2078
+ return _onCallWithCallTypeFunction(map, {
2079
+ callType: 'delete',
2080
+ crudType: 'delete',
2081
+ preAssert,
2082
+ throwOnUnknownModelType: deleteModelUnknownModelTypeError
2083
+ });
2084
+ }
2085
+ function deleteModelUnknownModelTypeError(modelType) {
2086
+ return badRequestError(serverError({
2087
+ status: 400,
2088
+ code: 'UNKNOWN_TYPE_ERROR',
2089
+ message: 'Invalid type to delete.',
2090
+ data: {
2091
+ modelType
2092
+ }
2093
+ }));
2094
+ }
2095
+
2096
+ function googleCloudStorageBucketForStorageFilePath(storage, path) {
2097
+ return storage.bucket(path.bucketId);
2098
+ }
2099
+ function googleCloudStorageFileForStorageFilePath(storage, path) {
2100
+ return googleCloudStorageBucketForStorageFilePath(storage, path).file(path.pathString);
2101
+ }
2102
+ function googleCloudFileMetadataToStorageMetadata(file, metadata) {
2103
+ const fullPath = file.name;
2104
+ const generation = String(metadata.generation ?? file.generation);
2105
+ const metageneration = String(metadata.metageneration);
2106
+ const size = Number(metadata.size);
2107
+ const customMetadata = metadata.metadata;
2108
+ return {
2109
+ bucket: file.bucket.name,
2110
+ fullPath,
2111
+ generation,
2112
+ metageneration,
2113
+ name: file.name,
2114
+ size,
2115
+ timeCreated: metadata.timeCreated,
2116
+ updated: metadata.updated,
2117
+ md5Hash: metadata.md5Hash,
2118
+ cacheControl: metadata.cacheControl,
2119
+ contentDisposition: metadata.contentDisposition,
2120
+ contentEncoding: metadata.contentEncoding,
2121
+ contentLanguage: metadata.contentLanguage,
2122
+ contentType: metadata.contentType,
2123
+ customMetadata
2124
+ };
2125
+ }
2126
+ function googleCloudStorageAccessorFile(storage, storagePath) {
2127
+ const file = googleCloudStorageFileForStorageFilePath(storage, storagePath);
2128
+ function makeDownloadOptions(maxDownloadSizeBytes) {
2129
+ return {
2130
+ ...(maxDownloadSizeBytes
2131
+ ? {
2132
+ // end is inclusive
2133
+ end: maxDownloadSizeBytes - 1
2134
+ }
2135
+ : undefined)
2136
+ };
2137
+ }
2138
+ function _configureMetadata(options) {
2139
+ const customMetadata = filterUndefinedValues({
2140
+ ...options.metadata?.customMetadata,
2141
+ ...options?.customMetadata
2142
+ });
2143
+ return filterUndefinedValues({
2144
+ cacheControl: options.metadata?.cacheControl,
2145
+ contentDisposition: options.metadata?.contentDisposition,
2146
+ contentEncoding: options.metadata?.contentEncoding,
2147
+ contentLanguage: options.metadata?.contentLanguage,
2148
+ contentType: options.metadata?.contentType,
2149
+ metadata: !objectHasNoKeys(customMetadata) ? customMetadata : undefined
2150
+ });
2151
+ }
2152
+ function makeUploadOptions(options) {
2153
+ let metadata;
2154
+ if (options != null) {
2155
+ metadata = _configureMetadata({
2156
+ metadata: {
2157
+ ...options.metadata,
2158
+ contentType: options.contentType ?? options.metadata?.contentType
2159
+ },
2160
+ customMetadata: options.customMetadata
2161
+ });
2162
+ }
2163
+ return {
2164
+ // non-resumable
2165
+ resumable: false,
2166
+ // add content type and other custom metadata
2167
+ ...(metadata ? { metadata } : undefined)
2168
+ };
2169
+ }
2170
+ function asFileMetadata(metadata) {
2171
+ return _configureMetadata({ metadata });
2172
+ }
2173
+ function makeStoragePathForPath(newPath) {
2174
+ let path;
2175
+ if (typeof newPath === 'string') {
2176
+ path = {
2177
+ bucketId: file.bucket.name,
2178
+ pathString: newPath
2179
+ };
2180
+ }
2181
+ else {
2182
+ path = newPath;
2183
+ }
2184
+ return path;
2185
+ }
2186
+ async function copy(newPath, options) {
2187
+ const newStoragePath = makeStoragePathForPath(newPath);
2188
+ const newFile = googleCloudStorageAccessorFile(storage, newStoragePath);
2189
+ return _copyWithFile(newFile, options);
2190
+ }
2191
+ async function _copyWithFile(newFile, options) {
2192
+ const copyOptions = {
2193
+ ...options
2194
+ };
2195
+ await file.copy(newFile.reference, copyOptions);
2196
+ return newFile;
2197
+ }
2198
+ /**
2199
+ * Configuration for the public ACL.
2200
+ */
2201
+ const PUBLIC_ACL = {
2202
+ entity: 'allUsers',
2203
+ role: 'READER'
2204
+ };
2205
+ const accessorFile = {
2206
+ reference: file,
2207
+ storagePath,
2208
+ exists: () => file.exists().then((x) => x[0]),
2209
+ getDownloadUrl: () => file.getMetadata().then(() => file.publicUrl()),
2210
+ getSignedUrl: async (input) => {
2211
+ const expires = input?.expiresAt ??
2212
+ (input?.expiresIn != null
2213
+ ? addMilliseconds(new Date(), input.expiresIn) // use expiresIn if provided
2214
+ : addHours(new Date(), 1)); // default expiration in 1 hour
2215
+ const config = {
2216
+ ...input,
2217
+ action: input?.action ?? 'read',
2218
+ expires,
2219
+ expiresIn: undefined, // clear from input
2220
+ expiresAt: undefined
2221
+ };
2222
+ return file
2223
+ .getSignedUrl(config)
2224
+ .then((x) => x[0])
2225
+ .catch((e) => {
2226
+ let publicUrlBackup;
2227
+ if (e && e.name === 'SigningError' && (isTestNodeEnv() || process.env.FIREBASE_STORAGE_EMULATOR_HOST)) {
2228
+ // NOTE: Signing does not behave properly in the emulator as it is not supported.
2229
+ // https://github.com/firebase/firebase-tools/issues/3400
2230
+ // we can return the public url instead.
2231
+ // This is fine, as in production this file url is protected by ACLs anyways.
2232
+ publicUrlBackup = file.publicUrl();
2233
+ }
2234
+ else {
2235
+ throw e;
2236
+ }
2237
+ return publicUrlBackup;
2238
+ });
2239
+ },
2240
+ getMetadata: () => file.getMetadata().then((x) => googleCloudFileMetadataToStorageMetadata(file, x[0])),
2241
+ setMetadata: (metadata) => file.setMetadata(asFileMetadata(metadata)).then((x) => googleCloudFileMetadataToStorageMetadata(file, x[0])),
2242
+ getBytes: (maxDownloadSizeBytes) => file.download(makeDownloadOptions(maxDownloadSizeBytes)).then((x) => x[0]),
2243
+ getStream: (maxDownloadSizeBytes) => file.createReadStream(makeDownloadOptions(maxDownloadSizeBytes)),
2244
+ upload: async (input, options) => {
2245
+ let dataToUpload;
2246
+ if (typeof input === 'string') {
2247
+ const parsedStringFormat = assertStorageUploadOptionsStringFormat(options);
2248
+ const stringFormat = parsedStringFormat === 'raw' ? 'utf-8' : parsedStringFormat;
2249
+ if (stringFormat === 'data_url') {
2250
+ // TODO(FUTURE): support this later if necessary. Server should really never see this type.
2251
+ throw new Error('"data_url" is unsupported.');
2252
+ }
2253
+ dataToUpload = Buffer.from(input, stringFormat);
2254
+ }
2255
+ else {
2256
+ if (Buffer.isBuffer(input)) {
2257
+ dataToUpload = input;
2258
+ }
2259
+ else if (isUint8Array(input)) {
2260
+ dataToUpload = Buffer.from(input);
2261
+ }
2262
+ else {
2263
+ // NOTE: these values shouldn't ever be encountered in the NodeJS environment. May remove later.
2264
+ if (isArrayBuffer(input)) {
2265
+ dataToUpload = Buffer.from(input);
2266
+ }
2267
+ else {
2268
+ dataToUpload = input.arrayBuffer().then((x) => Buffer.from(x));
2269
+ }
2270
+ }
2271
+ }
2272
+ const data = await dataToUpload;
2273
+ return file.save(data, makeUploadOptions(options));
2274
+ },
2275
+ uploadStream: (options) => file.createWriteStream(makeUploadOptions(options)),
2276
+ move: async (newPath, options) => {
2277
+ const newStoragePath = makeStoragePathForPath(newPath);
2278
+ const newFile = googleCloudStorageAccessorFile(storage, newStoragePath);
2279
+ const moveOptions = {
2280
+ ...options
2281
+ };
2282
+ await file.moveFileAtomic(newFile.reference, moveOptions).catch(async (e) => {
2283
+ if (e instanceof ApiError && e.response?.statusMessage === 'Not Implemented') {
2284
+ // NOTE: This is not implemented in storage emulator, so it will fail with this error in testing.
2285
+ // https://github.com/firebase/firebase-tools/issues/3751
2286
+ // we can perform the same task using copy and then deleting this file.
2287
+ await copy(newPath, moveOptions);
2288
+ await accessorFile.delete();
2289
+ }
2290
+ else {
2291
+ throw e;
2292
+ }
2293
+ });
2294
+ return newFile;
2295
+ },
2296
+ copy,
2297
+ delete: (options) => file.delete(options).then((x) => undefined),
2298
+ isPublic: () => file.isPublic().then((x) => x[0]),
2299
+ makePublic: (setPublic) => (setPublic !== false ? file.acl.add(PUBLIC_ACL) : file.acl.delete({ entity: PUBLIC_ACL.entity })).then(() => undefined),
2300
+ makePrivate: (options) => file.makePrivate(options).then(() => undefined),
2301
+ getAcls: (options) => file.acl.get(options).then((x) => ({ acls: x[0], metadata: x[1] }))
2302
+ };
2303
+ return accessorFile;
2304
+ }
2305
+ const googleCloudStorageListFilesResultFactory = storageListFilesResultFactory({
2306
+ hasItems(result) {
2307
+ return Boolean(result.apiResponse.items || result.apiResponse.prefixes);
2308
+ },
2309
+ hasNext: (result) => {
2310
+ return result.nextQuery != null;
2311
+ },
2312
+ nextPageTokenFromResult(result) {
2313
+ return result.nextQuery?.pageToken;
2314
+ },
2315
+ next(storage, options, folder, result) {
2316
+ return folder.list({ ...options, ...result.nextQuery });
2317
+ },
2318
+ file(storage, fileResult) {
2319
+ return googleCloudStorageAccessorFile(storage, fileResult.storagePath);
2320
+ },
2321
+ folder(storage, folderResult) {
2322
+ return googleCloudStorageAccessorFolder(storage, folderResult.storagePath);
2323
+ },
2324
+ filesFromResult(result) {
2325
+ const items = result.apiResponse?.items ?? [];
2326
+ return items.map((x) => ({ raw: x, name: slashPathName(x.name), storagePath: { bucketId: x.bucket, pathString: x.name } }));
2327
+ },
2328
+ foldersFromResult(result, folder) {
2329
+ const items = result.apiResponse?.prefixes ?? [];
2330
+ return items.map((prefix) => ({ raw: prefix, name: slashPathName(prefix), storagePath: { bucketId: folder.storagePath.bucketId, pathString: prefix } }));
2331
+ }
2332
+ });
2333
+ function googleCloudStorageAccessorFolder(storage, storagePath) {
2334
+ const bucket = googleCloudStorageBucketForStorageFilePath(storage, storagePath);
2335
+ const file = bucket.file(storagePath.pathString);
2336
+ const folder = {
2337
+ reference: file,
2338
+ storagePath,
2339
+ exists: async () => folder.list({ maxResults: 1 }).then((x) => x.hasItems()),
2340
+ list: (options) => {
2341
+ const { maxResults, pageToken, includeNestedResults: listAll } = options ?? {};
2342
+ const listOptions = {
2343
+ maxResults,
2344
+ pageToken,
2345
+ autoPaginate: false,
2346
+ versions: false,
2347
+ ...(listAll
2348
+ ? {
2349
+ prefix: toRelativeSlashPathStartType(fixMultiSlashesInSlashPath(storagePath.pathString + '/'))
2350
+ }
2351
+ : {
2352
+ // includeTrailingDelimiter: true,
2353
+ delimiter: SLASH_PATH_SEPARATOR,
2354
+ prefix: toRelativeSlashPathStartType(fixMultiSlashesInSlashPath(storagePath.pathString + '/')) // make sure the folder always ends with a slash
2355
+ })
2356
+ };
2357
+ return bucket.getFiles(listOptions).then((x) => {
2358
+ const files = x[0];
2359
+ const nextQuery = x[1];
2360
+ const apiResponse = x[2];
2361
+ const result = {
2362
+ files: files,
2363
+ nextQuery,
2364
+ apiResponse: apiResponse
2365
+ };
2366
+ return googleCloudStorageListFilesResultFactory(storage, folder, options, result);
2367
+ });
2368
+ }
2369
+ };
2370
+ return folder;
2371
+ }
2372
+ function googleCloudStorageFirebaseStorageAccessorDriver() {
2373
+ return {
2374
+ type: 'server',
2375
+ file: (storage, path) => googleCloudStorageAccessorFile(storage, path),
2376
+ folder: (storage, path) => googleCloudStorageAccessorFolder(storage, path)
2377
+ };
2378
+ }
2379
+
2380
+ function googleCloudFirebaseStorageDrivers() {
2381
+ return {
2382
+ storageDriverIdentifier: '@google-cloud/storage',
2383
+ storageDriverType: 'production',
2384
+ storageAccessorDriver: googleCloudStorageFirebaseStorageAccessorDriver()
2385
+ };
2386
+ }
2387
+
2388
+ /**
2389
+ * Basic service that implements FirebaseStorageAccessor and provides a FirebaseStorageContext.
2390
+ */
2391
+ class FirebaseServerStorageService {
2392
+ _storageContext;
2393
+ constructor(storageContext) {
2394
+ this._storageContext = storageContext;
2395
+ }
2396
+ get storageContext() {
2397
+ return this._storageContext;
2398
+ }
2399
+ defaultBucket() {
2400
+ return this.storageContext.defaultBucket();
2401
+ }
2402
+ file(path) {
2403
+ return this.storageContext.file(path);
2404
+ }
2405
+ folder(path) {
2406
+ return this.storageContext.folder(path);
2407
+ }
2408
+ }
2409
+
2410
+ /**
2411
+ * Creates a FirestoreContextFactory that uses the @google-cloud/storage package.
2412
+ */
2413
+ const googleCloudFirebaseStorageContextFactory = firebaseStorageContextFactory(googleCloudFirebaseStorageDrivers());
2414
+ /**
2415
+ * Retrieves the GoogleCloudStorage object from the input FirebaseAdmin Storage type.
2416
+ *
2417
+ * @param storage
2418
+ * @returns
2419
+ */
2420
+ function googleCloudStorageFromFirebaseAdminStorage(storage) {
2421
+ return storage.storageClient;
2422
+ }
2423
+
2424
+ // MARK: Tokens
2425
+ /**
2426
+ * Token to access the Storage.
2427
+ */
2428
+ const FIREBASE_STORAGE_TOKEN = 'FIREBASE_STORAGE_TOKEN';
2429
+ /**
2430
+ * Token to access the root StorageContext for a server.
2431
+ */
2432
+ const FIREBASE_STORAGE_CONTEXT_TOKEN = 'FIREBASE_STORAGE_CONTEXT_TOKEN';
2433
+ /**
2434
+ * Token to the default bucket id string
2435
+ */
2436
+ const FIREBASE_STORAGE_CONTEXT_FACTORY_CONFIG_TOKEN = 'FIREBASE_STORAGE_CONTEXT_FACTORY_CONFIG_TOKEN';
2437
+ /**
2438
+ * Nest provider module for Firebase that provides a firestore, etc. from the firestore token.
2439
+ */
2440
+ let FirebaseServerStorageModule = class FirebaseServerStorageModule {
2441
+ };
2442
+ FirebaseServerStorageModule = __decorate([
2443
+ Module({
2444
+ providers: [
2445
+ {
2446
+ provide: FIREBASE_STORAGE_TOKEN,
2447
+ useFactory: (app) => googleCloudStorageFromFirebaseAdminStorage(app.storage()),
2448
+ inject: [FIREBASE_APP_TOKEN]
2449
+ }
2450
+ ],
2451
+ exports: [FIREBASE_STORAGE_TOKEN]
2452
+ })
2453
+ ], FirebaseServerStorageModule);
2454
+ /**
2455
+ * Nest provider module for firebase that includes the FirebaseServerStorageModule and provides a value for STORAGE_CONTEXT_TOKEN using the googleCloudStorageContextFactory.
2456
+ */
2457
+ let FirebaseServerStorageContextModule = class FirebaseServerStorageContextModule {
2458
+ };
2459
+ FirebaseServerStorageContextModule = __decorate([
2460
+ Module({
2461
+ imports: [FirebaseServerStorageModule],
2462
+ providers: [
2463
+ {
2464
+ provide: FIREBASE_STORAGE_CONTEXT_TOKEN,
2465
+ useFactory: googleCloudFirebaseStorageContextFactory,
2466
+ inject: [FIREBASE_STORAGE_TOKEN, FIREBASE_STORAGE_CONTEXT_FACTORY_CONFIG_TOKEN]
2467
+ }
2468
+ ],
2469
+ exports: [FirebaseServerStorageModule, FIREBASE_STORAGE_CONTEXT_TOKEN]
2470
+ })
2471
+ ], FirebaseServerStorageContextModule);
2472
+ // MARK: Token Configuration
2473
+ function firebaseServerStorageDefaultBucketIdTokenProvider(input) {
2474
+ const config = typeof input === 'string' ? { defaultBucketId: input } : input;
2475
+ if (!config.defaultBucketId) {
2476
+ throw new Error('Non-empty defaultBucketId is required.');
2477
+ }
2478
+ return {
2479
+ provide: FIREBASE_STORAGE_CONTEXT_FACTORY_CONFIG_TOKEN,
2480
+ useValue: config
2481
+ };
2482
+ }
2483
+ function defaultProvideFirebaseServerStorageServiceSimple() {
2484
+ return {
2485
+ provide: FirebaseServerStorageService,
2486
+ useFactory: (context) => new FirebaseServerStorageService(context)
2487
+ };
2488
+ }
2489
+ function provideFirebaseServerStorageService(provider) {
2490
+ const providers = [
2491
+ {
2492
+ ...provider,
2493
+ inject: provider.inject ?? [FIREBASE_STORAGE_CONTEXT_TOKEN]
2494
+ }
2495
+ ];
2496
+ if (provider.provide !== FirebaseServerStorageService) {
2497
+ providers.push({
2498
+ provide: FirebaseServerStorageService,
2499
+ useExisting: provider.provide
2500
+ });
2501
+ }
2502
+ return providers;
2503
+ }
2504
+ /**
2505
+ * Convenience function used to generate ModuleMetadata for an app's Auth related modules and FirebaseServerStorageService provider.
2506
+ *
2507
+ * @param provide
2508
+ * @param useFactory
2509
+ * @returns
2510
+ */
2511
+ function firebaseServerStorageModuleMetadata(config) {
2512
+ const serviceProvider = config && config.serviceProvider ? config.serviceProvider : defaultProvideFirebaseServerStorageServiceSimple();
2513
+ const providers = provideFirebaseServerStorageService(serviceProvider);
2514
+ const tokensToExport = injectionTokensFromProviders(providers);
2515
+ return mergeModuleMetadata({
2516
+ imports: [FirebaseServerStorageContextModule],
2517
+ exports: [FirebaseServerStorageContextModule, ...tokensToExport],
2518
+ providers
2519
+ }, config);
2520
+ }
2521
+
2522
+ class FirebaseNestServerRootModule {
2523
+ }
2524
+ function nestServerInstance(config) {
2525
+ const { moduleClass, providers: additionalProviders, defaultStorageBucket: inputDefaultStorageBucket, forceStorageBucket, globalApiRoutePrefix, configureNestServerInstance } = config;
2526
+ const serversCache = new Map();
2527
+ const initNestServer = (firebaseApp, env) => {
2528
+ const appName = firebaseApp.name;
2529
+ const defaultStorageBucket = inputDefaultStorageBucket ?? firebaseApp.options.storageBucket;
2530
+ let nestServer = serversCache.get(appName);
2531
+ if (!nestServer) {
2532
+ const server = express();
2533
+ const createNestServer = async (expressInstance) => {
2534
+ const providers = [firebaseServerAppTokenProvider(asGetter(firebaseApp))];
2535
+ // configure environment providers
2536
+ if (env?.environment != null) {
2537
+ providers.push(serverEnvTokenProvider(env.environment));
2538
+ if (config.configureEnvService !== false) {
2539
+ providers.push({
2540
+ provide: FirebaseServerEnvService,
2541
+ useClass: DefaultFirebaseServerEnvService
2542
+ }, {
2543
+ provide: ServerEnvironmentService,
2544
+ useExisting: FirebaseServerEnvService
2545
+ });
2546
+ }
2547
+ }
2548
+ if (additionalProviders) {
2549
+ pushItemOrArrayItemsIntoArray(providers, additionalProviders);
2550
+ }
2551
+ const imports = [moduleClass];
2552
+ // NOTE: https://cloud.google.com/functions/docs/writing/http#parsing_http_requests
2553
+ const options = { bodyParser: false }; // firebase already parses the requests
2554
+ if (config.configureWebhooks) {
2555
+ imports.push(ConfigureFirebaseWebhookMiddlewareModule);
2556
+ }
2557
+ if (config.appCheckEnabled != false) {
2558
+ imports.push(ConfigureFirebaseAppCheckMiddlewareModule);
2559
+ }
2560
+ if (defaultStorageBucket) {
2561
+ providers.push(firebaseServerStorageDefaultBucketIdTokenProvider({
2562
+ defaultBucketId: defaultStorageBucket,
2563
+ forceBucket: forceStorageBucket
2564
+ }));
2565
+ }
2566
+ // provide the global prefix config to the app
2567
+ providers.push({
2568
+ provide: GlobalRoutePrefixConfig,
2569
+ useValue: {
2570
+ globalApiRoutePrefix
2571
+ }
2572
+ });
2573
+ const providersModule = {
2574
+ module: FirebaseNestServerRootModule,
2575
+ imports,
2576
+ providers,
2577
+ exports: providers,
2578
+ global: true
2579
+ };
2580
+ let nestApp = await NestFactory.create(providersModule, new ExpressAdapter(expressInstance), options);
2581
+ if (globalApiRoutePrefix) {
2582
+ nestApp = nestApp.setGlobalPrefix(globalApiRoutePrefix);
2583
+ }
2584
+ if (configureNestServerInstance) {
2585
+ nestApp = configureNestServerInstance(nestApp) || nestApp;
2586
+ }
2587
+ return nestApp.init();
2588
+ };
2589
+ const nest = createNestServer(server).catch((err) => {
2590
+ console.error('Nest failed startup.', err);
2591
+ throw err;
2592
+ });
2593
+ nestServer = { server, nest: makeGetter(nest) };
2594
+ serversCache.set(appName, nestServer);
2595
+ }
2596
+ return nestServer;
2597
+ };
2598
+ const removeNestServer = async (firebaseApp) => {
2599
+ const appName = firebaseApp.name;
2600
+ const nestServer = serversCache.get(appName);
2601
+ let removed;
2602
+ if (nestServer) {
2603
+ removed = nestServer.nest().then((x) => {
2604
+ serversCache.delete(appName);
2605
+ return x.close().then(() => true);
2606
+ });
2607
+ }
2608
+ else {
2609
+ removed = Promise.resolve(false);
2610
+ }
2611
+ return removed;
2612
+ };
2613
+ return {
2614
+ moduleClass,
2615
+ initNestServer,
2616
+ removeNestServer
2617
+ };
2618
+ }
2619
+
2620
+ /**
2621
+ * Abstract class that wraps an INestApplicationContext value.
2622
+ */
2623
+ class AbstractNestContext {
2624
+ _nest;
2625
+ constructor(nest) {
2626
+ this._nest = nest;
2627
+ }
2628
+ get nest() {
2629
+ return this._nest;
2630
+ }
2631
+ }
2632
+ class AbstractFirebaseNestContext extends AbstractNestContext {
2633
+ /**
2634
+ * FirebasePermissionErrorContextErrorFunction to use with makeModelContext().
2635
+ *
2636
+ * Defaults to nestFirebaseForbiddenPermissionError().
2637
+ */
2638
+ makePermissionError = nestFirebaseForbiddenPermissionError;
2639
+ /**
2640
+ * FirebaseDoesNotExistErrorContextErrorFunction to use with makeModelContext().
2641
+ *
2642
+ * Defaults to nestFirebaseDoesNotExistError().
2643
+ *
2644
+ * Some configurations may prefer to use nestFirebaseForbiddenPermissionError instead, which returns a forbidden error instead.
2645
+ * This prevents the leaking of information about the existence of an object.
2646
+ */
2647
+ makeDoesNotExistError = nestFirebaseDoesNotExistError;
2648
+ get envService() {
2649
+ return this.nest.get(FirebaseServerEnvService);
2650
+ }
2651
+ get storageService() {
2652
+ return this.nest.get(FirebaseServerStorageService);
2653
+ }
2654
+ /**
2655
+ * Creates a FirebaseAppModelContext instance.
2656
+ *
2657
+ * @param auth
2658
+ * @param buildFn
2659
+ * @returns
2660
+ */
2661
+ makeModelContext(auth, buildFn) {
2662
+ const base = {
2663
+ auth: this.authService.authContextInfo(auth),
2664
+ app: this.app,
2665
+ makePermissionError: this.makePermissionError,
2666
+ makeDoesNotExistError: this.makeDoesNotExistError
2667
+ };
2668
+ return buildFn
2669
+ ? build({
2670
+ base,
2671
+ build: buildFn
2672
+ })
2673
+ : base;
2674
+ }
2675
+ /**
2676
+ * Creates a InContextFirebaseModelsService given the input context and parameters.
2677
+ *
2678
+ * @param context
2679
+ * @param buildFn
2680
+ * @returns
2681
+ */
2682
+ model(context, buildFn) {
2683
+ const firebaseModelContext = this.makeModelContext(context, buildFn);
2684
+ return inContextFirebaseModelsServiceFactory(this.firebaseModelsService)(firebaseModelContext);
2685
+ }
2686
+ async useModel(type, select) {
2687
+ const context = this.makeModelContext(select.request, select.buildFn);
2688
+ const usePromise = useFirebaseModelsService(this.firebaseModelsService, type, {
2689
+ context,
2690
+ key: select.key,
2691
+ roles: select.roles,
2692
+ rolesSetIncludes: select.rolesSetIncludes
2693
+ });
2694
+ const use = select.use ?? ((x) => x);
2695
+ return usePromise(use);
2696
+ }
2697
+ }
2698
+
2699
+ export { ALREADY_EXISTS_ERROR_CODE, AbstractFirebaseNestContext, AbstractFirebaseServerActionsContext, AbstractFirebaseServerAuthContext, AbstractFirebaseServerAuthService, AbstractFirebaseServerAuthUserContext, AbstractFirebaseServerNewUserService, AbstractNestContext, BAD_REQUEST_ERROR_CODE, CONFLICT_ERROR_CODE, ConfigureFirebaseAppCheckMiddlewareModule, ConfigureFirebaseWebhookMiddlewareModule, DEFAULT_FIREBASE_PASSWORD_NUMBER_GENERATOR, DEFAULT_SETUP_COM_THROTTLE_TIME, DefaultFirebaseServerEnvService, FIREBASE_APP_TOKEN, FIREBASE_AUTH_TOKEN, FIREBASE_FIRESTORE_CONTEXT_TOKEN, FIREBASE_FIRESTORE_TOKEN, FIREBASE_SERVER_VALIDATION_ERROR_CODE, FIREBASE_STORAGE_CONTEXT_FACTORY_CONFIG_TOKEN, FIREBASE_STORAGE_CONTEXT_TOKEN, FIREBASE_STORAGE_TOKEN, FIRESTORE_CLIENT_QUERY_CONSTRAINT_HANDLER_MAPPING, FORBIDDEN_ERROR_CODE, FirebaseAppCheckMiddleware, FirebaseNestServerRootModule, FirebaseRawBodyMiddleware, FirebaseServerAuthModule, FirebaseServerAuthNewUserSendSetupDetailsNoSetupConfigError, FirebaseServerAuthNewUserSendSetupDetailsSendOnceError, FirebaseServerAuthNewUserSendSetupDetailsThrottleError, FirebaseServerAuthService, FirebaseServerEnvService, FirebaseServerFirestoreContextModule, FirebaseServerFirestoreModule, FirebaseServerStorageContextModule, FirebaseServerStorageModule, FirebaseServerStorageService, INTERNAL_SERVER_ERROR_CODE, MODEL_NOT_AVAILABLE_ERROR_CODE, NOT_FOUND_ERROR_CODE, NO_RUN_NAME_SPECIFIED_FOR_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_CODE, NoSetupContentFirebaseServerNewUserService, PERMISSION_DENIED_ERROR_CODE, PHONE_NUMBER_ALREADY_EXISTS_ERROR_CODE, SkipAppCheck, UNAUTHENTICATED_ERROR_CODE, UNAVAILABLE_ERROR_CODE, UNAVAILABLE_OR_DEACTIVATED_FUNCTION_ERROR_CODE, UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_NAME_CODE, UNKNOWN_SCHEDULED_FUNCTION_DEVELOPMENT_FUNCTION_TYPE_CODE, _onCallWithCallTypeFunction, alreadyExistsError, appFirestoreModuleMetadata, assertContextHasAuth, assertDocumentExists, assertHasRolesInRequest, assertHasSignedTosInRequest, assertIsAdminInRequest, assertIsAdminOrTargetUserInRequestData, assertIsContextWithAuthData, assertRequestRequiresAuthForFunction, assertSnapshotData, assertSnapshotDataWithKey, badRequestError, blockingFunctionHandlerWithNestContextFactory, cloudEventHandlerWithNestContextFactory, collectionRefForPath, createModelUnknownModelTypeError, defaultFirebaseServerActionsTransformFactoryLogErrorFunction, defaultProvideFirebaseServerStorageServiceSimple, deleteModelUnknownModelTypeError, developmentUnknownSpecifierError, docRefForPath, documentModelNotAvailableError, firebaseAuthTokenFromDecodedIdToken, firebaseServerActionsContext, firebaseServerActionsTransformContext, firebaseServerActionsTransformFactory, firebaseServerAppTokenProvider, firebaseServerAuthModuleMetadata, firebaseServerDevFunctions, firebaseServerErrorInfo, firebaseServerErrorInfoCodePair, firebaseServerErrorInfoServerErrorCodePair, firebaseServerErrorInfoServerErrorPair, firebaseServerStorageDefaultBucketIdTokenProvider, firebaseServerStorageModuleMetadata, firebaseServerValidationError, firebaseServerValidationServerError, firestoreClientQueryConstraintFunctionsDriver, firestoreServerIncrementUpdateToUpdateData, forbiddenError, getAuthUserOrUndefined, googleCloudFileMetadataToStorageMetadata, googleCloudFirebaseStorageContextFactory, googleCloudFirebaseStorageDrivers, googleCloudFirestoreAccessorDriver, googleCloudFirestoreContextFactory, googleCloudFirestoreDrivers, googleCloudFirestoreQueryDriver, googleCloudStorageAccessorFile, googleCloudStorageAccessorFolder, googleCloudStorageBucketForStorageFilePath, googleCloudStorageFileForStorageFilePath, googleCloudStorageFirebaseStorageAccessorDriver, googleCloudStorageFromFirebaseAdminStorage, googleCloudStorageListFilesResultFactory, handleFirebaseAuthError, handleFirebaseError, hasAuthRolesInRequest, hasNewUserSetupPasswordInRequest, hasSignedTosInRequest, inAuthContext, injectNestApplicationContextIntoRequest, injectNestIntoRequest, internalServerError, isAdminInRequest, isAdminOrTargetUserInRequestData, isContextWithAuthData, isFirebaseError, isFirebaseHttpsError, makeBlockingFunctionWithHandler, makeOnScheduleHandlerWithNestApplicationRequest, makeScheduledFunctionDevelopmentFunction, modelNotAvailableError, nestAppHasDevelopmentSchedulerEnabled, nestAppIsProductionEnvironment, nestFirebaseDoesNotExistError, nestFirebaseForbiddenPermissionError, nestServerInstance, noRunNameSpecifiedForScheduledFunctionDevelopmentFunction, notFoundError, onCallCreateModel, onCallDeleteModel, onCallDevelopmentFunction, onCallHandlerWithNestApplicationFactory, onCallHandlerWithNestContextFactory, onCallModel, onCallModelMissingCallTypeError, onCallModelUnknownCallTypeError, onCallReadModel, onCallSpecifierHandler, onCallUpdateModel, onScheduleHandlerWithNestApplicationFactory, onScheduleHandlerWithNestContextFactory, optionalAuthContext, permissionDeniedError, phoneNumberAlreadyExistsError, preconditionConflictError, provideAppFirestoreCollections, provideFirebaseServerAuthService, provideFirebaseServerStorageService, readModelUnknownModelTypeError, setNestContextOnRequest, setNestContextOnScheduleRequest, taskQueueFunctionHandlerWithNestContextFactory, unauthenticatedContextHasNoAuthData, unauthenticatedContextHasNoUidError, unauthenticatedError, unavailableError, unavailableOrDeactivatedFunctionError, unknownModelCrudFunctionSpecifierError, unknownScheduledFunctionDevelopmentFunctionName, unknownScheduledFunctionDevelopmentFunctionType, updateModelUnknownModelTypeError, userContextFromUid, verifyAppCheckInRequest };