backend-manager 5.11.6 → 5.12.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/usage-rate-limiting.md +2 -0
- package/package.json +1 -1
- package/src/cli/commands/serve.js +49 -2
- 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 +96 -0
- package/src/test/fixtures/firebase-project/.temp/test-mode.json +1 -1
- package/src/test/fixtures/firebase-project/database-debug.log +8 -14
- package/src/test/fixtures/firebase-project/firestore-debug.log +55 -1344
- package/src/test/fixtures/firebase-project/pubsub-debug.log +3 -5
- package/test/helpers/ai-test-provider.js +24 -0
- package/test/helpers/usage-limits.js +85 -0
|
@@ -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
|
-
Jul 03, 2026
|
|
3
|
+
Jul 03, 2026 5:56:47 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,11 +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
|
-
Jul 03, 2026
|
|
12
|
+
Jul 03, 2026 5:56:48 PM com.google.cloud.pubsub.testing.v1.Main main
|
|
13
13
|
INFO: Server started, listening on 8085
|
|
14
|
-
Jul 03, 2026
|
|
15
|
-
INFO: Detected HTTP/2 connection.
|
|
16
|
-
Jul 03, 2026 4:27:45 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
14
|
+
Jul 03, 2026 5:56:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
|
|
17
15
|
INFO: Detected HTTP/2 connection.
|
|
18
16
|
*** shutting down gRPC server since JVM is shutting down
|
|
19
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
|
+
};
|