onbuzz 4.6.1 → 4.6.2

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": "onbuzz",
3
- "version": "4.6.1",
3
+ "version": "4.6.2",
4
4
  "description": "Loxia OnBuzz - Your AI Fleet",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Sync-guard for vendored web-ui copies of server-side helpers.
3
+ *
4
+ * Two helpers exist in BOTH `src/utilities/` (server-side, under unit
5
+ * tests) AND `web-ui/src/utils/` (vendored copy bundled by Vite).
6
+ * We keep two copies because the Docker build context is `web-ui/`
7
+ * only — cross-tree imports from `../../../src/...` worked locally
8
+ * but broke production builds.
9
+ *
10
+ * The two copies must stay BEHAVIORALLY identical. This test imports
11
+ * both copies and exercises them on the same fixtures, asserting the
12
+ * outputs match. If they diverge, this test fails loudly; whoever
13
+ * changed one was supposed to change the other.
14
+ *
15
+ * The path-based dynamic import bypasses the unit jest project's
16
+ * `/web-ui/` testPathIgnorePattern (we're not running web-ui tests,
17
+ * we're just importing modules from the web-ui tree to compare them).
18
+ */
19
+ import { describe, test, expect, beforeAll } from '@jest/globals';
20
+
21
+ // Server-side originals.
22
+ import * as srvEdgeIds from '../flowEdgeIds.js';
23
+ import * as srvPublish from '../flowPublish.js';
24
+
25
+ // Vendored web-ui copies. Plain relative imports — jest's
26
+ // testPathIgnorePatterns gates which TEST FILES run (not which modules
27
+ // can be imported by other tests), so importing from web-ui/ is fine.
28
+ import * as webUiEdgeIds from '../../../web-ui/src/utils/flowEdgeIds.js';
29
+ import * as webUiPublish from '../../../web-ui/src/utils/flowPublish.js';
30
+
31
+ // Fixtures exercising both helpers' interesting branches.
32
+ const edgeFixtures = [
33
+ [],
34
+ null,
35
+ undefined,
36
+ 'not-an-array',
37
+ [{ source: 'a', target: 'b' }],
38
+ [{ source: 'a', sourceField: 'topic', target: 'b', targetField: 'topic' }],
39
+ [{ id: 'pre-existing-id', source: 'a', target: 'b' }],
40
+ [
41
+ { source: 'a', target: 'b' },
42
+ { source: 'a', target: 'b' }, // duplicate — needs index tiebreaker
43
+ { id: 'kept', source: 'c', target: 'd' },
44
+ ],
45
+ [null, { source: 'x', target: 'y' }, undefined],
46
+ ];
47
+
48
+ const flowFixtures = [
49
+ null,
50
+ undefined,
51
+ 'not-an-object',
52
+ { nodes: [], edges: [] },
53
+ {
54
+ schemaVersion: 2,
55
+ description: 'A '.repeat(200),
56
+ nodes: [
57
+ { id: 'in', type: 'input' },
58
+ { id: 'a', type: 'agent', data: { agentId: 'agent-real-id', model: 'gpt-5', label: 'A' } },
59
+ { id: 'b', type: 'agent', data: { agentId: 'another-id', preferredModel: 'kimi' } },
60
+ { id: 'p', type: 'pause' },
61
+ { id: 'cron',type: 'agent', data: { cron: '0 9 * * *' } },
62
+ { id: 'out', type: 'output' },
63
+ ],
64
+ edges: [{ source: 'in', target: 'a' }, { source: 'a', target: 'b' }],
65
+ },
66
+ ];
67
+
68
+ describe('flowEdgeIds — server vs web-ui copy', () => {
69
+ test('exports the same surface', () => {
70
+ expect(typeof webUiEdgeIds.makeEdgeId).toBe('function');
71
+ expect(typeof webUiEdgeIds.ensureEdgeIds).toBe('function');
72
+ });
73
+
74
+ test('makeEdgeId outputs match for every fixture edge', () => {
75
+ const cases = [
76
+ [{ source: 'a', target: 'b' }, 0],
77
+ [{ source: 'a', sourceField: 'x', target: 'b', targetField: 'y' }, 7],
78
+ [{}, 0],
79
+ [null, 5],
80
+ [{ source: 'with:colons', target: 'b' }, 0],
81
+ ];
82
+ for (const [edge, idx] of cases) {
83
+ expect(webUiEdgeIds.makeEdgeId(edge, idx)).toBe(srvEdgeIds.makeEdgeId(edge, idx));
84
+ }
85
+ });
86
+
87
+ test('ensureEdgeIds outputs match for every fixture array', () => {
88
+ for (const fixture of edgeFixtures) {
89
+ const a = srvEdgeIds.ensureEdgeIds(fixture);
90
+ const b = webUiEdgeIds.ensureEdgeIds(fixture);
91
+ expect(b).toEqual(a);
92
+ }
93
+ });
94
+ });
95
+
96
+ describe('flowPublish — server vs web-ui copy', () => {
97
+ test('exports the same surface', () => {
98
+ expect(typeof webUiPublish.computeFlowPublishMetadata).toBe('function');
99
+ expect(typeof webUiPublish.sanitizeFlowForPublish).toBe('function');
100
+ });
101
+
102
+ test('computeFlowPublishMetadata outputs match for every fixture flow', () => {
103
+ for (const flow of flowFixtures) {
104
+ const a = srvPublish.computeFlowPublishMetadata(flow);
105
+ const b = webUiPublish.computeFlowPublishMetadata(flow);
106
+ expect(b).toEqual(a);
107
+ }
108
+ });
109
+
110
+ test('sanitizeFlowForPublish outputs match for every fixture flow', () => {
111
+ for (const flow of flowFixtures) {
112
+ const a = srvPublish.sanitizeFlowForPublish(flow);
113
+ const b = webUiPublish.sanitizeFlowForPublish(flow);
114
+ expect(b).toEqual(a);
115
+ }
116
+ });
117
+ });