backend-manager 5.11.7 → 5.13.0
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/docs/ai-library.md +3 -1
- package/docs/email-system.md +4 -2
- package/docs/usage-rate-limiting.md +2 -0
- package/package.json +1 -1
- package/src/manager/functions/core/actions/api/admin/send-email.js +0 -8
- package/src/manager/helpers/usage.js +9 -2
- package/src/manager/libraries/ai/providers/test.js +15 -1
- package/src/manager/libraries/email/data/disposable-domains.json +342 -1
- package/src/manager/libraries/email/generators/lib/templates/plain.js +1 -2
- package/src/manager/libraries/email/prepare.js +3 -12
- package/src/manager/routes/user/signup/post.js +10 -28
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/metadata.json +14 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/newsletter.html +486 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/newsletter.md +41 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/newsletter.mjml +97 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/structure.json +42 -0
- package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/summary.md +1 -0
- package/src/test/fixtures/firebase-project/.temp/test-mode.json +1 -1
- package/src/test/fixtures/firebase-project/database-debug.log +8 -8
- package/src/test/fixtures/firebase-project/firestore-debug.log +61 -55
- package/src/test/fixtures/firebase-project/pubsub-debug.log +3 -3
- package/test/helpers/ai-test-provider.js +24 -0
- package/test/helpers/usage-limits.js +85 -0
package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/newsletter.mjml
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<mjml>
|
|
2
|
+
<mj-head>
|
|
3
|
+
<mj-title>Identity is the new growth lever</mj-title>
|
|
4
|
+
<mj-preview>Three platform shifts to lock in this week.</mj-preview>
|
|
5
|
+
<mj-attributes>
|
|
6
|
+
<mj-all font-family="Inter, system-ui, sans-serif" />
|
|
7
|
+
<mj-text font-size="16px" line-height="1.6" color="#1E1E2A" />
|
|
8
|
+
<mj-button background-color="#5B5BFF" color="#ffffff" border-radius="6px" font-weight="600" inner-padding="14px 24px" padding="0" />
|
|
9
|
+
<mj-section padding="0" />
|
|
10
|
+
|
|
11
|
+
</mj-attributes>
|
|
12
|
+
<mj-style>
|
|
13
|
+
h1, h2, h3 { color: #1E1E2A; margin: 0 0 12px; }
|
|
14
|
+
h2 { font-size: 22px; line-height: 1.3; }
|
|
15
|
+
a { color: #5B5BFF; }
|
|
16
|
+
p { margin: 0 0 12px; }
|
|
17
|
+
|
|
18
|
+
</mj-style>
|
|
19
|
+
</mj-head>
|
|
20
|
+
<mj-body background-color="#F6F7FB" width="600px">
|
|
21
|
+
|
|
22
|
+
<mj-section background-color="#ffffff" padding="32px 32px 16px 32px">
|
|
23
|
+
<mj-column>
|
|
24
|
+
<mj-text font-size="20px" font-weight="700" color="#5B5BFF">
|
|
25
|
+
<a href="https://example.com" style="color: #5B5BFF; text-decoration: none;">BEM Fixture</a>
|
|
26
|
+
</mj-text>
|
|
27
|
+
</mj-column>
|
|
28
|
+
</mj-section>
|
|
29
|
+
|
|
30
|
+
<mj-section background-color="#ffffff" padding="0 32px 24px 32px">
|
|
31
|
+
<mj-column>
|
|
32
|
+
<mj-text><p>Identity matters because trust is the new growth lever. Teams that handle this well will spend less time cleaning up later.</p></mj-text>
|
|
33
|
+
</mj-column>
|
|
34
|
+
</mj-section>
|
|
35
|
+
|
|
36
|
+
<mj-section background-color="#ffffff" padding="24px 32px 8px 32px">
|
|
37
|
+
<mj-column>
|
|
38
|
+
<mj-text padding="20px 0 0 0">
|
|
39
|
+
<h2>LinkedIn ships verified-profile gates for business accounts</h2>
|
|
40
|
+
<p>LinkedIn now requires verified identity attestations on any business profile claiming more than 500 followers. Accounts with documented attribution histories sail through verification in under twelve hours. The practical implication is to lock down your attribution log this week, not next.</p>
|
|
41
|
+
</mj-text>
|
|
42
|
+
</mj-column>
|
|
43
|
+
</mj-section>
|
|
44
|
+
|
|
45
|
+
<mj-section background-color="#ffffff" padding="24px 32px 8px 32px">
|
|
46
|
+
<mj-column>
|
|
47
|
+
<mj-text padding="20px 0 0 0">
|
|
48
|
+
<h2>Documentation is the new operator moat</h2>
|
|
49
|
+
<p>Operator playbooks are now the difference between an account that recovers from a flag and one that gets permanently restricted. Teams running documented processes recover in days. The ones without burn weeks negotiating with support queues.</p>
|
|
50
|
+
</mj-text>
|
|
51
|
+
</mj-column>
|
|
52
|
+
</mj-section>
|
|
53
|
+
|
|
54
|
+
<mj-section background-color="#ffffff" padding="24px 32px 8px 32px">
|
|
55
|
+
<mj-column>
|
|
56
|
+
<mj-text padding="20px 0 0 0">
|
|
57
|
+
<h2>YouTube tests creator-attribution metadata on uploads</h2>
|
|
58
|
+
<p>A subset of channels saw a new upload checkbox this week asking whether content was assisted by automation. The checkbox is optional today. Reading the room: it will not stay optional. Creators with clear internal workflows will adapt in an afternoon.</p>
|
|
59
|
+
</mj-text>
|
|
60
|
+
</mj-column>
|
|
61
|
+
</mj-section>
|
|
62
|
+
|
|
63
|
+
<mj-section background-color="#ffffff" padding="32px 32px 8px 32px">
|
|
64
|
+
<mj-column>
|
|
65
|
+
<mj-text padding="0"><div style="color: #1E1E2A;">Best,<br/>The Somiibo Team</div></mj-text>
|
|
66
|
+
</mj-column>
|
|
67
|
+
</mj-section>
|
|
68
|
+
|
|
69
|
+
<mj-section background-color="#ffffff" padding="24px 32px 24px 32px">
|
|
70
|
+
<mj-column>
|
|
71
|
+
<mj-text font-size="12px" line-height="1.5">
|
|
72
|
+
<div style="font-size: 11px; letter-spacing: 4px; text-transform: uppercase; font-weight: 700; color: #5B5BFF; margin-bottom: 12px;">Sources & data</div>
|
|
73
|
+
|
|
74
|
+
<div style="margin-bottom: 8px;">
|
|
75
|
+
<span style="font-weight: 600; color: #5B5BFF;">[1]</span>
|
|
76
|
+
<span style="color: #1E1E2A;"> LinkedIn flagged 12,000 impersonation attempts in the verified-profile beta.</span>
|
|
77
|
+
<span style="color: #888888;"> — Reported by LinkedIn product team, May 2026</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div style="margin-bottom: 8px;">
|
|
80
|
+
<span style="font-weight: 600; color: #5B5BFF;">[2]</span>
|
|
81
|
+
<span style="color: #1E1E2A;"> Operator playbook adoption up 38% week-over-week in Q2.</span>
|
|
82
|
+
<span style="color: #888888;"> — Per platform analytics, May 2026</span>
|
|
83
|
+
</div>
|
|
84
|
+
</mj-text>
|
|
85
|
+
</mj-column>
|
|
86
|
+
</mj-section>
|
|
87
|
+
|
|
88
|
+
<mj-section background-color="transparent" padding="16px 32px 32px 32px">
|
|
89
|
+
<mj-column>
|
|
90
|
+
<mj-text font-size="12px" color="#888888" align="center">
|
|
91
|
+
You're receiving this because you subscribed to <a href="https://example.com" style="color: #888888;">BEM Fixture</a>.
|
|
92
|
+
|
|
93
|
+
</mj-text>
|
|
94
|
+
</mj-column>
|
|
95
|
+
</mj-section>
|
|
96
|
+
</mj-body>
|
|
97
|
+
</mjml>
|
package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/structure.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Predefined fixture for the `clean` template. Loaded via NEWSLETTER_FIXTURE=clean. Edit freely — no AI involved. Classic content shape: intro + sections[{title, body, cta, image_prompt}].",
|
|
3
|
+
"subject": "Identity is the new growth lever",
|
|
4
|
+
"preheader": "Three platform shifts to lock in this week.",
|
|
5
|
+
"summary": "LinkedIn, YouTube, and the broader creator stack are all tightening identity controls this week. The operators with documented attribution histories will outrun the rest. Documentation is no longer overhead — it's the moat.",
|
|
6
|
+
"tags": [
|
|
7
|
+
"linkedin",
|
|
8
|
+
"youtube",
|
|
9
|
+
"platform-policy",
|
|
10
|
+
"creator-economy",
|
|
11
|
+
"operator-tools"
|
|
12
|
+
],
|
|
13
|
+
"intro": "Identity matters because trust is the new growth lever. Teams that handle this well will spend less time cleaning up later.",
|
|
14
|
+
"sections": [
|
|
15
|
+
{
|
|
16
|
+
"title": "LinkedIn ships verified-profile gates for business accounts",
|
|
17
|
+
"body": "LinkedIn now requires verified identity attestations on any business profile claiming more than 500 followers. Accounts with documented attribution histories sail through verification in under twelve hours. The practical implication is to lock down your attribution log this week, not next.",
|
|
18
|
+
"image_prompt": "Abstract geometric illustration of a verification checkmark inside a layered profile card."
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"title": "Documentation is the new operator moat",
|
|
22
|
+
"body": "Operator playbooks are now the difference between an account that recovers from a flag and one that gets permanently restricted. Teams running documented processes recover in days. The ones without burn weeks negotiating with support queues.",
|
|
23
|
+
"image_prompt": "Stack of geometric document layers casting clean shadows on a flat surface."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"title": "YouTube tests creator-attribution metadata on uploads",
|
|
27
|
+
"body": "A subset of channels saw a new upload checkbox this week asking whether content was assisted by automation. The checkbox is optional today. Reading the room: it will not stay optional. Creators with clear internal workflows will adapt in an afternoon.",
|
|
28
|
+
"image_prompt": "Minimalist play button morphing into a label tag, flat geometric style."
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"signoff": "Best,\nThe Somiibo Team",
|
|
32
|
+
"citations": [
|
|
33
|
+
{
|
|
34
|
+
"note": "LinkedIn flagged 12,000 impersonation attempts in the verified-profile beta.",
|
|
35
|
+
"source": "Reported by LinkedIn product team, May 2026"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"note": "Operator playbook adoption up 38% week-over-week in Q2.",
|
|
39
|
+
"source": "Per platform analytics, May 2026"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
package/src/test/fixtures/firebase-project/.temp/newsletter/run-2026-08-05T01-21-40/summary.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
LinkedIn, YouTube, and the broader creator stack are all tightening identity controls this week. The operators with documented attribution histories will outrun the rest. Documentation is no longer overhead — it's the moat.
|
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
18:24:05.166 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
|
|
6
|
+
18:24:05.255 [main] INFO com.firebase.server.forge.App$ - Listening at 127.0.0.1:9000
|
|
7
|
+
18:24:13.954 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO com.firebase.core.namespace.NamespaceActor - demo-backend-manager-default-rtdb successfully activated FBKV (SurveyIdle(0)) wait: 61ms, init: 0ms
|
|
8
|
+
18:24:13.981 [NamespaceSystem-blocking-namespace-operation-dispatcher-7] INFO com.firebase.core.namespace.StateManager - Namespace demo-backend-manager-default-rtdb status Active to Active
|
|
9
|
+
18:24:26.615 [Thread-0] INFO com.firebase.server.forge.App$ - Attempting graceful shutdown.
|
|
10
|
+
18:24:26.626 [NamespaceSystem-akka.actor.default-dispatcher-5] INFO com.firebase.core.namespace.Terminator$Terminator - 1 actors left to terminate: demo-backend-manager-default-rtdb
|
|
11
|
+
18:24:26.628 [NamespaceSystem-akka.actor.default-dispatcher-6] INFO com.firebase.core.namespace.NamespaceActor - stopped namespace actor for demo-backend-manager-default-rtdb
|
|
12
|
+
18:24:26.637 [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
|
-
|
|
5
|
+
Aug 04, 2026 6:24:04 PM 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,113 +20,119 @@ 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
|
-
|
|
23
|
+
Aug 04, 2026 6:24:13 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
24
24
|
INFO: Detected non-HTTP/2 connection.
|
|
25
|
-
|
|
25
|
+
Aug 04, 2026 6:24:13 PM io.grpc.netty.TcpMetrics loadEpollInfo
|
|
26
26
|
INFO: Epoll available during static init of TcpMetrics:false
|
|
27
|
-
|
|
27
|
+
Aug 04, 2026 6:24:13 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
28
28
|
INFO: Detected HTTP/2 connection.
|
|
29
|
-
|
|
29
|
+
Aug 04, 2026 6:24:13 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
30
|
+
INFO: Detected non-HTTP/2 connection.
|
|
31
|
+
Aug 04, 2026 6:24:15 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
32
|
+
INFO: Detected HTTP/2 connection.
|
|
33
|
+
Aug 04, 2026 6:24:15 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
34
|
+
INFO: Detected HTTP/2 connection.
|
|
35
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
30
36
|
INFO: Detected HTTP/2 connection.
|
|
31
|
-
|
|
37
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
32
38
|
INFO: Detected HTTP/2 connection.
|
|
33
|
-
|
|
39
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
34
40
|
INFO: Detected HTTP/2 connection.
|
|
35
|
-
|
|
41
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
36
42
|
INFO: Detected HTTP/2 connection.
|
|
37
|
-
|
|
43
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
38
44
|
INFO: Detected HTTP/2 connection.
|
|
39
|
-
|
|
45
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
40
46
|
INFO: Detected HTTP/2 connection.
|
|
41
|
-
|
|
47
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
42
48
|
INFO: Detected HTTP/2 connection.
|
|
43
|
-
|
|
49
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
44
50
|
INFO: Detected HTTP/2 connection.
|
|
45
|
-
|
|
51
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
46
52
|
INFO: Detected HTTP/2 connection.
|
|
47
|
-
|
|
53
|
+
Aug 04, 2026 6:24:24 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
48
54
|
INFO: Detected HTTP/2 connection.
|
|
49
|
-
|
|
55
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
50
56
|
INFO: Detected HTTP/2 connection.
|
|
51
|
-
|
|
57
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
52
58
|
INFO: Detected HTTP/2 connection.
|
|
53
|
-
|
|
59
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
54
60
|
INFO: Detected HTTP/2 connection.
|
|
55
|
-
|
|
61
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
56
62
|
INFO: Detected HTTP/2 connection.
|
|
57
|
-
|
|
63
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
58
64
|
INFO: Detected HTTP/2 connection.
|
|
59
|
-
|
|
65
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
60
66
|
INFO: Detected HTTP/2 connection.
|
|
61
|
-
|
|
67
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
62
68
|
INFO: Detected HTTP/2 connection.
|
|
63
|
-
|
|
69
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
64
70
|
INFO: Detected HTTP/2 connection.
|
|
65
|
-
|
|
71
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
66
72
|
INFO: Detected HTTP/2 connection.
|
|
67
|
-
|
|
73
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
68
74
|
INFO: Detected HTTP/2 connection.
|
|
69
|
-
|
|
75
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
70
76
|
INFO: Detected HTTP/2 connection.
|
|
71
|
-
|
|
77
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
72
78
|
INFO: Detected HTTP/2 connection.
|
|
73
|
-
|
|
79
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
74
80
|
INFO: Detected HTTP/2 connection.
|
|
75
|
-
|
|
81
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
76
82
|
INFO: Detected HTTP/2 connection.
|
|
77
|
-
|
|
83
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
78
84
|
INFO: Detected HTTP/2 connection.
|
|
79
|
-
|
|
85
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
80
86
|
INFO: Detected HTTP/2 connection.
|
|
81
|
-
|
|
87
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
82
88
|
INFO: Detected HTTP/2 connection.
|
|
83
|
-
|
|
89
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
84
90
|
INFO: Detected HTTP/2 connection.
|
|
85
|
-
|
|
91
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
86
92
|
INFO: Detected HTTP/2 connection.
|
|
87
|
-
|
|
93
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
88
94
|
INFO: Detected HTTP/2 connection.
|
|
89
|
-
|
|
95
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
90
96
|
INFO: Detected HTTP/2 connection.
|
|
91
|
-
|
|
97
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
92
98
|
INFO: Detected HTTP/2 connection.
|
|
93
|
-
|
|
99
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
94
100
|
INFO: Detected HTTP/2 connection.
|
|
95
|
-
|
|
101
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
96
102
|
INFO: Detected HTTP/2 connection.
|
|
97
|
-
|
|
103
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
98
104
|
INFO: Detected HTTP/2 connection.
|
|
99
|
-
|
|
105
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
100
106
|
INFO: Detected HTTP/2 connection.
|
|
101
|
-
|
|
107
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
102
108
|
INFO: Detected HTTP/2 connection.
|
|
103
|
-
|
|
109
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
104
110
|
INFO: Detected HTTP/2 connection.
|
|
105
|
-
|
|
111
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
106
112
|
INFO: Detected HTTP/2 connection.
|
|
107
|
-
|
|
113
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
108
114
|
INFO: Detected HTTP/2 connection.
|
|
109
|
-
|
|
115
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
110
116
|
INFO: Detected HTTP/2 connection.
|
|
111
|
-
|
|
117
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
112
118
|
INFO: Detected HTTP/2 connection.
|
|
113
|
-
|
|
119
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
114
120
|
INFO: Detected HTTP/2 connection.
|
|
115
|
-
|
|
121
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
116
122
|
INFO: Detected HTTP/2 connection.
|
|
117
|
-
|
|
123
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
118
124
|
INFO: Detected HTTP/2 connection.
|
|
119
|
-
|
|
125
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
120
126
|
INFO: Detected HTTP/2 connection.
|
|
121
|
-
|
|
127
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
122
128
|
INFO: Detected HTTP/2 connection.
|
|
123
|
-
|
|
129
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
124
130
|
INFO: Detected HTTP/2 connection.
|
|
125
|
-
|
|
131
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
126
132
|
INFO: Detected HTTP/2 connection.
|
|
127
|
-
|
|
133
|
+
Aug 04, 2026 6:24:25 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
128
134
|
INFO: Detected HTTP/2 connection.
|
|
129
|
-
|
|
135
|
+
Aug 04, 2026 6:24:26 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
130
136
|
INFO: Detected HTTP/2 connection.
|
|
131
137
|
*** shutting down gRPC server since JVM is shutting down
|
|
132
138
|
*** 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
|
-
|
|
3
|
+
Aug 04, 2026 6:24:08 PM 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.34/pubsub-emulator/lib/cloud-pubsub-emulator-0.8.34-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
|
-
|
|
12
|
+
Aug 04, 2026 6:24:08 PM com.google.cloud.pubsub.testing.v1.Main main
|
|
13
13
|
INFO: Server started, listening on 8085
|
|
14
|
-
|
|
14
|
+
Aug 04, 2026 6:24:13 PM 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
|
|
@@ -198,5 +198,29 @@ module.exports = {
|
|
|
198
198
|
assert.equal(String(second.content).startsWith('Echo:'), true, 'echo fallback');
|
|
199
199
|
},
|
|
200
200
|
},
|
|
201
|
+
|
|
202
|
+
// ─── Path-based messages (BEM prompt-template style) ───
|
|
203
|
+
|
|
204
|
+
{
|
|
205
|
+
name: 'reply-directive-from-path-based-message-settings',
|
|
206
|
+
async run({ assert }) {
|
|
207
|
+
// Routes idiomatically pass message: { path, settings } — the real
|
|
208
|
+
// providers render the template, so directives arrive via settings values
|
|
209
|
+
const provider = makeProvider();
|
|
210
|
+
const result = await provider.request({
|
|
211
|
+
response: 'json',
|
|
212
|
+
message: {
|
|
213
|
+
path: '/prompts/user.md',
|
|
214
|
+
settings: {
|
|
215
|
+
level: 'college',
|
|
216
|
+
message: 'What is 2+2? [[reply:{"answer":"4"}]]',
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
assert.equal(typeof result.content, 'object', 'parsed object');
|
|
222
|
+
assert.equal(result.content.answer, '4', 'directive extracted from settings values');
|
|
223
|
+
},
|
|
224
|
+
},
|
|
201
225
|
],
|
|
202
226
|
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test: Usage limit semantics (helpers/usage.js)
|
|
3
|
+
*
|
|
4
|
+
* Negative product limits (the -1 "unlimited" config convention) must never
|
|
5
|
+
* rate-limit a user. Regression: the daily-cap math turned -1 into a 0/day cap
|
|
6
|
+
* that 429'd every request from unlimited-plan users.
|
|
7
|
+
*/
|
|
8
|
+
const PRODUCT_ID = 'unlimited-limits-fixture';
|
|
9
|
+
const TEST_UID = '_test-unlimited-limits-user';
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
description: 'Usage limits (negative = unlimited)',
|
|
13
|
+
type: 'suite',
|
|
14
|
+
timeout: 15000,
|
|
15
|
+
|
|
16
|
+
tests: [
|
|
17
|
+
{
|
|
18
|
+
name: 'setup-product-and-user',
|
|
19
|
+
async run({ Manager, firestore, state, assert }) {
|
|
20
|
+
// Inject a fixture product into the real config (restored in cleanup)
|
|
21
|
+
Manager.config.payment = Manager.config.payment || {};
|
|
22
|
+
state.originalProducts = Manager.config.payment.products;
|
|
23
|
+
Manager.config.payment.products = [
|
|
24
|
+
...(state.originalProducts || []),
|
|
25
|
+
{ id: PRODUCT_ID, type: 'subscription', limits: { requests: -1 } },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Seed a user on that product with existing usage (fixture seeding —
|
|
29
|
+
// production code must always go through the usage helper)
|
|
30
|
+
await firestore.set(`users/${TEST_UID}`, {
|
|
31
|
+
subscription: { product: { id: PRODUCT_ID }, status: 'active' },
|
|
32
|
+
usage: { requests: { monthly: 12345, daily: 678, total: 99999 } },
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
assert.ok(true, 'Fixture product and user seeded');
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'negative-limit-has-no-daily-allowance',
|
|
40
|
+
async run({ Manager, state, assert }) {
|
|
41
|
+
const usage = Manager.Usage();
|
|
42
|
+
await usage.init(Manager.Assistant(), { log: false });
|
|
43
|
+
await usage.setUser(TEST_UID);
|
|
44
|
+
|
|
45
|
+
state.usage = usage;
|
|
46
|
+
|
|
47
|
+
assert.equal(usage.getLimit('requests'), -1, 'Limit resolves to -1');
|
|
48
|
+
assert.equal(usage.getDailyAllowance('requests'), null, 'Negative limits have no daily cap');
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'validate-resolves-for-negative-limit',
|
|
53
|
+
async run({ state, assert }) {
|
|
54
|
+
const result = await state.usage.validate('requests').catch((e) => e);
|
|
55
|
+
|
|
56
|
+
assert.ok(!(result instanceof Error), 'validate() must resolve for unlimited plans regardless of usage');
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'zero-limit-still-rejects',
|
|
61
|
+
async run({ Manager, firestore, assert }) {
|
|
62
|
+
// Guard the other edge: a missing/0 limit must keep rejecting
|
|
63
|
+
await firestore.set(`users/${TEST_UID}-zero`, {
|
|
64
|
+
subscription: { product: { id: 'basic' }, status: 'active' },
|
|
65
|
+
usage: { unknownmetric: { monthly: 1, daily: 1, total: 1 } },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const usage = Manager.Usage();
|
|
69
|
+
await usage.init(Manager.Assistant(), { log: false });
|
|
70
|
+
await usage.setUser(`${TEST_UID}-zero`);
|
|
71
|
+
|
|
72
|
+
const result = await usage.validate('unknownmetric').catch((e) => e);
|
|
73
|
+
|
|
74
|
+
assert.ok(result instanceof Error, 'Metrics without a configured limit must reject');
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
|
|
79
|
+
async cleanup({ Manager, state }) {
|
|
80
|
+
// Restore the real product list
|
|
81
|
+
if (Manager?.config?.payment) {
|
|
82
|
+
Manager.config.payment.products = state?.originalProducts;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
};
|