backend-manager 5.0.129 → 5.0.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -14,6 +14,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
14
14
  - `Fixed` for any bug fixes.
15
15
  - `Security` in case of vulnerabilities.
16
16
 
17
+ # [5.0.129] - 2026-03-11
18
+ ### Added
19
+ - Usage proxy system: `setUser()` to bill usage to a different user, `addMirror()`/`setMirrors()` to write usage to additional Firestore docs in parallel
20
+ - Admin post route image rewriting: `extractImages()` now returns a URL map and rewrites markdown body to use `@post/` prefix for uploaded images
21
+ - `metadata` object on user schema with `created` and `updated` timestamps
22
+ - Firestore security rules: added `metadata` to server-only write fields
23
+ - Test for admin post creation route
24
+ - CLAUDE.md and README.md documentation for usage proxy and admin post route
25
+
26
+ ### Changed
27
+ - User schema: moved `activity.lastActivity` to `metadata.updated` and `activity.created` to `metadata.created`
28
+ - `before-signin` event handler writes to `metadata.updated` instead of `activity.lastActivity`
29
+ - Admin user sync route writes to `metadata.created`/`metadata.updated` instead of `activity.created`/`activity.lastActivity`
30
+ - `Usage.update()` refactored to execute primary + mirror writes in parallel via `Promise.all()`
31
+ - Bumped version to 5.0.129
32
+
17
33
  # [5.0.123] - 2026-03-10
18
34
  ### Added
19
35
  - Dispute alert system: `POST /payments/dispute-alert` endpoint with Chargeblast processor for ingesting payment dispute webhooks
