@tracearr/shared 2.2.0-beta.2 → 2.2.0-beta.3

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 (84) hide show
  1. package/dist/automations/__tests__/actions.test.d.ts +2 -0
  2. package/dist/automations/__tests__/actions.test.d.ts.map +1 -0
  3. package/dist/automations/__tests__/actions.test.js +68 -0
  4. package/dist/automations/__tests__/actions.test.js.map +1 -0
  5. package/dist/automations/__tests__/conditions.test.d.ts +2 -0
  6. package/dist/automations/__tests__/conditions.test.d.ts.map +1 -0
  7. package/dist/automations/__tests__/conditions.test.js +55 -0
  8. package/dist/automations/__tests__/conditions.test.js.map +1 -0
  9. package/dist/automations/__tests__/definition.test.d.ts +2 -0
  10. package/dist/automations/__tests__/definition.test.d.ts.map +1 -0
  11. package/dist/automations/__tests__/definition.test.js +376 -0
  12. package/dist/automations/__tests__/definition.test.js.map +1 -0
  13. package/dist/automations/__tests__/share.test.d.ts +2 -0
  14. package/dist/automations/__tests__/share.test.d.ts.map +1 -0
  15. package/dist/automations/__tests__/share.test.js +98 -0
  16. package/dist/automations/__tests__/share.test.js.map +1 -0
  17. package/dist/automations/__tests__/templates.test.d.ts +2 -0
  18. package/dist/automations/__tests__/templates.test.d.ts.map +1 -0
  19. package/dist/automations/__tests__/templates.test.js +278 -0
  20. package/dist/automations/__tests__/templates.test.js.map +1 -0
  21. package/dist/automations/__tests__/triggers.test.d.ts +2 -0
  22. package/dist/automations/__tests__/triggers.test.d.ts.map +1 -0
  23. package/dist/automations/__tests__/triggers.test.js +42 -0
  24. package/dist/automations/__tests__/triggers.test.js.map +1 -0
  25. package/dist/automations/actions.d.ts +783 -0
  26. package/dist/automations/actions.d.ts.map +1 -0
  27. package/dist/automations/actions.js +97 -0
  28. package/dist/automations/actions.js.map +1 -0
  29. package/dist/automations/conditions.d.ts +459 -0
  30. package/dist/automations/conditions.d.ts.map +1 -0
  31. package/dist/automations/conditions.js +460 -0
  32. package/dist/automations/conditions.js.map +1 -0
  33. package/dist/automations/definition.d.ts +1389 -0
  34. package/dist/automations/definition.d.ts.map +1 -0
  35. package/dist/automations/definition.js +215 -0
  36. package/dist/automations/definition.js.map +1 -0
  37. package/dist/automations/dryRun.d.ts +413 -0
  38. package/dist/automations/dryRun.d.ts.map +1 -0
  39. package/dist/automations/dryRun.js +9 -0
  40. package/dist/automations/dryRun.js.map +1 -0
  41. package/dist/automations/index.d.ts +8 -0
  42. package/dist/automations/index.d.ts.map +1 -0
  43. package/dist/automations/index.js +8 -0
  44. package/dist/automations/index.js.map +1 -0
  45. package/dist/automations/share.d.ts +27 -0
  46. package/dist/automations/share.d.ts.map +1 -0
  47. package/dist/automations/share.js +119 -0
  48. package/dist/automations/share.js.map +1 -0
  49. package/dist/automations/templates.d.ts +1304 -0
  50. package/dist/automations/templates.d.ts.map +1 -0
  51. package/dist/automations/templates.js +525 -0
  52. package/dist/automations/templates.js.map +1 -0
  53. package/dist/automations/triggers.d.ts +141 -0
  54. package/dist/automations/triggers.d.ts.map +1 -0
  55. package/dist/automations/triggers.js +172 -0
  56. package/dist/automations/triggers.js.map +1 -0
  57. package/dist/constants.d.ts +22 -40
  58. package/dist/constants.d.ts.map +1 -1
  59. package/dist/constants.js +25 -56
  60. package/dist/constants.js.map +1 -1
  61. package/dist/destinations.d.ts +21 -22
  62. package/dist/destinations.d.ts.map +1 -1
  63. package/dist/destinations.js +13 -2
  64. package/dist/destinations.js.map +1 -1
  65. package/dist/index.d.ts +10 -5
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +15 -9
  68. package/dist/index.js.map +1 -1
  69. package/dist/listQuery.d.ts +41 -0
  70. package/dist/listQuery.d.ts.map +1 -0
  71. package/dist/listQuery.js +33 -0
  72. package/dist/listQuery.js.map +1 -0
  73. package/dist/schemas.d.ts +152 -832
  74. package/dist/schemas.d.ts.map +1 -1
  75. package/dist/schemas.js +90 -287
  76. package/dist/schemas.js.map +1 -1
  77. package/dist/types.d.ts +51 -137
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js.map +1 -1
  80. package/dist/violations.d.ts +2 -1
  81. package/dist/violations.d.ts.map +1 -1
  82. package/dist/violations.js +7 -0
  83. package/dist/violations.js.map +1 -1
  84. package/package.json +2 -1
