@jeffusion/bungee-core 5.20.0 → 5.21.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.
Files changed (41) hide show
  1. package/dist/config-worker/private-transport.d.ts +2 -0
  2. package/dist/data-admission/errors.d.ts +6 -1
  3. package/dist/gateway/contracts.d.ts +15 -4
  4. package/dist/gateway/forward-plugin.d.ts +2 -0
  5. package/dist/gateway/plugin.js +12 -2
  6. package/dist/gateway/request-plugin.d.ts +6 -0
  7. package/dist/gateway/responses-websocket-session.d.ts +18 -0
  8. package/dist/gateway/runtime.d.ts +1 -0
  9. package/dist/gateway/websocket-contracts.d.ts +1 -0
  10. package/dist/hooks/plugin-hooks.d.ts +2 -3
  11. package/dist/logger/access-log-writer.d.ts +2 -2
  12. package/dist/main.js +1199 -176
  13. package/dist/plugins/ai-transformer/index.js +1 -1
  14. package/dist/plugins/ai-transformer/index.js.map +4 -4
  15. package/dist/plugins/codex-router/control.js +6 -2
  16. package/dist/plugins/codex-router/control.js.map +4 -4
  17. package/dist/plugins/codex-router/index.js +498 -165
  18. package/dist/plugins/codex-router/index.js.map +13 -11
  19. package/dist/plugins/codex-router/manifest.json +124 -8
  20. package/dist/plugins/key-access/index.js +12 -2
  21. package/dist/plugins/key-access/index.js.map +3 -3
  22. package/dist/plugins/key-access/ingress.js +12 -2
  23. package/dist/plugins/key-access/ingress.js.map +3 -3
  24. package/dist/plugins/openai-messages-to-chat/index.js +6 -4
  25. package/dist/plugins/openai-messages-to-chat/index.js.map +4 -4
  26. package/dist/plugins/token-metering/index.js +1 -1
  27. package/dist/plugins/token-metering/index.js.map +4 -4
  28. package/dist/plugins/token-stats/manifest.json +16 -6
  29. package/dist/plugins/token-stats/ui/ClientModelPicker.svelte +13 -61
  30. package/dist/plugins/token-stats/ui/PriceModelPicker.svelte +18 -74
  31. package/dist/plugins/token-stats/ui/TokenStatsSettings.svelte +3 -2
  32. package/dist/plugins/token-stats/ui/model-search.ts +2 -45
  33. package/dist/plugins/token-stats/ui/pricing-catalog.ts +2 -1
  34. package/dist/scoped-plugin-registry.d.ts +7 -0
  35. package/dist/websocket/index.d.ts +1 -1
  36. package/dist/websocket/transport.d.ts +40 -18
  37. package/package.json +2 -2
  38. package/dist/plugins/chatgpt-oauth/ui/account-model.test.js +0 -69
  39. package/dist/plugins/local-accounts/ui/login-errors.test.ts +0 -22
  40. package/dist/plugins/token-stats/ui/client-model-search.test.ts +0 -58
  41. package/dist/plugins/token-stats/ui/pricing-catalog.test.ts +0 -114
