backend-manager 5.9.20 → 5.9.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.9.20",
3
+ "version": "5.9.21",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "files": [
@@ -5,12 +5,14 @@
5
5
  * Two-stage process using SSOT segment keys from constants.js:
6
6
  *
7
7
  * Stage 1 (engagement_inactive_5m):
8
- * → Send re-engagement email via sendCampaign
8
+ * → Send re-engagement email via sendCampaign (brand-scoped internally)
9
9
  * → Excludes engagement_inactive_6m (those get pruned instead)
10
10
  *
11
11
  * Stage 2 (engagement_inactive_6m):
12
- * → Export contacts from segment, bulk delete
13
- * → Excludes subscription_paid (never prune paying customers)
12
+ * → Create brand-scoped temp segment via createBrandScopedSegment
13
+ * → Export contacts, exclude paying customers, bulk delete
14
+ * → Log deleted emails to Firestore for recoverability
15
+ * → Remove from Beehiiv (same emails)
14
16
  *
15
17
  * Segment keys are resolved to provider-specific IDs at runtime.
16
18
  * Requires marketing.prune.enabled = true in backend-manager-config.json.
@@ -19,8 +21,7 @@
19
21
  */
20
22
  const sendgridProvider = require('../../../libraries/email/providers/sendgrid.js');
21
23
 
22
- module.exports = async ({ Manager, assistant }) => {
23
- // Only run on the 1st of the month
24
+ module.exports = async ({ Manager, assistant, libraries }) => {
24
25
  if (new Date().getDate() !== 1) {
25
26
  return;
26
27
  }
@@ -30,20 +31,29 @@ module.exports = async ({ Manager, assistant }) => {
30
31
  return;
31
32
  }
32
33
 
33
- assistant.log('Marketing prune: Starting monthly prune cycle');
34
+ const brand = Manager.config?.brand;
35
+
36
+ assistant.log(`Marketing prune: Starting monthly prune cycle for ${brand?.id || 'unknown'}`);
34
37
 
35
38
  // --- Stage 1: Re-engagement email ---
36
- await stageReengage(Manager, assistant);
39
+ try {
40
+ await stageReengage(Manager, assistant);
41
+ } catch (e) {
42
+ assistant.error('Marketing prune: Stage 1 (re-engagement) failed:', e.message);
43
+ }
37
44
 
38
45
  // --- Stage 2: Delete inactive contacts ---
39
- await stagePrune(Manager, assistant);
46
+ await stagePrune(Manager, assistant, libraries);
40
47
 
41
- assistant.log('Marketing prune: Completed');
48
+ assistant.log(`Marketing prune: Completed for ${brand?.id || 'unknown'}`);
42
49
  };
43
50
 
44
51
  /**
45
52
  * Stage 1: Send re-engagement email to contacts inactive 5+ months
46
- * (excluding 6+ months — those get pruned in stage 2)
53
+ * (excluding 6+ months — those get pruned in stage 2).
54
+ *
55
+ * sendCampaign handles brand-scoping internally via _resolveAudience →
56
+ * createBrandScopedSegment, so this stage is already brand-safe.
47
57
  */
48
58
  async function stageReengage(Manager, assistant) {
49
59
  assistant.log('Marketing prune: Stage 1 — Re-engagement');
@@ -76,26 +86,51 @@ async function stageReengage(Manager, assistant) {
76
86
  }
77
87
 
78
88
  /**
79
- * Stage 2: Delete contacts inactive 6+ months.
80
- * Resolves segment IDs from SSOT keys at runtime.
81
- * Excludes paying customers.
89
+ * Stage 2: Delete contacts inactive 6+ months (brand-scoped).
90
+ *
91
+ * Uses createBrandScopedSegment to AND the engagement_inactive_6m query
92
+ * with brand_id = '<brandId>' — each brand only prunes its own contacts.
93
+ * Excludes paying customers (subscription_paid segment).
94
+ * Logs deleted emails to Firestore for recoverability.
82
95
  */
83
- async function stagePrune(Manager, assistant) {
96
+ async function stagePrune(Manager, assistant, libraries) {
84
97
  assistant.log('Marketing prune: Stage 2 — Prune');
85
98
 
86
99
  const marketing = Manager.config?.marketing || {};
100
+ const brand = Manager.config?.brand;
101
+ const { admin } = libraries;
87
102
 
88
- // --- SendGrid ---
89
- if (marketing.campaigns?.enabled !== false && process.env.SENDGRID_API_KEY) {
90
- const segmentIdMap = await sendgridProvider.resolveSegmentIds();
91
- const pruneSegmentId = segmentIdMap['engagement_inactive_6m'];
103
+ if (!brand?.id) {
104
+ assistant.error('Marketing prune: brand.id is missing aborting to prevent account-global deletion');
105
+ return;
106
+ }
92
107
 
93
- if (!pruneSegmentId) {
94
- assistant.error('Marketing prune: engagement_inactive_6m segment not found in SendGrid');
95
- return;
96
- }
108
+ if (marketing.campaigns?.enabled === false || !process.env.SENDGRID_API_KEY) {
109
+ assistant.log('Marketing prune: SendGrid not configured, skipping');
110
+ return;
111
+ }
112
+
113
+ const segmentIdMap = await sendgridProvider.resolveSegmentIds();
114
+ const pruneSegmentId = segmentIdMap['engagement_inactive_6m'];
97
115
 
98
- const exportResult = await sendgridProvider.getSegmentContacts(pruneSegmentId, 180000);
116
+ if (!pruneSegmentId) {
117
+ assistant.error('Marketing prune: engagement_inactive_6m segment not found in SendGrid');
118
+ return;
119
+ }
120
+
121
+ // Brand-scope the prune segment
122
+ const tempPrune = await sendgridProvider.createBrandScopedSegment(
123
+ [pruneSegmentId],
124
+ brand.id,
125
+ );
126
+
127
+ if (!tempPrune) {
128
+ assistant.error('Marketing prune: Failed to create brand-scoped prune segment');
129
+ return;
130
+ }
131
+
132
+ try {
133
+ const exportResult = await sendgridProvider.getSegmentContacts(tempPrune.segmentId, 180000);
99
134
 
100
135
  if (!exportResult.success) {
101
136
  assistant.error('Marketing prune: Failed to export segment:', exportResult.error);
@@ -107,9 +142,45 @@ async function stagePrune(Manager, assistant) {
107
142
  return;
108
143
  }
109
144
 
110
- assistant.log(`Marketing prune: Deleting ${exportResult.contacts.length} contacts`);
145
+ // Exclude paying customers
146
+ let contactsToPrune = exportResult.contacts;
147
+ let skippedPaid = 0;
148
+
149
+ const paidSegmentId = segmentIdMap['subscription_paid'];
150
+
151
+ if (paidSegmentId) {
152
+ const tempPaid = await sendgridProvider.createBrandScopedSegment(
153
+ [paidSegmentId],
154
+ brand.id,
155
+ );
156
+
157
+ if (tempPaid) {
158
+ try {
159
+ const paidExport = await sendgridProvider.getSegmentContacts(tempPaid.segmentId, 180000);
160
+
161
+ if (paidExport.success && paidExport.contacts.length > 0) {
162
+ const paidEmails = new Set(paidExport.contacts.map(c => c.email));
163
+ contactsToPrune = contactsToPrune.filter(c => !paidEmails.has(c.email));
164
+ skippedPaid = exportResult.contacts.length - contactsToPrune.length;
165
+ assistant.log(`Marketing prune: Excluded ${skippedPaid} paying customers`);
166
+ }
167
+ } finally {
168
+ await tempPaid.cleanup();
169
+ }
170
+ }
171
+ }
172
+
173
+ if (contactsToPrune.length === 0) {
174
+ assistant.log('Marketing prune: No contacts to prune after paid exclusion');
175
+ return;
176
+ }
177
+
178
+ const emails = contactsToPrune.map(c => c.email).filter(Boolean);
179
+
180
+ assistant.log(`Marketing prune: Deleting ${contactsToPrune.length} contacts for ${brand.id}`);
111
181
 
112
- const ids = exportResult.contacts.map(c => c.id).filter(Boolean);
182
+ // Delete from SendGrid
183
+ const ids = contactsToPrune.map(c => c.id).filter(Boolean);
113
184
  let totalDeleted = 0;
114
185
 
115
186
  for (let i = 0; i < ids.length; i += 100) {
@@ -123,18 +194,39 @@ async function stagePrune(Manager, assistant) {
123
194
  }
124
195
  }
125
196
 
126
- assistant.log(`Marketing prune: Deleted ${totalDeleted} SendGrid contacts`);
197
+ assistant.log(`Marketing prune: Deleted ${totalDeleted} SendGrid contacts for ${brand.id}`);
127
198
 
128
- // Also remove from Beehiiv (same emails)
199
+ // Remove from Beehiiv (before Firestore log — a failed log shouldn't skip BH cleanup)
129
200
  if (marketing.newsletter?.enabled !== false && process.env.BEEHIIV_API_KEY) {
130
201
  const beehiivProvider = require('../../../libraries/email/providers/beehiiv.js');
131
- const emails = exportResult.contacts.map(c => c.email).filter(Boolean);
132
202
 
133
- assistant.log(`Marketing prune: Removing ${emails.length} contacts from Beehiiv`);
203
+ assistant.log(`Marketing prune: Removing ${emails.length} contacts from Beehiiv for ${brand.id}`);
134
204
 
135
205
  await Promise.allSettled(
136
206
  emails.map(email => beehiivProvider.removeContact(email))
137
207
  );
138
208
  }
209
+
210
+ // Log to Firestore for recoverability (non-fatal — don't abort if write fails)
211
+ try {
212
+ const now = new Date();
213
+ const logKey = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
214
+
215
+ await admin.firestore()
216
+ .doc(`marketing-prune-logs/${brand.id}/runs/${logKey}`)
217
+ .set({
218
+ brandId: brand.id,
219
+ date: now.toISOString(),
220
+ count: emails.length,
221
+ emails,
222
+ skippedPaid,
223
+ });
224
+
225
+ assistant.log(`Marketing prune: Logged ${emails.length} pruned emails to Firestore (${logKey})`);
226
+ } catch (e) {
227
+ assistant.error('Marketing prune: Failed to write Firestore log:', e.message);
228
+ }
229
+ } finally {
230
+ await tempPrune.cleanup();
139
231
  }
140
232
  }
@@ -2,5 +2,5 @@
2
2
  "env": {
3
3
  "TEST_EXTENDED_MODE": ""
4
4
  },
5
- "updatedAt": "2026-06-27T09:39:36.444Z"
5
+ "updatedAt": "2026-06-27T11:14:35.153Z"
6
6
  }
@@ -2,11 +2,11 @@ WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
2
2
  WARNING: sun.misc.Unsafe::objectFieldOffset has been called by akka.util.Unsafe (file:/Users/ian/.cache/firebase/emulators/firebase-database-emulator-v4.11.2.jar)
3
3
  WARNING: Please consider reporting this to the maintainers of class akka.util.Unsafe
4
4
  WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release
5
- 02:39:43.600 [NamespaceSystem-akka.actor.default-dispatcher-5] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
6
- 02:39:43.698 [main] INFO com.firebase.server.forge.App$ - Listening at 127.0.0.1:9000
7
- 02:39:53.731 [NamespaceSystem-akka.actor.default-dispatcher-5] INFO com.firebase.core.namespace.NamespaceActor - demo-backend-manager-default-rtdb successfully activated FBKV (SurveyIdle(0)) wait: 78ms, init: 0ms
8
- 02:39:53.761 [NamespaceSystem-blocking-namespace-operation-dispatcher-7] INFO com.firebase.core.namespace.StateManager - Namespace demo-backend-manager-default-rtdb status Active to Active
9
- 02:40:05.377 [Thread-0] INFO com.firebase.server.forge.App$ - Attempting graceful shutdown.
10
- 02:40:05.385 [NamespaceSystem-akka.actor.default-dispatcher-6] INFO com.firebase.core.namespace.Terminator$Terminator - 1 actors left to terminate: demo-backend-manager-default-rtdb
11
- 02:40:05.389 [NamespaceSystem-akka.actor.default-dispatcher-8] INFO com.firebase.core.namespace.NamespaceActor - stopped namespace actor for demo-backend-manager-default-rtdb
12
- 02:40:05.392 [Thread-0] INFO com.firebase.server.forge.App$ - Graceful shutdown complete.
5
+ 04:14:42.031 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
6
+ 04:14:42.131 [main] INFO com.firebase.server.forge.App$ - Listening at 127.0.0.1:9000
7
+ 04:14:51.750 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO com.firebase.core.namespace.NamespaceActor - demo-backend-manager-default-rtdb successfully activated FBKV (SurveyIdle(0)) wait: 75ms, init: 0ms
8
+ 04:14:51.778 [NamespaceSystem-blocking-namespace-operation-dispatcher-6] INFO com.firebase.core.namespace.StateManager - Namespace demo-backend-manager-default-rtdb status Active to Active
9
+ 04:15:02.979 [Thread-0] INFO com.firebase.server.forge.App$ - Attempting graceful shutdown.
10
+ 04:15:03.025 [NamespaceSystem-akka.actor.default-dispatcher-7] INFO com.firebase.core.namespace.Terminator$Terminator - 1 actors left to terminate: demo-backend-manager-default-rtdb
11
+ 04:15:03.028 [NamespaceSystem-akka.actor.default-dispatcher-5] INFO com.firebase.core.namespace.NamespaceActor - stopped namespace actor for demo-backend-manager-default-rtdb
12
+ 04:15:03.034 [Thread-0] INFO com.firebase.server.forge.App$ - Graceful shutdown complete.
@@ -2,7 +2,7 @@ WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
2
2
  WARNING: sun.misc.Unsafe::allocateMemory has been called by io.netty.util.internal.PlatformDependent0$2 (file:/Users/ian/.cache/firebase/emulators/cloud-firestore-emulator-v1.21.0.jar)
3
3
  WARNING: Please consider reporting this to the maintainers of class io.netty.util.internal.PlatformDependent0$2
4
4
  WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
5
- Jun 27, 2026 2:39:42 AM com.google.cloud.datastore.emulator.firestore.websocket.WebSocketServer start
5
+ Jun 27, 2026 4:14:40 AM com.google.cloud.datastore.emulator.firestore.websocket.WebSocketServer start
6
6
  INFO: Started WebSocket server on ws://127.0.0.1:9150
7
7
 
8
8
  API endpoint: http://127.0.0.1:8080
@@ -20,117 +20,105 @@ If you are running a Firestore in Datastore Mode project, run:
20
20
  Note: Support for Datastore Mode is in preview. If you encounter any bugs please file at https://github.com/firebase/firebase-tools/issues.
21
21
  Dev App Server is now running.
22
22
 
23
- Jun 27, 2026 2:39:53 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
23
+ Jun 27, 2026 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
24
24
  INFO: Detected non-HTTP/2 connection.
25
- Jun 27, 2026 2:39:53 AM io.grpc.netty.TcpMetrics loadEpollInfo
25
+ Jun 27, 2026 4:14:51 AM io.grpc.netty.TcpMetrics loadEpollInfo
26
26
  INFO: Epoll available during static init of TcpMetrics:false
27
- Jun 27, 2026 2:39:53 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
27
+ Jun 27, 2026 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
28
28
  INFO: Detected HTTP/2 connection.
29
- Jun 27, 2026 2:39:55 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
29
+ Jun 27, 2026 4:14:52 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
30
30
  INFO: Detected HTTP/2 connection.
31
- Jun 27, 2026 2:39:55 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
31
+ Jun 27, 2026 4:14:53 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
32
32
  INFO: Detected HTTP/2 connection.
33
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
33
+ Jun 27, 2026 4:15:00 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
34
34
  INFO: Detected HTTP/2 connection.
35
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
35
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
36
36
  INFO: Detected HTTP/2 connection.
37
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
37
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
38
38
  INFO: Detected HTTP/2 connection.
39
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
39
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
40
40
  INFO: Detected HTTP/2 connection.
41
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
41
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
42
42
  INFO: Detected HTTP/2 connection.
43
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
43
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
44
44
  INFO: Detected HTTP/2 connection.
45
- Jun 27, 2026 2:40:03 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
45
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
46
46
  INFO: Detected HTTP/2 connection.
47
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
47
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
48
48
  INFO: Detected HTTP/2 connection.
49
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
49
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
50
50
  INFO: Detected HTTP/2 connection.
51
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
51
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
52
52
  INFO: Detected HTTP/2 connection.
53
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
53
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
54
54
  INFO: Detected HTTP/2 connection.
55
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
55
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
56
56
  INFO: Detected HTTP/2 connection.
57
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
57
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
58
58
  INFO: Detected HTTP/2 connection.
59
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
59
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
60
60
  INFO: Detected HTTP/2 connection.
61
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
61
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
62
62
  INFO: Detected HTTP/2 connection.
63
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
63
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
64
64
  INFO: Detected HTTP/2 connection.
65
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
65
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
66
66
  INFO: Detected HTTP/2 connection.
67
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
67
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
68
68
  INFO: Detected HTTP/2 connection.
69
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
69
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
70
70
  INFO: Detected HTTP/2 connection.
71
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
71
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
72
72
  INFO: Detected HTTP/2 connection.
73
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
73
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
74
74
  INFO: Detected HTTP/2 connection.
75
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
75
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
76
76
  INFO: Detected HTTP/2 connection.
77
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
77
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
78
78
  INFO: Detected HTTP/2 connection.
79
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
79
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
80
80
  INFO: Detected HTTP/2 connection.
81
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
81
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
82
82
  INFO: Detected HTTP/2 connection.
83
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
83
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
84
84
  INFO: Detected HTTP/2 connection.
85
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
85
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
86
86
  INFO: Detected HTTP/2 connection.
87
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
87
+ Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
88
88
  INFO: Detected HTTP/2 connection.
89
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
89
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
90
90
  INFO: Detected HTTP/2 connection.
91
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
91
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
92
92
  INFO: Detected HTTP/2 connection.
93
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
93
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
94
94
  INFO: Detected HTTP/2 connection.
95
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
95
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
96
96
  INFO: Detected HTTP/2 connection.
97
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
97
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
98
98
  INFO: Detected HTTP/2 connection.
99
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
99
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
100
100
  INFO: Detected HTTP/2 connection.
101
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
101
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
102
102
  INFO: Detected HTTP/2 connection.
103
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
103
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
104
104
  INFO: Detected HTTP/2 connection.
105
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
105
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
106
106
  INFO: Detected HTTP/2 connection.
107
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
107
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
108
108
  INFO: Detected HTTP/2 connection.
109
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
109
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
110
110
  INFO: Detected HTTP/2 connection.
111
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
111
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
112
112
  INFO: Detected HTTP/2 connection.
113
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
113
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
114
114
  INFO: Detected HTTP/2 connection.
115
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
115
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
116
116
  INFO: Detected HTTP/2 connection.
117
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
117
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
118
118
  INFO: Detected HTTP/2 connection.
119
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
119
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
120
120
  INFO: Detected HTTP/2 connection.
121
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
122
- INFO: Detected HTTP/2 connection.
123
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
124
- INFO: Detected HTTP/2 connection.
125
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
126
- INFO: Detected HTTP/2 connection.
127
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
128
- INFO: Detected HTTP/2 connection.
129
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
130
- INFO: Detected HTTP/2 connection.
131
- Jun 27, 2026 2:40:04 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
132
- INFO: Detected HTTP/2 connection.
133
- Jun 27, 2026 2:40:05 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
121
+ Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
134
122
  INFO: Detected HTTP/2 connection.
135
123
  *** shutting down gRPC server since JVM is shutting down
136
124
  *** server shut down
@@ -1,6 +1,6 @@
1
1
  This is the Google Pub/Sub fake.
2
2
  Implementation may be incomplete or differ from the real system.
3
- Jun 27, 2026 2:39:46 AM com.google.cloud.pubsub.testing.v1.Main main
3
+ Jun 27, 2026 4:14:45 AM com.google.cloud.pubsub.testing.v1.Main main
4
4
  INFO: IAM integration is disabled. IAM policy methods and ACL checks are not supported
5
5
  SLF4J(W): No SLF4J providers were found.
6
6
  SLF4J(W): Defaulting to no-operation (NOP) logger implementation
@@ -9,9 +9,9 @@ WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
9
9
  WARNING: sun.misc.Unsafe::allocateMemory has been called by io.netty.util.internal.PlatformDependent0$2 (file:/Users/ian/.cache/firebase/emulators/pubsub-emulator-0.8.33/pubsub-emulator/lib/cloud-pubsub-emulator-0.8.33-all.jar)
10
10
  WARNING: Please consider reporting this to the maintainers of class io.netty.util.internal.PlatformDependent0$2
11
11
  WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
12
- Jun 27, 2026 2:39:47 AM com.google.cloud.pubsub.testing.v1.Main main
12
+ Jun 27, 2026 4:14:45 AM com.google.cloud.pubsub.testing.v1.Main main
13
13
  INFO: Server started, listening on 8085
14
- Jun 27, 2026 2:39:53 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
14
+ Jun 27, 2026 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
15
15
  INFO: Detected HTTP/2 connection.
16
16
  *** shutting down gRPC server since JVM is shutting down
17
17
  *** server shut down