backend-manager 5.9.21 → 5.9.23

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.
@@ -231,6 +231,8 @@ npx mgr test user/ admin/ # Multiple paths
231
231
 
232
232
  Use `bem:` or `project:` prefix to filter by source. **Mirror the source path so a test reads like what it tests.** Route tests live under `test/routes/<route-path>/<concern>.js`, mirroring `functions/routes/<route-path>/` — e.g. `functions/routes/write/article/` → `test/routes/write/article/generate.js`, `functions/routes/sponsorship/post.js` → `test/routes/sponsorship/post.js`. Split each route into **one file per concern** under its mirrored dir (`test/routes/sponsorship/post.js`, `.../manual-validation.js`), never one giant `test/test.js`. The runner discovers files by directory, so the split also drives the `project:<path>` filter: `npx mgr test project:routes/write` runs a whole route's tests, `project:routes/write/markdown` runs one concern.
233
233
 
234
+ **The underscore convention:** `_`-prefixed files and directories at any depth under `test/` are excluded from suite discovery. Put shared helpers, fixture data, and non-test support files in `_`-prefixed paths — e.g. `test/_fixtures/`, `test/_helpers/`, `test/routes/_shared-utils.js`. The runner still specifically loads `test/_init.js` as the lifecycle hook. Matches the same convention in EM/BXM/UJM.
235
+
234
236
  ## Test Types
235
237
 
236
238
  > **The runner reads each file's `module.exports` object — it does NOT inject Mocha/Jest globals.** A test file that calls `describe`/`it`/`before`/`beforeEach`/`after` at top level throws `ReferenceError: beforeEach is not defined` and shows as `Failed to load`. There is no global `assert` either — use the `assert` passed into `run({ assert })`. Every test file MUST export one of the shapes below.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.9.21",
3
+ "version": "5.9.23",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "files": [
@@ -390,8 +390,8 @@ OpenAI.prototype.request = function (options) {
390
390
  // Custom options
391
391
  options.dedupeConsecutiveRoles = typeof options.dedupeConsecutiveRoles === 'undefined' ? true : options.dedupeConsecutiveRoles;
392
392
 
393
- // Format schema
394
- options.schema = options.schema || undefined;
393
+ // Format schema — accept inline object or { path: '...' } to load from a JSON file
394
+ options.schema = resolveSchema(options.schema, _log);
395
395
 
396
396
  // Reasons
397
397
  options.reasoning = options.reasoning || undefined;
@@ -658,6 +658,33 @@ function normalizePrompt(input) {
658
658
  });
659
659
  }
660
660
 