@@ -0,0 +1,98 @@
1
+ import { deflateRawSync, inflateRawSync } from 'node:zlib';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { SHARE_CODE_PREFIX, ShareCodeError, canonicalJson, decodeShareCode, encodeShareCode, } from '../index.js';
4
+ const deflateRaw = (bytes) => new Uint8Array(deflateRawSync(bytes));
5
+ const inflateRaw = (bytes, maxOut) => new Uint8Array(inflateRawSync(bytes, { maxOutputLength: maxOut }));
6
+ const id = (n) => `00000000-0000-4000-8000-${String(n).padStart(12, '0')}`;
7
+ const envelope = {
8
+ schemaVersion: 1,
9
+ slug: 'stream-started',
10
+ name: 'Stream started',
11
+ description: 'Notify a destination whenever playback begins',
12
+ group: 'notifications',
13
+ kind: 'notification',
14
+ minServerVersion: '2.2.0',
15
+ inputs: [{ key: 'to', kind: 'destinations', label: 'Send to', required: true }],
16
+ definition: {
17
+ kind: 'notification',
18
+ triggers: [{ id: id(1), type: 'session.started', enabled: true }],
19
+ conditions: { groups: [] },
20
+ actions: { actions: [{ id: id(2), type: 'send', to: { $input: 'to' } }] },
21
+ scope: {},
22
+ },
23
+ fingerprint: 'a'.repeat(64),
24
+ };
25
+ describe('canonicalJson', () => {
26
+ it('sorts keys, keeps array order and drops undefined', () => {
27
+ expect(canonicalJson({ b: 1, a: [3, 2], c: undefined })).toBe('{"a":[3,2],"b":1}');
28
+ });
29
+ });
30
+ describe('share codes', () => {
31
+ it('round-trips an envelope', () => {
32
+ const code = encodeShareCode(envelope, deflateRaw);
33
+ expect(code.startsWith(SHARE_CODE_PREFIX)).toBe(true);
34
+ expect(decodeShareCode(code, inflateRaw)).toEqual(envelope);
35
+ });
36
+ it('rejects a truncated code', () => {
37
+ const code = encodeShareCode(envelope, deflateRaw);
38
+ expect(() => decodeShareCode(code.slice(0, code.length - 12), inflateRaw)).toThrow(ShareCodeError);
39
+ try {
40
+ decodeShareCode(code.slice(0, code.length - 12), inflateRaw);
41
+ }
42
+ catch (error) {
43
+ expect(error.reason).toBe('incomplete');
44
+ }
45
+ });
46
+ it('rejects an oversized code before inflating', () => {
47
+ let calls = 0;
48
+ const counted = (bytes, maxOut) => {
49
+ calls += 1;
50
+ return inflateRaw(bytes, maxOut);
51
+ };
52
+ const code = SHARE_CODE_PREFIX + 'A'.repeat(65_537);
53
+ try {
54
+ decodeShareCode(code, counted);
55
+ expect.unreachable('oversized code should throw');
56
+ }
57
+ catch (error) {
58
+ expect(error.reason).toBe('too_long');
59
+ }
60
+ expect(calls).toBe(0);
61
+ });
62
+ it('rejects a small code that inflates past the output cap', () => {
63
+ const bomb = { ...envelope, description: 'x'.repeat(2_000_000) };
64
+ const code = encodeShareCode(bomb, deflateRaw);
65
+ expect(code.length).toBeLessThan(65_536);
66
+ try {
67
+ decodeShareCode(code, inflateRaw);
68
+ expect.unreachable('a compression bomb should throw');
69
+ }
70
+ catch (error) {
71
+ expect(error.reason).toBe('incomplete');
72
+ }
73
+ });
74
+ it('rejects a code with the wrong prefix', () => {
75
+ const code = encodeShareCode(envelope, deflateRaw);
76
+ try {
77
+ decodeShareCode(code.replace(SHARE_CODE_PREFIX, 'tracearr2.'), inflateRaw);
78
+ expect.unreachable('wrong prefix should throw');
79
+ }
80
+ catch (error) {
81
+ expect(error.reason).toBe('prefix');
82
+ }
83
+ });
84
+ it('rejects a payload nested past the depth limit', () => {
85
+ let nested = 1;
86
+ for (let level = 0; level < 40; level += 1)
87
+ nested = [nested];
88
+ const deep = encodeShareCode(nested, deflateRaw);
89
+ try {
90
+ decodeShareCode(deep, inflateRaw);
91
+ expect.unreachable('deep payload should throw');
92
+ }
93
+ catch (error) {
94
+ expect(error.reason).toBe('too_deep');
95
+ }
96
+ });
97
+ });
98
+ //# sourceMappingURL=share.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share.test.js","sourceRoot":"","sources":["../../../src/automations/__tests__/share.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=templates.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.test.d.ts","sourceRoot":"","sources":["../../../src/automations/__tests__/templates.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,278 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { SLOT_KINDS, TEMPLATE_MIN_SERVER_VERSION, TEMPLATE_SCHEMA_VERSION, TemplateBindingError, fingerprintOf, liftAutomation, materializeTemplate, templateEnvelopeSchema, } from '../index.js';
4
+ import * as entry from '../../index.js';
5
+ const sha256Hex = (text) => createHash('sha256').update(text).digest('hex');
6
+ const id = (n) => `00000000-0000-4000-8000-${String(n).padStart(12, '0')}`;
7
+ const serverInput = { key: 'server', kind: 'server', label: 'Server', required: false };
8
+ const toInput = { key: 'to', kind: 'destinations', label: 'Send to', required: true };
9
+ const streamStarted = {
10
+ kind: 'notification',
11
+ triggers: [{ id: id(1), type: 'session.started', enabled: true }],
12
+ conditions: { groups: [] },
13
+ actions: {
14
+ actions: [
15
+ {
16
+ id: id(2),
17
+ type: 'send',
18
+ to: { $input: 'to' },
19
+ title: 'Stream started',
20
+ body: '{{user.username}} started {{session.mediaTitle}}',
21
+ },
22
+ ],
23
+ },
24
+ scope: { serverId: { $input: 'server' } },
25
+ };
26
+ function envelope(patch = {}) {
27
+ const inputs = [serverInput, toInput];
28
+ return {
29
+ schemaVersion: TEMPLATE_SCHEMA_VERSION,
30
+ slug: 'stream-started',
31
+ name: 'Stream started',
32
+ description: 'Notify a destination whenever playback begins',
33
+ group: 'notifications',
34
+ kind: 'notification',
35
+ minServerVersion: TEMPLATE_MIN_SERVER_VERSION,
36
+ inputs,
37
+ definition: streamStarted,
38
+ fingerprint: fingerprintOf({ inputs, definition: streamStarted }, sha256Hex),
39
+ ...patch,
40
+ };
41
+ }
42
+ const paths = (issues) => issues.map((issue) => issue.path.join('.'));
43
+ describe('templateEnvelopeSchema', () => {
44
+ it('round-trips a hand-written envelope', () => {
45
+ const written = envelope();
46
+ const parsed = templateEnvelopeSchema.parse(written);
47
+ expect(parsed).toEqual(written);
48
+ });
49
+ it('rejects a placeholder naming no declared input', () => {
50
+ const result = templateEnvelopeSchema.safeParse(envelope({
51
+ definition: { ...streamStarted, scope: { serverId: { $input: 'nope' } } },
52
+ }));
53
+ expect(result.success).toBe(false);
54
+ expect(paths(result.error?.issues ?? [])).toContain('definition.scope.serverId');
55
+ });
56
+ it('rejects an input nothing references', () => {
57
+ const inputs = [
58
+ serverInput,
59
+ toInput,
60
+ { key: 'spare', kind: 'text', label: 'Spare', required: false, default: 'x' },
61
+ ];
62
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs }));
63
+ expect(result.success).toBe(false);
64
+ expect(paths(result.error?.issues ?? [])).toContain('inputs.2.key');
65
+ });
66
+ it('rejects a default on a server input', () => {
67
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs: [{ ...serverInput, default: id(3) }, toInput] }));
68
+ expect(result.success).toBe(false);
69
+ });
70
+ it('rejects an optional destinations input', () => {
71
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs: [serverInput, { ...toInput, required: false }] }));
72
+ expect(result.success).toBe(false);
73
+ });
74
+ it('rejects an optional input with no default', () => {
75
+ const inputs = [
76
+ serverInput,
77
+ toInput,
78
+ { key: 'note', kind: 'text', label: 'Note', required: false },
79
+ ];
80
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs }));
81
+ expect(result.success).toBe(false);
82
+ });
83
+ it('rejects a literal destination id but keeps node ids', () => {
84
+ const definition = {
85
+ ...streamStarted,
86
+ actions: { actions: [{ id: id(2), type: 'send', to: [id(4)] }] },
87
+ };
88
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs: [serverInput], definition }));
89
+ expect(result.success).toBe(false);
90
+ expect(paths(result.error?.issues ?? [])).toContain('definition.actions.actions.0.to');
91
+ expect(templateEnvelopeSchema.safeParse(envelope()).success).toBe(true);
92
+ });
93
+ it('rejects an envelope whose kind differs from its definition', () => {
94
+ const result = templateEnvelopeSchema.safeParse(envelope({ kind: 'policy' }));
95
+ expect(result.success).toBe(false);
96
+ expect(paths(result.error?.issues ?? [])).toContain('kind');
97
+ });
98
+ it('rejects an input kind the slot cannot take', () => {
99
+ const inputs = [serverInput, { ...toInput, kind: 'text', default: 'x', required: false }];
100
+ const result = templateEnvelopeSchema.safeParse(envelope({ inputs }));
101
+ expect(result.success).toBe(false);
102
+ });
103
+ });
104
+ describe('materializeTemplate', () => {
105
+ const version = () => {
106
+ const parsed = templateEnvelopeSchema.parse(envelope());
107
+ return { inputs: parsed.inputs, definition: parsed.definition };
108
+ };
109
+ it('drops an unbound optional scope and substitutes what is bound', () => {
110
+ const result = materializeTemplate(version(), { to: [id(5)] }, { name: 'Stream started' });
111
+ expect(result.name).toBe('Stream started');
112
+ expect('serverId' in result).toBe(false);
113
+ const [action] = result.actions.actions;
114
+ expect(action).toMatchObject({ type: 'send', to: [id(5)] });
115
+ });
116
+ it('binds a scope input that is supplied', () => {
117
+ const result = materializeTemplate(version(), { to: [id(5)], server: id(6) }, { name: 'Stream started' });
118
+ expect(result.serverId).toBe(id(6));
119
+ });
120
+ it('throws with the keys a required input is missing', () => {
121
+ const name = { name: 'Stream started' };
122
+ expect(() => materializeTemplate(version(), {}, name)).toThrow(TemplateBindingError);
123
+ try {
124
+ materializeTemplate(version(), {}, name);
125
+ }
126
+ catch (error) {
127
+ expect(error).toBeInstanceOf(TemplateBindingError);
128
+ expect(error.missing).toEqual(['to']);
129
+ }
130
+ });
131
+ it('converts an hours input into a minutes slot', () => {
132
+ const inputs = [
133
+ { key: 'hold', kind: 'duration', unit: 'hours', label: 'Hold for', required: true },
134
+ ];
135
+ const definition = {
136
+ kind: 'notification',
137
+ triggers: [
138
+ {
139
+ id: id(7),
140
+ type: 'session.held_for',
141
+ enabled: true,
142
+ params: { minutes: { $input: 'hold' }, measure: 'current' },
143
+ },
144
+ ],
145
+ conditions: { groups: [] },
146
+ actions: { actions: [] },
147
+ scope: {},
148
+ };
149
+ const result = materializeTemplate({ inputs, definition }, { hold: 2 }, { name: 'Held' });
150
+ const [trigger] = result.triggers;
151
+ expect(trigger).toMatchObject({ type: 'session.held_for', params: { minutes: 120 } });
152
+ });
153
+ });
154
+ describe('liftAutomation', () => {
155
+ it('turns scope ids, destinations and network values into required inputs', () => {
156
+ const automation = {
157
+ name: 'Kill VPN streams',
158
+ kind: 'policy',
159
+ severity: 'warning',
160
+ triggers: [{ id: id(1), type: 'session.started', enabled: true }],
161
+ conditions: {
162
+ groups: [
163
+ {
164
+ id: id(8),
165
+ conditions: [{ id: id(9), field: 'ip_in_range', operator: 'eq', value: '10.0.0.0/8' }],
166
+ },
167
+ ],
168
+ },
169
+ actions: { actions: [{ id: id(2), type: 'send', to: [id(4)] }] },
170
+ serverId: id(6),
171
+ };
172
+ const { inputs, definition } = liftAutomation(automation);
173
+ expect(inputs).toHaveLength(3);
174
+ expect(inputs.every((input) => input.required)).toBe(true);
175
+ expect(inputs.map((input) => input.kind).sort()).toEqual([
176
+ 'destinations',
177
+ 'field_value',
178
+ 'server',
179
+ ]);
180
+ expect(definition.scope.serverId).toEqual({ $input: 'server' });
181
+ expect(definition.actions.actions[0]).toMatchObject({ to: { $input: 'to' } });
182
+ expect(definition.conditions.groups[0]?.conditions[0]?.value).toEqual({ $input: 'ipInRange' });
183
+ expect(definition.triggers).toEqual(automation.triggers);
184
+ });
185
+ it('gives each differing send list its own input', () => {
186
+ const automation = {
187
+ name: 'Two sends',
188
+ kind: 'notification',
189
+ severity: null,
190
+ triggers: [{ id: id(1), type: 'session.started', enabled: true }],
191
+ conditions: { groups: [] },
192
+ actions: {
193
+ actions: [
194
+ { id: id(2), type: 'send', to: [id(4)] },
195
+ { id: id(3), type: 'send', to: [id(5)] },
196
+ { id: id(7), type: 'send', to: [id(4)] },
197
+ ],
198
+ },
199
+ };
200
+ const { inputs, definition } = liftAutomation(automation);
201
+ expect(inputs.map((input) => input.key)).toEqual(['to', 'to2']);
202
+ expect(definition.actions.actions.map((action) => ('to' in action ? action.to : null))).toEqual([{ $input: 'to' }, { $input: 'to2' }, { $input: 'to' }]);
203
+ });
204
+ });
205
+ describe('lift and materialize', () => {
206
+ it('round-trips an automation through an envelope and back to its ids', () => {
207
+ const automation = {
208
+ name: 'Kill VPN streams',
209
+ kind: 'policy',
210
+ severity: 'warning',
211
+ triggers: [{ id: id(1), type: 'session.started', enabled: true }],
212
+ conditions: {
213
+ groups: [
214
+ {
215
+ id: id(8),
216
+ conditions: [{ id: id(9), field: 'ip_in_range', operator: 'eq', value: '10.0.0.0/8' }],
217
+ },
218
+ ],
219
+ },
220
+ actions: { actions: [{ id: id(2), type: 'send', to: [id(4)] }] },
221
+ serverId: id(6),
222
+ };
223
+ const lifted = liftAutomation(automation);
224
+ const parsed = templateEnvelopeSchema.parse({
225
+ schemaVersion: TEMPLATE_SCHEMA_VERSION,
226
+ slug: 'kill-vpn-streams',
227
+ name: 'Kill VPN streams',
228
+ description: 'Stop playback from a named network range',
229
+ group: 'policies',
230
+ kind: 'policy',
231
+ minServerVersion: TEMPLATE_MIN_SERVER_VERSION,
232
+ inputs: lifted.inputs,
233
+ definition: lifted.definition,
234
+ fingerprint: fingerprintOf(lifted, sha256Hex),
235
+ });
236
+ const rebuilt = materializeTemplate({ inputs: parsed.inputs, definition: parsed.definition }, { server: id(6), to: [id(4)], ipInRange: '10.0.0.0/8' }, { name: automation.name });
237
+ expect(rebuilt).toEqual(automation);
238
+ });
239
+ });
240
+ const ENTRY_EXPORTS = [
241
+ 'TEMPLATE_GROUPS',
242
+ 'templateEnvelopeSchema',
243
+ 'TEMPLATE_SCHEMA_VERSION',
244
+ 'TEMPLATE_MIN_SERVER_VERSION',
245
+ 'canonicalJson',
246
+ 'fingerprintOf',
247
+ 'materializeTemplate',
248
+ 'slotValueFor',
249
+ 'liftAutomation',
250
+ 'encodeShareCode',
251
+ 'decodeShareCode',
252
+ 'ShareCodeError',
253
+ 'TemplateBindingError',
254
+ ];
255
+ describe('package entry', () => {
256
+ it('reaches every template and share primitive a consumer uses', () => {
257
+ expect(ENTRY_EXPORTS.filter((name) => !(name in entry))).toEqual([]);
258
+ const destinations = 'to';
259
+ expect(SLOT_KINDS[destinations]).toEqual(['destinations']);
260
+ });
261
+ });
262
+ describe('fingerprintOf', () => {
263
+ it('is stable across key order', () => {
264
+ const inputs = [serverInput, toInput];
265
+ const first = fingerprintOf({ inputs, definition: streamStarted }, sha256Hex);
266
+ const reordered = {
267
+ scope: streamStarted.scope,
268
+ actions: streamStarted.actions,
269
+ conditions: streamStarted.conditions,
270
+ triggers: streamStarted.triggers,
271
+ kind: streamStarted.kind,
272
+ };
273
+ const second = fingerprintOf({ definition: reordered, inputs }, sha256Hex);
274
+ expect(second).toBe(first);
275
+ expect(first).toMatch(/^[0-9a-f]{64}$/);
276
+ });
277
+ });
278
+ //# sourceMappingURL=templates.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../../src/automations/__tests__/templates.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=triggers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triggers.test.d.ts","sourceRoot":"","sources":["../../../src/automations/__tests__/triggers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { TRIGGERS, TRIGGER_TYPES, contextOf, contextSupplies, variablesFor } from '../index.js';
3
+ const id = (n) => `00000000-0000-4000-8000-${String(n).padStart(12, '0')}`;
4
+ const started = { id: id(1), type: 'session.started', enabled: true };
5
+ const down = { id: id(2), type: 'server.down', enabled: true };
6
+ const added = { id: id(3), type: 'media.added', enabled: true };
7
+ const upgraded = { id: id(4), type: 'media.upgraded', enabled: true };
8
+ const newDevice = { id: id(5), type: 'account.new_device', enabled: true };
9
+ const trustChanged = { id: id(6), type: 'account.trust_changed', enabled: true };
10
+ describe('trigger contexts', () => {
11
+ it('walks the parent chain to say what a context supplies', () => {
12
+ expect(contextSupplies('media', 'server')).toBe(true);
13
+ expect(contextSupplies('media', 'account')).toBe(false);
14
+ expect(contextSupplies('session', 'media')).toBe(false);
15
+ expect(contextSupplies('session', 'account')).toBe(true);
16
+ expect(contextSupplies('server', 'server')).toBe(true);
17
+ expect(contextSupplies('install', 'server')).toBe(false);
18
+ });
19
+ it('meets a media trigger and a session one at the server they share', () => {
20
+ expect(contextOf([started, added])).toBe('server');
21
+ expect(contextOf([added, upgraded])).toBe('media');
22
+ expect(contextOf([added])).toBe('media');
23
+ expect(contextOf([started, down])).toBe('server');
24
+ });
25
+ it('meets a new-device trigger with the account it sits under and the server beyond it', () => {
26
+ expect(contextOf([newDevice])).toBe('session');
27
+ expect(contextOf([newDevice, trustChanged])).toBe('account');
28
+ expect(contextOf([newDevice, added])).toBe('server');
29
+ });
30
+ it('lists every catalog key', () => {
31
+ expect(TRIGGER_TYPES).toEqual(Object.keys(TRIGGERS));
32
+ });
33
+ it('ignores disabled triggers', () => {
34
+ expect(contextOf([started, { ...down, enabled: false }])).toBe('session');
35
+ expect(contextOf([{ ...started, enabled: false }])).toBeNull();
36
+ expect(variablesFor([started, { ...down, enabled: false }])).toContain('user.username');
37
+ });
38
+ it('offers no variables when nothing is enabled', () => {
39
+ expect(variablesFor([])).toEqual([]);
40
+ });
41
+ });
42
+ //# sourceMappingURL=triggers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triggers.test.js","sourceRoot":"","sources":["../../../src/automations/__tests__/triggers.test.ts"],"names":[],"mappings":"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"}