@@ -1,114 +0,0 @@
1
- import { expect, test } from 'bun:test';
2
- import { createPricingModelSearch, type PricingModelPage, type PricingModelSearchState } from './pricing-catalog';
3
-
4
- const option = (model: string) => ({ provider: 'custom-provider', providerName: 'Custom provider', model, name: model });
5
- const page = (models: string[], current = 1): PricingModelPage => ({ models: models.map(option), total: 8394, page: current, pageSize: 50 });
6
- const deferred = () => { let resolve!: (page: PricingModelPage) => void; const promise = new Promise<PricingModelPage>(done => resolve = done); return { resolve, promise }; };
7
- const tick = () => new Promise(resolve => setTimeout(resolve, 10));
8
-
9
- test('does not preload and requests only the selected provider page', async () => {
10
- const paths: string[] = [];
11
- const states: PricingModelSearchState[] = [];
12
- const search = createPricingModelSearch(async path => { paths.push(path); return page(['ExactCase']); }, state => states.push(state));
13
- expect(paths).toEqual([]);
14
- search.search({ provider: 'custom-provider', search: '' }, 1, false);
15
- await tick();
16
- expect(paths).toEqual(['/pricing/models?provider=custom-provider&search=&page=1&pageSize=50']);
17
- expect(states.at(-1)?.models[0]?.model).toBe('ExactCase');
18
- // A large total never triggers another page automatically.
19
- expect(paths).toHaveLength(1);
20
- search.search({ provider: 'custom-provider', search: '' }, 2, false);
21
- await tick();
22
- expect(paths.at(-1)).toContain('page=2&pageSize=50');
23
- search.destroy();
24
- });
25
-
26
- test('debounces remote searches and preserves query characters and model case', async () => {
27
- const paths: string[] = [];
28
- const states: PricingModelSearchState[] = [];
29
- const search = createPricingModelSearch(async path => { paths.push(path); return page(['DeepSeek/V4 & 中文']); }, state => states.push(state), 5);
30
- search.search({ provider: 'custom-provider', search: 'first' });
31
- search.search({ provider: 'custom-provider', search: 'DeepSeek/V4 & 中文' });
32
- await tick();
33
- expect(paths).toEqual(['/pricing/models?provider=custom-provider&search=DeepSeek%2FV4+%26+%E4%B8%AD%E6%96%87&page=1&pageSize=50']);
34
- expect(states.at(-1)?.models[0]?.model).toBe('DeepSeek/V4 & 中文');
35
- search.destroy();
36
- });
37
-
38
- test('provider changes, closure and destruction reject late results', async () => {
39
- const requests = [deferred(), deferred(), deferred()];
40
- const signals: AbortSignal[] = [];
41
- const states: PricingModelSearchState[] = [];
42
- const search = createPricingModelSearch((_path, signal) => { signals.push(signal); return requests[signals.length - 1]!.promise; }, state => states.push(state));
43
- search.search({ provider: 'old', search: '' }, 1, false);
44
- search.search({ provider: 'new', search: '' }, 1, false);
45
- expect(signals[0]!.aborted).toBe(true);
46
- requests[0]!.resolve(page(['OLD'])); await tick();
47
- expect(states.at(-1)?.models).toEqual([]);
48
- requests[1]!.resolve(page(['New'])); await tick();
49
- expect(states.at(-1)?.models[0]?.model).toBe('New');
50
- search.search({ provider: 'new', search: '' }, 1, false);
51
- search.cancel(); expect(signals[2]!.aborted).toBe(true);
52
- const count = states.length;
53
- requests[2]!.resolve(page(['Late'])); await tick();
54
- expect(states).toHaveLength(count);
55
- search.destroy(); search.search({ provider: 'ignored', search: '' }, 1, false);
56
- expect(signals).toHaveLength(3);
57
- });
58
-
59
-
60
- // Exercise the actual Svelte load functions with controlled response ordering.
61
- async function settingsFixture(loadRequest: (plugin: string, path: string) => Promise<unknown>) {
62
- const source = await Bun.file(new URL('./TokenStatsSettings.svelte', import.meta.url)).text();
63
- const providers = source.slice(source.indexOf(' async function loadProviders('), source.indexOf(' async function loadMappings('));
64
- const load = source.slice(source.indexOf(' async function load()'), source.indexOf(' onMount('));
65
- const code = `function fixture(requestPluginControl: any) {
66
- let alive = true, polling = false, loading = true, error = '', providersError = false;
67
- let status: any = null, catalogVersion: number | null = null, providers: any[] = [];
68
- let providersVersion: number | null | undefined, providersPendingVersion: number | null | undefined, providersGeneration = 0;
69
- const controller = new AbortController();
70
- ${providers}
71
- ${load}
72
- return { load, state: () => ({ status, providers, catalogVersion, loading, providersError }) };
73
- }`;
74
- const javascript = new Bun.Transpiler({ loader: 'ts' }).transformSync(code);
75
- return new Function(`${javascript}
76
- return fixture;`)()(loadRequest);
77
- }
78
-
79
- test('settings displays status without waiting for providers and ignores a superseded directory response', async () => {
80
- let version = 1;
81
- const pending: Array<(value: unknown) => void> = [];
82
- let calls = 0;
83
- const settings = await settingsFixture(async (_plugin, path) => {
84
- if (path === '/pricing') return { version, modelCount: 100 };
85
- calls++;
86
- return new Promise(resolve => pending.push(resolve));
87
- });
88
- await settings.load();
89
- expect(settings.state()).toMatchObject({ loading: false, catalogVersion: 1 });
90
- // A poll during a slow provider request does not keep aborting/restarting it.
91
- await settings.load(); expect(calls).toBe(1);
92
- version = 2;
93
- await settings.load(); expect(calls).toBe(2);
94
- pending[1]!({ providers: [{ provider: 'new' }] }); await tick();
95
- pending[0]!({ providers: [] }); await tick();
96
- expect(settings.state().providers).toEqual([{ provider: 'new' }]);
97
- await settings.load(); expect(calls).toBe(2);
98
- });
99
-
100
- test('settings recovers provider selection when an initially empty directory gets its first version', async () => {
101
- let version: number | null = null;
102
- let calls = 0;
103
- const settings = await settingsFixture(async (_plugin, path) => {
104
- if (path === '/pricing') return { version, modelCount: version === null ? 0 : 100 };
105
- calls++;
106
- return { providers: version === null ? [] : [{ provider: 'available' }] };
107
- });
108
- await settings.load(); await tick();
109
- expect(settings.state().providers).toEqual([]);
110
- version = 1;
111
- await settings.load(); await tick();
112
- expect(settings.state().providers).toEqual([{ provider: 'available' }]);
113
- expect(calls).toBe(2);
114
- });