661
+ function resolveSchema(schema, _log) {
662
+ if (!schema) {
663
+ return undefined;
664
+ }
665
+
666
+ // Already an inline schema object (has "type" or "properties")
667
+ if (!schema.path) {
668
+ return schema;
669
+ }
670
+
671
+ const filePath = schema.path;
672
+ const exists = jetpack.exists(filePath);
673
+
674
+ _log('Reading schema from path:', filePath);
675
+
676
+ if (!exists) {
677
+ throw new Error(`Schema path ${filePath} not found`);
678
+ }
679
+
680
+ if (exists === 'dir') {
681
+ throw new Error(`Schema path ${filePath} is a directory`);
682
+ }
683
+
684
+ const raw = jetpack.read(filePath);
685
+ return JSON5.parse(raw);
686
+ }
687
+
661
688
  function loadContent(input, _log) {
662
689
  // console.log('*** input!!!', input.content.slice(0, 50), input.path);
663
690
  // console.log('*** input.content', input.content.slice(0, 50));
@@ -1321,5 +1348,6 @@ module.exports._internals = {
1321
1348
  formatMessages,
1322
1349
  normalizeToolEntry,
1323
1350
  normalizeToolChoice,
1351
+ resolveSchema,
1324
1352
  VALID_PROMPT_ROLES,
1325
1353
  };
@@ -255,6 +255,7 @@
255
255
  "5tb.in",
256
256
  "5x25.com",
257
257
  "5y.loseyourip.com",
258
+ "5yaochu.top",
258
259
  "5ymail.com",
259
260
  "60minutemail.com",
260
261
  "628868.xyz",
@@ -604,6 +605,7 @@
604
605
  "aminating.com",
605
606
  "amiri.net",
606
607
  "amiriindustries.com",
608
+ "amiyiy.xyz",
607
609
  "amplewe.us",
608
610
  "amplifiedwe.us",
609
611
  "amplifywe.us",
@@ -955,6 +957,7 @@
955
957
  "bbmailku.com",
956
958
  "bboys.fr.nf",
957
959
  "bbroot.com",
960
+ "bbwg.one",
958
961
  "bcaoo.com",
959
962
  "bcast.ws",
960
963
  "bcb.ro",
@@ -1104,6 +1107,7 @@
1104
1107
  "borged.net",
1105
1108
  "borged.org",
1106
1109
  "bosakun.com",
1110
+ "boscharena.dev",
1107
1111
  "bot.cd",
1108
1112
  "bot.nu",
1109
1113
  "botasky.eu.cc",
@@ -1249,6 +1253,7 @@
1249
1253
  "candymail.de",
1250
1254
  "cane.pw",
1251
1255
  "canfga.org",
1256
+ "cangcud.com",
1252
1257
  "cangcutku.pro",
1253
1258
  "cantozil.com",
1254
1259
  "canvect.com",
@@ -1289,6 +1294,7 @@
1289
1294
  "cbasosbr.top",
1290
1295
  "cbdol.mx",
1291
1296
  "cbes.net",
1297
+ "cbsbada.com",
1292
1298
  "cbty.ru",
1293
1299
  "cbty.store",
1294
1300
  "cbvl.co.uk",
@@ -2057,6 +2063,7 @@
2057
2063
  "egg5233.com",
2058
2064
  "egg5233.one",
2059
2065
  "eggbanjos.org",
2066
+ "eggso.click",
2060
2067
  "eggur.com",
2061
2068
  "egirl.help",
2062
2069
  "egvoo.com",
@@ -2369,6 +2376,8 @@
2369
2376
  "fanclub.pm",
2370
2377
  "fandoe.com",
2371
2378
  "fangoh.com",
2379
+ "fangxiaobai.us.ci",
2380
+ "fangxiaobai1.us.ci",
2372
2381
  "fanicle.com",
2373
2382
  "fansworldwide.de",
2374
2383
  "fantastu.com",
@@ -2477,6 +2486,7 @@
2477
2486
  "firstaidtrainingschool.co.uk",
2478
2487
  "firstlawyer.org",
2479
2488
  "fisdom.vip",
2489
+ "fitbloomlab.com",
2480
2490
  "fitnesrezink.ru",
2481
2491
  "fivemail.de",
2482
2492
  "fivermail.com",
@@ -2487,6 +2497,7 @@
2487
2497
  "flaimenet.ir",
2488
2498
  "flameoflovedegree.com",
2489
2499
  "flashemail.site",
2500
+ "flatimostore.cloud",
2490
2501
  "flavourity.com",
2491
2502
  "flayeraaron.eu.cc",
2492
2503
  "flayerhu.eu.cc",
@@ -2520,6 +2531,7 @@
2520
2531
  "footard.com",
2521
2532
  "foothilltoy.site",
2522
2533
  "for4u.net",
2534
+ "forapps.space",
2523
2535
  "foreastate.com",
2524
2536
  "forecastertests.com",
2525
2537
  "foreskin.cf",
@@ -2746,6 +2758,7 @@
2746
2758
  "geteit.com",
2747
2759
  "getfun.men",
2748
2760
  "getgptcode.com",
2761
+ "getmail.my.id",
2749
2762
  "getmail1.com",
2750
2763
  "getmailfree.cc",
2751
2764
  "getmails.eu",
@@ -3159,11 +3172,13 @@
3159
3172
  "herpderp.nl",
3160
3173
  "hertz.ltd",
3161
3174
  "hesoyam.shop",
3175
+ "hethongtudong.store",
3162
3176
  "hetzez.com",
3163
3177
  "heycmm.cn",
3164
3178
  "hezll.com",
3165
3179
  "hfogzua.top",
3166
3180
  "hh7f.com",
3181
+ "hhan.top",
3167
3182
  "hhe.org.uk",
3168
3183
  "hhyru.us",
3169
3184
  "hi2.in",
@@ -3553,6 +3568,7 @@
3553
3568
  "ixx.io",
3554
3569
  "iya.fr.nf",
3555
3570
  "iysqv.com",
3571
+ "izhowto.com",
3556
3572
  "izunasan.my.id",
3557
3573
  "izunasuite.biz.id",
3558
3574
  "j-p.us",
@@ -3788,6 +3804,7 @@
3788
3804
  "kisoq.com",
3789
3805
  "kissgy.com",
3790
3806
  "kisstwink.com",
3807
+ "kitap.az",
3791
3808
  "kitnastar.com",
3792
3809
  "kiwkiw.shop",
3793
3810
  "kjkszpjcompany.com",
@@ -4410,6 +4427,7 @@
4410
4427
  "maswae.world",
4411
4428
  "matamuasu.ga",
4412
4429
  "matchpol.net",
4430
+ "matjoa.com",
4413
4431
  "matmayer.com",
4414
4432
  "matra.site",
4415
4433
  "max-mail.org",
@@ -5475,6 +5493,7 @@
5475
5493
  "pozima.rest",
5476
5494
  "pp-n6.top",
5477
5495
  "pp7rvv.com",
5496
+ "ppdf.cc",
5478
5497
  "ppedu.pp.ua",
5479
5498
  "ppetw.com",
5480
5499
  "ppoo.ccwu.cc",
@@ -5496,6 +5515,7 @@
5496
5515
  "premigu.co",
5497
5516
  "premirum.shop",
5498
5517
  "premium-mail.fr",
5518
+ "premiumonebd.store",
5499
5519
  "premsy.net",
5500
5520
  "prestige-leadership.org",
5501
5521
  "prestore.space",
@@ -5740,6 +5760,7 @@
5740
5760
  "reusable.email",
5741
5761
  "reusecomputers.site",
5742
5762
  "reverendneedham.co.uk",
5763
+ "reviewfood.vn",
5743
5764
  "revolvingdoorhoax.org",
5744
5765
  "rexabot.com",
5745
5766
  "rexmoo.ccwu.cc",
@@ -5748,6 +5769,7 @@
5748
5769
  "rezato.com",
5749
5770
  "rf.gd",
5750
5771
  "rfc822.org",
5772
+ "rfods.tech",
5751
5773
  "rfzpnrbpv.top",
5752
5774
  "rgbeastcomputers.site",
5753
5775
  "rhalmshouse.church",
@@ -5998,6 +6020,7 @@
5998
6020
  "shieldedmail.com",
5999
6021
  "shieldemail.com",
6000
6022
  "shiftmail.com",
6023
+ "shiita12.com",
6001
6024
  "shipfromto.com",
6002
6025
  "shiphazmat.org",
6003
6026
  "shipping-regulations.com",
@@ -6708,6 +6731,7 @@
6708
6731
  "tidaksuka.cfd",
6709
6732
  "tidewick.org",
6710
6733
  "tidissajiiu.com",
6734
+ "tidylifehub.com",
6711
6735
  "tiendadezapasok.com",
6712
6736
  "tiffincrane.com",
6713
6737
  "tigrisstem.org",
@@ -6995,6 +7019,7 @@
6995
7019
  "ultralux.io.vn",
6996
7020
  "ultravex.cfd",
6997
7021
  "ultraz1.io.vn",
7022
+ "ultrmigos.online",
6998
7023
  "uma3.be",
6999
7024
  "umail.net",
7000
7025
  "umil.net",
@@ -7505,6 +7530,7 @@
7505
7530
  "xdnss.cc",
7506
7531
  "xdpxdp.online",
7507
7532
  "xehop.org",
7533
+ "xelio.sbs",
7508
7534
  "xelu.space",
7509
7535
  "xemaps.com",
7510
7536
  "xemne.com",
@@ -7585,6 +7611,7 @@
7585
7611
  "yaloo.fr.nf",
7586
7612
  "yamail.win",
7587
7613
  "yanet.me",
7614
+ "yangzhai.xyz",
7588
7615
  "yannmail.win",
7589
7616
  "yanxuan.eu.cc",
7590
7617
  "yapped.net",
@@ -2,5 +2,5 @@
2
2
  "env": {
3
3
  "TEST_EXTENDED_MODE": ""
4
4
  },
5
- "updatedAt": "2026-06-27T11:14:35.153Z"
5
+ "updatedAt": "2026-06-30T01:53:26.779Z"
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
- 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.
5
+ 18:53:34.244 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started
6
+ 18:53:34.346 [main] INFO com.firebase.server.forge.App$ - Listening at 127.0.0.1:9000
7
+ 18:53:44.206 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO com.firebase.core.namespace.NamespaceActor - demo-backend-manager-default-rtdb successfully activated FBKV (SurveyIdle(0)) wait: 74ms, init: 0ms
8
+ 18:53:44.243 [NamespaceSystem-blocking-namespace-operation-dispatcher-6] INFO com.firebase.core.namespace.StateManager - Namespace demo-backend-manager-default-rtdb status Active to Active
9
+ 18:53:55.860 [Thread-0] INFO com.firebase.server.forge.App$ - Attempting graceful shutdown.
10
+ 18:53:55.865 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO com.firebase.core.namespace.Terminator$Terminator - 1 actors left to terminate: demo-backend-manager-default-rtdb
11
+ 18:53:55.869 [NamespaceSystem-akka.actor.default-dispatcher-4] INFO com.firebase.core.namespace.NamespaceActor - stopped namespace actor for demo-backend-manager-default-rtdb
12
+ 18:53:55.872 [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 4:14:40 AM com.google.cloud.datastore.emulator.firestore.websocket.WebSocketServer start
5
+ Jun 29, 2026 6:53:32 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,105 +20,95 @@ 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 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
23
+ Jun 29, 2026 6:53:43 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
24
24
  INFO: Detected non-HTTP/2 connection.
25
- Jun 27, 2026 4:14:51 AM io.grpc.netty.TcpMetrics loadEpollInfo
25
+ Jun 29, 2026 6:53:43 PM io.grpc.netty.TcpMetrics loadEpollInfo
26
26
  INFO: Epoll available during static init of TcpMetrics:false
27
- Jun 27, 2026 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
27
+ Jun 29, 2026 6:53:43 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
28
28
  INFO: Detected HTTP/2 connection.
29
- Jun 27, 2026 4:14:52 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
29
+ Jun 29, 2026 6:53:45 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
30
30
  INFO: Detected HTTP/2 connection.
31
- Jun 27, 2026 4:14:53 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
31
+ Jun 29, 2026 6:53:45 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
32
32
  INFO: Detected HTTP/2 connection.
33
- Jun 27, 2026 4:15:00 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
33
+ Jun 29, 2026 6:53:53 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
34
34
  INFO: Detected HTTP/2 connection.
35
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
35
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
36
36
  INFO: Detected HTTP/2 connection.
37
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
37
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
38
38
  INFO: Detected HTTP/2 connection.
39
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
39
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
40
40
  INFO: Detected HTTP/2 connection.
41
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
41
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
42
42
  INFO: Detected HTTP/2 connection.
43
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
43
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
44
44
  INFO: Detected HTTP/2 connection.
45
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
45
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
46
46
  INFO: Detected HTTP/2 connection.
47
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
47
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
48
48
  INFO: Detected HTTP/2 connection.
49
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
49
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
50
50
  INFO: Detected HTTP/2 connection.
51
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
51
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
52
52
  INFO: Detected HTTP/2 connection.
53
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
53
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
54
54
  INFO: Detected HTTP/2 connection.
55
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
55
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
56
56
  INFO: Detected HTTP/2 connection.
57
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
57
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
58
58
  INFO: Detected HTTP/2 connection.
59
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
59
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
60
60
  INFO: Detected HTTP/2 connection.
61
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
61
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
62
62
  INFO: Detected HTTP/2 connection.
63
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
63
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
64
64
  INFO: Detected HTTP/2 connection.
65
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
65
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
66
66
  INFO: Detected HTTP/2 connection.
67
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
67
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
68
68
  INFO: Detected HTTP/2 connection.
69
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
69
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
70
70
  INFO: Detected HTTP/2 connection.
71
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
71
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
72
72
  INFO: Detected HTTP/2 connection.
73
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
73
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
74
74
  INFO: Detected HTTP/2 connection.
75
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
75
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
76
76
  INFO: Detected HTTP/2 connection.
77
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
77
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
78
78
  INFO: Detected HTTP/2 connection.
79
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
79
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
80
80
  INFO: Detected HTTP/2 connection.
81
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
81
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
82
82
  INFO: Detected HTTP/2 connection.
83
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
83
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
84
84
  INFO: Detected HTTP/2 connection.
85
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
85
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
86
86
  INFO: Detected HTTP/2 connection.
87
- Jun 27, 2026 4:15:01 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
87
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
88
88
  INFO: Detected HTTP/2 connection.
89
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
89
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
90
90
  INFO: Detected HTTP/2 connection.
91
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
91
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
92
92
  INFO: Detected HTTP/2 connection.
93
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
93
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
94
94
  INFO: Detected HTTP/2 connection.
95
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
95
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
96
96
  INFO: Detected HTTP/2 connection.
97
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
97
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
98
98
  INFO: Detected HTTP/2 connection.
99
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
99
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
100
100
  INFO: Detected HTTP/2 connection.
101
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
101
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
102
102
  INFO: Detected HTTP/2 connection.
103
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
103
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
104
104
  INFO: Detected HTTP/2 connection.
105
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
105
+ Jun 29, 2026 6:53:54 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
106
106
  INFO: Detected HTTP/2 connection.
107
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
107
+ Jun 29, 2026 6:53:55 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
108
108
  INFO: Detected HTTP/2 connection.
109
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
109
+ Jun 29, 2026 6:53:55 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
110
110
  INFO: Detected HTTP/2 connection.
111
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
112
- INFO: Detected HTTP/2 connection.
113
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
114
- INFO: Detected HTTP/2 connection.
115
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
116
- INFO: Detected HTTP/2 connection.
117
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
118
- INFO: Detected HTTP/2 connection.
119
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
120
- INFO: Detected HTTP/2 connection.
121
- Jun 27, 2026 4:15:02 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
111
+ Jun 29, 2026 6:53:55 PM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
122
112
  INFO: Detected HTTP/2 connection.
123
113
  *** shutting down gRPC server since JVM is shutting down
124
114
  *** 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 4:14:45 AM com.google.cloud.pubsub.testing.v1.Main main
3
+ Jun 29, 2026 6:53:37 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.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 4:14:45 AM com.google.cloud.pubsub.testing.v1.Main main
12
+ Jun 29, 2026 6:53:37 PM com.google.cloud.pubsub.testing.v1.Main main
13
13
  INFO: Server started, listening on 8085
14
- Jun 27, 2026 4:14:51 AM io.gapi.emulators.netty.HttpVersionRoutingHandler channelRead
14
+ Jun 29, 2026 6:53:43 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
@@ -464,13 +464,9 @@ class TestRunner {
464
464
  const items = jetpack.list(dir) || [];
465
465
 
466
466
  for (const item of items) {
467
- // Skip _legacy directory
468
- if (item === '_legacy') {
469
- continue;
470
- }
471
-
472
- // Skip the _init.js lifecycle hook — it's run by setupAccounts(), not as a test.
473
- if (item === '_init.js') {
467
+ // Skip _-prefixed files and directories (fixtures, helpers, internal data).
468
+ // Matches EM/BXM/UJM convention — `test/_fixtures/`, `test/_helpers/`, etc.
469
+ if (item.startsWith('_')) {
474
470
  continue;
475
471
  }
476
472
 
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Test: AI schema resolution (libraries/ai/providers/openai.js)
3
+ *
4
+ * Verifies resolveSchema() — loading JSON Schema from inline objects or file paths.
5
+ */
6
+ const path = require('path');
7
+ const jetpack = require('fs-jetpack');
8
+ const OpenAI = require('../../src/manager/libraries/ai/providers/openai.js');
9
+ const { resolveSchema } = OpenAI._internals;
10
+
11
+ function noopLog() {}
12
+
13
+ const FIXTURES_DIR = path.join(__dirname, '..', 'fixtures', 'ai-schema');
14
+ const VALID_SCHEMA_PATH = path.join(FIXTURES_DIR, 'valid.json');
15
+ const VALID_SCHEMA = {
16
+ type: 'object',
17
+ properties: {
18
+ name: { type: 'string', description: 'The name' },
19
+ tags: { type: 'array', items: { type: 'string' } },
20
+ },
21
+ required: ['name', 'tags'],
22
+ additionalProperties: false,
23
+ };
24
+
25
+ module.exports = {
26
+ description: 'AI schema resolution (inline vs file path)',
27
+ type: 'group',
28
+
29
+ before() {
30
+ jetpack.dir(FIXTURES_DIR);
31
+ jetpack.write(VALID_SCHEMA_PATH, VALID_SCHEMA);
32
+ jetpack.write(path.join(FIXTURES_DIR, 'invalid.json'), '{ not valid json !!!');
33
+ },
34
+
35
+ after() {
36
+ jetpack.remove(FIXTURES_DIR);
37
+ },
38
+
39
+ tests: [
40
+ {
41
+ name: 'undefined-returns-undefined',
42
+ async run({ assert }) {
43
+ assert.equal(resolveSchema(undefined, noopLog), undefined, 'undefined → undefined');
44
+ },
45
+ },
46
+
47
+ {
48
+ name: 'null-returns-undefined',
49
+ async run({ assert }) {
50
+ assert.equal(resolveSchema(null, noopLog), undefined, 'null → undefined');
51
+ },
52
+ },
53
+
54
+ {
55
+ name: 'false-returns-undefined',
56
+ async run({ assert }) {
57
+ assert.equal(resolveSchema(false, noopLog), undefined, 'false → undefined');
58
+ },
59
+ },
60
+
61
+ {
62
+ name: 'inline-object-returned-as-is',
63
+ async run({ assert }) {
64
+ const inline = { type: 'object', properties: { x: { type: 'string' } } };
65
+ const result = resolveSchema(inline, noopLog);
66
+ assert.deepEqual(result, inline, 'inline schema passed through unchanged');
67
+ },
68
+ },
69
+
70
+ {
71
+ name: 'path-loads-json-file',
72
+ async run({ assert }) {
73
+ const result = resolveSchema({ path: VALID_SCHEMA_PATH }, noopLog);
74
+ assert.deepEqual(result, VALID_SCHEMA, 'loaded schema matches fixture');
75
+ },
76
+ },
77
+
78
+ {
79
+ name: 'path-not-found-throws',
80
+ async run({ assert }) {
81
+ let threw = false;
82
+ try {
83
+ resolveSchema({ path: '/nonexistent/schema.json' }, noopLog);
84
+ } catch (e) {
85
+ threw = true;
86
+ assert.equal(e.message.includes('not found'), true, 'error mentions not found');
87
+ }
88
+ assert.equal(threw, true, 'should throw on missing file');
89
+ },
90
+ },
91
+
92
+ {
93
+ name: 'path-to-directory-throws',
94
+ async run({ assert }) {
95
+ let threw = false;
96
+ try {
97
+ resolveSchema({ path: FIXTURES_DIR }, noopLog);
98
+ } catch (e) {
99
+ threw = true;
100
+ assert.equal(e.message.includes('is a directory'), true, 'error mentions directory');
101
+ }
102
+ assert.equal(threw, true, 'should throw on directory path');
103
+ },
104
+ },
105
+
106
+ {
107
+ name: 'invalid-json-throws',
108
+ async run({ assert }) {
109
+ let threw = false;
110
+ try {
111
+ resolveSchema({ path: path.join(FIXTURES_DIR, 'invalid.json') }, noopLog);
112
+ } catch (e) {
113
+ threw = true;
114
+ }
115
+ assert.equal(threw, true, 'should throw on invalid JSON');
116
+ },
117
+ },
118
+ ],
119
+ };