package/README.md CHANGED
@@ -630,7 +630,7 @@ await utilities.iterateUsers(
630
630
 
631
631
  // Get document with owner user
632
632
  const { document, user } = await utilities.getDocumentWithOwnerUser('posts/abc123', {
633
- owner: 'owner.uid',
633
+ owner: 'owner',
634
634
  resolve: {
635
635
  schema: 'posts',
636
636
  assistant: assistant,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.0.129",
3
+ "version": "5.0.130",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "bin": {
@@ -41,7 +41,7 @@ module.exports = async ({ Manager, assistant, change, context, libraries }) => {
41
41
 
42
42
  Manager.Analytics({
43
43
  assistant: assistant,
44
- uuid: dataBefore?.owner?.uid,
44
+ uuid: dataBefore?.owner,
45
45
  }).event('notification-unsubscribe', {});
46
46
 
47
47
  assistant.log('Notification subscription deleted:', dataBefore);
@@ -63,7 +63,7 @@ module.exports = async ({ Manager, assistant, change, context, libraries }) => {
63
63
 
64
64
  Manager.Analytics({
65
65
  assistant: assistant,
66
- uuid: dataAfter?.owner?.uid,
66
+ uuid: dataAfter?.owner,
67
67
  }).event('notification-subscribe', {});
68
68
 
69
69
  assistant.log('Notification subscription created:', dataAfter);
@@ -168,7 +168,7 @@ const META_EVENTS = {
168
168
  */
169
169
  function fireMeta({ resolved, currency, uid, processor, assistant, config }) {
170
170
  try {
171
- const pixelId = config.meta?.pixelId;
171
+ const pixelId = config.analytics?.providers?.meta?.id;
172
172
  const accessToken = process.env.META_ACCESS_TOKEN;
173
173
 
174
174
  if (!pixelId || !accessToken) {
@@ -238,7 +238,7 @@ const TIKTOK_EVENTS = {
238
238
  */
239
239
  function fireTikTok({ resolved, currency, uid, processor, assistant, config }) {
240
240
  try {
241
- const pixelCode = config.tiktok?.pixelCode;
241
+ const pixelCode = config.analytics?.providers?.tiktok?.id;
242
242
  const accessToken = process.env.TIKTOK_ACCESS_TOKEN;
243
243
 
244
244
  if (!pixelCode || !accessToken) {
@@ -50,13 +50,13 @@ Module.prototype.main = function () {
50
50
  // Save feedback to firestore
51
51
  self.libraries.admin.firestore().doc(`feedback/${docId}`)
52
52
  .set({
53
- created: assistant.meta.startTime,
54
53
  feedback: request,
55
54
  decision: decision,
56
- owner: {
57
- uid: user?.auth?.uid ?? null,
55
+ owner: user?.auth?.uid ?? null,
56
+ metadata: {
57
+ ...Manager.Metadata().set({tag: 'user:submit-feedback'}),
58
+ created: assistant.meta.startTime,
58
59
  },
59
- metadata: Manager.Metadata().set({tag: 'user:submit-feedback'}),
60
60
  }, {merge: true})
61
61
  .then(r => {
62
62
  return resolve({
@@ -161,8 +161,8 @@ function Analytics(Manager, options) {
161
161
  };
162
162
 
163
163
  // Set id and secret
164
- self.analyticsId = self?.Manager?.config?.googleAnalytics?.id;
165
- self.analyticsSecret = self?.Manager?.config?.googleAnalytics?.secret;
164
+ self.analyticsId = self?.Manager?.config?.analytics?.providers?.google?.id;
165
+ self.analyticsSecret = process.env.GOOGLE_ANALYTICS_SECRET;
166
166
 
167
167
  // Check if we have the required properties
168
168
  if (!self.analyticsId) {
@@ -272,7 +272,7 @@ Utilities.prototype.getDocumentWithOwnerUser = function (path, options) {
272
272
 
273
273
  // Set defaults
274
274
  options = options || {};
275
- options.owner = options.owner || 'owner.uid';
275
+ options.owner = options.owner || 'owner';
276
276
  options.log = typeof options.log === 'undefined' ? false : options.log;
277
277
 
278
278
  // Set resolve/schema options
@@ -10,7 +10,7 @@ module.exports = async ({ assistant, Manager }) => {
10
10
 
11
11
  /**
12
12
  * Build a public-safe config object from Manager.config
13
- * Excludes sensitive fields: sentry, googleAnalytics, ghostii, etc.
13
+ * Excludes sensitive fields: sentry, analytics, ghostii, etc.
14
14
  */
15
15
  function buildPublicConfig(config) {
16
16
  return {
@@ -46,7 +46,6 @@ module.exports = async ({ assistant, Manager, user, settings, libraries }) => {
46
46
  // Save feedback to Firestore
47
47
  await admin.firestore().doc(`feedback/${docId}`)
48
48
  .set({
49
- created: assistant.meta.startTime,
50
49
  feedback: {
51
50
  rating: settings.rating,
52
51
  like: settings.like,
@@ -54,10 +53,11 @@ module.exports = async ({ assistant, Manager, user, settings, libraries }) => {
54
53
  comments: settings.comments,
55
54
  },
56
55
  decision: decision,
57
- owner: {
58
- uid: user?.auth?.uid ?? null,
56
+ owner: user?.auth?.uid ?? null,
57
+ metadata: {
58
+ ...Manager.Metadata().set({ tag: 'user/feedback' }),
59
+ created: assistant.meta.startTime,
59
60
  },
60
- metadata: Manager.Metadata().set({ tag: 'user/feedback' }),
61
61
  }, { merge: true })
62
62
  .catch((e) => {
63
63
  return assistant.respond(`Failed to save feedback: ${e.message}`, { code: 500, sentry: true });
package/templates/_.env CHANGED
@@ -15,6 +15,11 @@ STRIPE_SECRET_KEY=""
15
15
  CHARGEBEE_API_KEY=""
16
16
  COINBASE_API_KEY=""
17
17
 
18
+ # Analytics
19
+ GOOGLE_ANALYTICS_SECRET=""
20
+ META_ACCESS_TOKEN=""
21
+ TIKTOK_ACCESS_TOKEN=""
22
+
18
23
  # Security
19
24
  CLOUDFLARE_TOKEN=""
20
25
  RECAPTCHA_SECRET_KEY=""
@@ -20,15 +20,18 @@
20
20
  sentry: {
21
21
  dsn: 'https://d965557418748jd749d837asf00552f@o777489.ingest.sentry.io/8789941',
22
22
  },
23
- googleAnalytics: {
24
- id: 'UA-123456789-1',
25
- secret: 'ABCx1234567890ABCDEFGH',
26
- },
27
- meta: {
28
- pixelId: null,
29
- },
30
- tiktok: {
31
- pixelCode: null,
23
+ analytics: {
24
+ providers: {
25
+ google: {
26
+ id: null,
27
+ },
28
+ meta: {
29
+ id: null,
30
+ },
31
+ tiktok: {
32
+ id: null,
33
+ },
34
+ },
32
35
  },
33
36
  oauth2: {},
34
37
  payment: {