@tappify/extension-sdk 2.0.0 → 2.1.0-beta.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.
Files changed (148) hide show
  1. package/README.md +208 -0
  2. package/dist/chunk-2CY5HVY7.mjs +59 -0
  3. package/dist/chunk-2CY5HVY7.mjs.map +1 -0
  4. package/dist/{chunk-2DBSVKAU.cjs → chunk-6HETNZJY.cjs} +1 -1
  5. package/dist/chunk-6HETNZJY.cjs.map +1 -0
  6. package/dist/{chunk-PYJMJF44.cjs → chunk-7YKH4LZN.cjs} +9 -2
  7. package/dist/chunk-7YKH4LZN.cjs.map +1 -0
  8. package/dist/{chunk-RMUWRESK.cjs → chunk-A74HCO6T.cjs} +31 -18
  9. package/dist/chunk-A74HCO6T.cjs.map +1 -0
  10. package/dist/chunk-BPCGXXMD.cjs +781 -0
  11. package/dist/chunk-BPCGXXMD.cjs.map +1 -0
  12. package/dist/chunk-EB5XWQAU.cjs +132 -0
  13. package/dist/chunk-EB5XWQAU.cjs.map +1 -0
  14. package/dist/{chunk-5AAPD5WV.cjs → chunk-GAUZYBXE.cjs} +11 -11
  15. package/dist/chunk-GAUZYBXE.cjs.map +1 -0
  16. package/dist/chunk-J5LGTIGS.mjs +10 -0
  17. package/dist/chunk-J5LGTIGS.mjs.map +1 -0
  18. package/dist/{chunk-ZT35X7KL.mjs → chunk-KZ5NGFUP.mjs} +22 -9
  19. package/dist/chunk-KZ5NGFUP.mjs.map +1 -0
  20. package/dist/chunk-NN263PGQ.cjs +70 -0
  21. package/dist/chunk-NN263PGQ.cjs.map +1 -0
  22. package/dist/{chunk-3YWVYA42.cjs → chunk-O357OJXL.cjs} +14 -18
  23. package/dist/chunk-O357OJXL.cjs.map +1 -0
  24. package/dist/chunk-ONJMPO3P.cjs +59 -0
  25. package/dist/chunk-ONJMPO3P.cjs.map +1 -0
  26. package/dist/{chunk-OPPYEA7F.cjs → chunk-PRCZMOLD.cjs} +3 -3
  27. package/dist/chunk-PRCZMOLD.cjs.map +1 -0
  28. package/dist/chunk-Q7SFCCGT.cjs +10 -0
  29. package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
  30. package/dist/{chunk-QHM7XNRK.mjs → chunk-QA5AL3VZ.mjs} +2 -2
  31. package/dist/{chunk-QHM7XNRK.mjs.map → chunk-QA5AL3VZ.mjs.map} +1 -1
  32. package/dist/chunk-QJMZRV7A.mjs +132 -0
  33. package/dist/chunk-QJMZRV7A.mjs.map +1 -0
  34. package/dist/{chunk-CSTYBKZC.mjs → chunk-QXD7WVKK.mjs} +1 -1
  35. package/dist/chunk-QXD7WVKK.mjs.map +1 -0
  36. package/dist/{chunk-4C5Z3CIK.mjs → chunk-RBIQT75L.mjs} +2 -2
  37. package/dist/chunk-RBIQT75L.mjs.map +1 -0
  38. package/dist/{chunk-MNDVYPEP.mjs → chunk-SGCYEEXD.mjs} +9 -2
  39. package/dist/chunk-SGCYEEXD.mjs.map +1 -0
  40. package/dist/{chunk-BDCX6LRQ.mjs → chunk-SGEYDV3K.mjs} +3 -3
  41. package/dist/chunk-SGEYDV3K.mjs.map +1 -0
  42. package/dist/{chunk-IGK2AP6J.mjs → chunk-SLGOHIBL.mjs} +13 -17
  43. package/dist/chunk-SLGOHIBL.mjs.map +1 -0
  44. package/dist/chunk-SWG7CNTZ.mjs +781 -0
  45. package/dist/chunk-SWG7CNTZ.mjs.map +1 -0
  46. package/dist/{chunk-7KIKOH5H.cjs → chunk-VV7ELNRW.cjs} +3 -3
  47. package/dist/chunk-VV7ELNRW.cjs.map +1 -0
  48. package/dist/chunk-Z43DPNZ6.mjs +70 -0
  49. package/dist/chunk-Z43DPNZ6.mjs.map +1 -0
  50. package/dist/client-BO3kavn0.d.ts +25 -0
  51. package/dist/client-DE-vMgdO.d.cts +25 -0
  52. package/dist/codegen.cjs.map +1 -1
  53. package/dist/codegen.d.cts +43 -7
  54. package/dist/codegen.d.ts +43 -7
  55. package/dist/codegen.mjs.map +1 -1
  56. package/dist/{constants-DJ_KgZpN.d.cts → constants-Bh759FUI.d.cts} +44 -8
  57. package/dist/{constants-DJ_KgZpN.d.ts → constants-Bh759FUI.d.ts} +44 -8
  58. package/dist/{context-Dt6xh_5t.d.cts → context-DI0EJCRD.d.cts} +5 -4
  59. package/dist/{context-Ml7k_V14.d.ts → context-mr8R5CNt.d.ts} +5 -4
  60. package/dist/{errors-COsBh7kd.d.cts → errors-Cqh0wrqt.d.cts} +3 -2
  61. package/dist/{errors-COsBh7kd.d.ts → errors-Cqh0wrqt.d.ts} +3 -2
  62. package/dist/host.cjs +5 -4
  63. package/dist/host.cjs.map +1 -1
  64. package/dist/host.d.cts +5 -5
  65. package/dist/host.d.ts +5 -5
  66. package/dist/host.mjs +4 -3
  67. package/dist/host.mjs.map +1 -1
  68. package/dist/index.cjs +9 -656
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.d.cts +69 -627
  71. package/dist/index.d.ts +69 -627
  72. package/dist/index.mjs +5 -652
  73. package/dist/index.mjs.map +1 -1
  74. package/dist/manifest.cjs +142 -86
  75. package/dist/manifest.cjs.map +1 -1
  76. package/dist/manifest.d.cts +97 -12
  77. package/dist/manifest.d.ts +97 -12
  78. package/dist/manifest.mjs +129 -73
  79. package/dist/manifest.mjs.map +1 -1
  80. package/dist/server.cjs +15 -66
  81. package/dist/server.cjs.map +1 -1
  82. package/dist/server.d.cts +6 -6
  83. package/dist/server.d.ts +6 -6
  84. package/dist/server.mjs +10 -61
  85. package/dist/server.mjs.map +1 -1
  86. package/dist/testing/index.cjs +73 -750
  87. package/dist/testing/index.cjs.map +1 -1
  88. package/dist/testing/index.d.cts +30 -11
  89. package/dist/testing/index.d.ts +30 -11
  90. package/dist/testing/index.mjs +89 -766
  91. package/dist/testing/index.mjs.map +1 -1
  92. package/dist/testing/jest.cjs +6 -5
  93. package/dist/testing/jest.cjs.map +1 -1
  94. package/dist/testing/jest.mjs +3 -2
  95. package/dist/testing/jest.mjs.map +1 -1
  96. package/dist/testing/vitest.cjs +6 -5
  97. package/dist/testing/vitest.cjs.map +1 -1
  98. package/dist/testing/vitest.d.cts +10 -0
  99. package/dist/testing/vitest.d.ts +10 -0
  100. package/dist/testing/vitest.mjs +3 -2
  101. package/dist/testing/vitest.mjs.map +1 -1
  102. package/dist/{types-DDAGLpov.d.ts → types-BdDaLnqs.d.cts} +4 -3
  103. package/dist/{types-DrpQSv_2.d.cts → types-uGHrRaOj.d.ts} +4 -3
  104. package/dist/ui/styles.css +740 -0
  105. package/dist/ui.cjs +1018 -0
  106. package/dist/ui.cjs.map +1 -0
  107. package/dist/ui.d.cts +231 -0
  108. package/dist/ui.d.ts +231 -0
  109. package/dist/ui.mjs +1018 -0
  110. package/dist/ui.mjs.map +1 -0
  111. package/dist/vite-preview-bootstrap.cjs +66 -0
  112. package/dist/vite-preview-bootstrap.cjs.map +1 -0
  113. package/dist/vite-preview-bootstrap.d.cts +15 -0
  114. package/dist/vite-preview-bootstrap.d.ts +15 -0
  115. package/dist/vite-preview-bootstrap.mjs +66 -0
  116. package/dist/vite-preview-bootstrap.mjs.map +1 -0
  117. package/dist/vite-preview.cjs +876 -0
  118. package/dist/vite-preview.cjs.map +1 -0
  119. package/dist/vite-preview.d.cts +9 -0
  120. package/dist/vite-preview.d.ts +9 -0
  121. package/dist/vite-preview.mjs +876 -0
  122. package/dist/vite-preview.mjs.map +1 -0
  123. package/dist/vite.cjs +320 -60
  124. package/dist/vite.cjs.map +1 -1
  125. package/dist/vite.d.cts +54 -8
  126. package/dist/vite.d.ts +54 -8
  127. package/dist/vite.mjs +312 -54
  128. package/dist/vite.mjs.map +1 -1
  129. package/dist/work-events-BlOVpK0k.d.ts +547 -0
  130. package/dist/work-events-D97EoqvS.d.cts +547 -0
  131. package/package.json +19 -2
  132. package/schema/extension-v2.json +440 -121
  133. package/dist/chunk-2DBSVKAU.cjs.map +0 -1
  134. package/dist/chunk-3YWVYA42.cjs.map +0 -1
  135. package/dist/chunk-4C5Z3CIK.mjs.map +0 -1
  136. package/dist/chunk-5AAPD5WV.cjs.map +0 -1
  137. package/dist/chunk-7KIKOH5H.cjs.map +0 -1
  138. package/dist/chunk-BDCX6LRQ.mjs.map +0 -1
  139. package/dist/chunk-CSTYBKZC.mjs.map +0 -1
  140. package/dist/chunk-IGK2AP6J.mjs.map +0 -1
  141. package/dist/chunk-MNDVYPEP.mjs.map +0 -1
  142. package/dist/chunk-OPPYEA7F.cjs.map +0 -1
  143. package/dist/chunk-PYJMJF44.cjs.map +0 -1
  144. package/dist/chunk-RMUWRESK.cjs.map +0 -1
  145. package/dist/chunk-ZT35X7KL.mjs.map +0 -1
  146. package/dist/handler-CZIlZ5vu.d.ts +0 -227
  147. package/dist/handler-kU9Jf36K.d.cts +0 -227
  148. package/dist/styles.css +0 -367
@@ -1,775 +1,42 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunk5AAPD5WVcjs = require('../chunk-5AAPD5WV.cjs');
5
4
 
5
+ var _chunkO357OJXLcjs = require('../chunk-O357OJXL.cjs');
6
6
 
7
- var _chunk7KIKOH5Hcjs = require('../chunk-7KIKOH5H.cjs');
8
- require('../chunk-OPPYEA7F.cjs');
9
7
 
10
8
 
11
9
 
12
10
 
13
11
 
14
- var _chunkRMUWRESKcjs = require('../chunk-RMUWRESK.cjs');
15
12
 
16
13
 
17
14
 
18
15
 
19
- var _chunkPYJMJF44cjs = require('../chunk-PYJMJF44.cjs');
20
16
 
21
17
 
22
18
 
23
19
 
24
- var _chunk3YWVYA42cjs = require('../chunk-3YWVYA42.cjs');
25
20
 
26
21
 
22
+ var _chunkBPCGXXMDcjs = require('../chunk-BPCGXXMD.cjs');
27
23
 
28
- var _chunk2DBSVKAUcjs = require('../chunk-2DBSVKAU.cjs');
29
24
 
30
- // src/testing/client.ts
31
25
 
26
+ var _chunkGAUZYBXEcjs = require('../chunk-GAUZYBXE.cjs');
32
27
 
33
28
 
29
+ var _chunkVV7ELNRWcjs = require('../chunk-VV7ELNRW.cjs');
30
+ require('../chunk-PRCZMOLD.cjs');
34
31
 
35
- var _jose = require('jose');
36
32
 
37
- // src/testing/envelope.ts
38
- var DEFAULT_FILTERS = {
39
- range: { from: "2026-09-01", to: "2026-09-08", preset: "7d" },
40
- platform: "all",
41
- country: "all"
42
- };
43
- function callEnvelope(envelope) {
44
- const context = {
45
- projectId: envelope.install.projectId,
46
- platform: envelope.filters.platform,
47
- from: envelope.filters.range.from,
48
- to: envelope.filters.range.to,
49
- filters: envelope.filters
50
- };
51
- return JSON.stringify({
52
- install: envelope.install,
53
- context,
54
- input: envelope.input,
55
- credentials: _nullishCoalesce(envelope.credentials, () => ( {})),
56
- documents: _nullishCoalesce(envelope.documents, () => ( {})),
57
- event: envelope.event
58
- });
59
- }
60
- function parseJson(text) {
61
- try {
62
- return { parsed: true, value: JSON.parse(text) };
63
- } catch (e) {
64
- return { parsed: false, value: void 0 };
65
- }
66
- }
67
- async function readEnvelopeResponse(response, call) {
68
- const text = await response.text();
69
- const body = parseJson(text);
70
- const status = String(response.status);
71
- if (response.ok) {
72
- if (body.parsed) return body.value;
73
- if (text.trim() === "") return void 0;
74
- throw new (0, _chunk2DBSVKAUcjs.TapServerError)(
75
- _chunkRMUWRESKcjs.SERVER_ERROR_CODES.INTERNAL_ERROR,
76
- `The extension server answered ${status} for ${call} with a body that is not JSON. Every Tappify route answers JSON, or 204 with no body.`,
77
- response.status
78
- );
79
- }
80
- const error = _chunkRMUWRESKcjs.readRecord.call(void 0, body.value, "error");
81
- throw new (0, _chunk2DBSVKAUcjs.TapServerError)(
82
- _nullishCoalesce(_chunkRMUWRESKcjs.readText.call(void 0, error, "code"), () => ( _chunkRMUWRESKcjs.SERVER_ERROR_CODES.INTERNAL_ERROR)),
83
- _nullishCoalesce(_chunkRMUWRESKcjs.readText.call(void 0, error, "message"), () => ( `The extension server answered ${status} for ${call} without a JSON error body.`)),
84
- response.status
85
- );
86
- }
33
+ var _chunkEB5XWQAUcjs = require('../chunk-EB5XWQAU.cjs');
34
+ require('../chunk-A74HCO6T.cjs');
87
35
 
88
- // src/testing/client.ts
89
- var TEST_KID = "tappify-test-key";
90
- var TEST_ISSUER = "https://api.tappify.ai";
91
- var keys = null;
92
- function ensureKeys() {
93
- _nullishCoalesce(keys, () => ( (keys = (async () => {
94
- const pair = await _jose.generateKeyPair.call(void 0, "RS256", { extractable: true });
95
- const publicJwk = await _jose.exportJWK.call(void 0, pair.publicKey);
96
- return {
97
- privateKey: pair.privateKey,
98
- jwks: {
99
- keys: [{ ...publicJwk, kid: TEST_KID, alg: "RS256", use: "sig" }]
100
- }
101
- };
102
- })())));
103
- return keys;
104
- }
105
- async function testJwks() {
106
- return (await ensureKeys()).jwks;
107
- }
108
- async function signTestToken(claims = {}, options = {}) {
109
- const { privateKey } = await ensureKeys();
110
- const extensionId = _nullishCoalesce(_nullishCoalesce(options.extensionId, () => ( claims.extensionId)), () => ( "starter"));
111
- return new (0, _jose.SignJWT)({
112
- installId: _nullishCoalesce(claims.installId, () => ( "ins_test")),
113
- extensionId,
114
- projectId: _nullishCoalesce(claims.projectId, () => ( "prj_north")),
115
- organizationId: _nullishCoalesce(claims.organizationId, () => ( "org_test")),
116
- scopes: _nullishCoalesce(claims.scopes, () => ( [])),
117
- ...claims.userId === void 0 ? {} : { userId: claims.userId }
118
- }).setProtectedHeader({ alg: "RS256", kid: TEST_KID }).setIssuer(TEST_ISSUER).setAudience(`ext:${extensionId}`).setIssuedAt().setExpirationTime(_nullishCoalesce(options.expiresIn, () => ( "5m"))).sign(privateKey);
119
- }
120
- var HEALTH_PATH = "/tappify/health";
121
- function createTestClient(target, defaults = {}) {
122
- if (typeof target === "function") {
123
- throw new (0, _chunk2DBSVKAUcjs.TapError)(
124
- "TAP_TEST_TARGET_INVALID",
125
- "createTestClient() was handed a built handler instead of the options object. A handler from createTappifyHandler() verifies install tokens against the live Tappify key set, so every call the test client makes would come back 401. Pass the options themselves \u2014 createTestClient(handlerOptions) \u2014 or, when you need the handler, build it with createTappifyHandler({ ...handlerOptions, jwks: await testJwks() }) and drive it through createTapMock({ handler, extensionId: handlerOptions.extensionId }) so the test token carries the audience the handler expects."
126
- );
127
- }
128
- const extensionId = target.extensionId;
129
- const handlerPromise = testJwks().then(
130
- (jwks) => _chunkRMUWRESKcjs.createTappifyHandler.call(void 0, { ...target, jwks })
131
- );
132
- const install = {
133
- id: "ins_test",
134
- extensionId,
135
- projectId: "prj_north",
136
- organizationId: "org_test",
137
- ...defaults.install
138
- };
139
- const filters = _nullishCoalesce(defaults.filters, () => ( DEFAULT_FILTERS));
140
- const origin = _nullishCoalesce(defaults.origin, () => ( "https://vendor.test"));
141
- let sent = 0;
142
- function envelope(input, event) {
143
- return callEnvelope({
144
- install,
145
- filters,
146
- input,
147
- credentials: defaults.credentials,
148
- documents: defaults.documents,
149
- event
150
- });
151
- }
152
- async function send(method, path, body) {
153
- const handler = await handlerPromise;
154
- sent += 1;
155
- const headers = new Headers({
156
- "content-type": "application/json",
157
- "x-tappify-event-id": _nullishCoalesce(defaults.eventId, () => ( `evt_${path}_${String(sent)}`))
158
- });
159
- if (path !== HEALTH_PATH) {
160
- const token = await signTestToken(
161
- {
162
- installId: install.id,
163
- extensionId: install.extensionId,
164
- projectId: install.projectId,
165
- organizationId: install.organizationId,
166
- scopes: _nullishCoalesce(defaults.scopes, () => ( []))
167
- },
168
- { extensionId }
169
- );
170
- headers.set("authorization", `Bearer ${token}`);
171
- }
172
- return handler(
173
- new Request(`${origin}${path}`, {
174
- method,
175
- headers,
176
- ...body === void 0 ? {} : { body }
177
- })
178
- );
179
- }
180
- async function call(method, path, body) {
181
- return readEnvelopeResponse(
182
- await send(method, path, body),
183
- `${method} ${path}`
184
- );
185
- }
186
- return {
187
- health: async () => await call("GET", HEALTH_PATH),
188
- metrics: async (input) => await call(
189
- "POST",
190
- "/tappify/metrics",
191
- envelope(input)
192
- ),
193
- tool: (id, input) => call("POST", `/tappify/tools/${id}`, envelope(input)),
194
- mention: async (id, query) => await call(
195
- "GET",
196
- `/tappify/mentions/${id}?q=${encodeURIComponent(query)}`
197
- ),
198
- action: (id, input) => call("POST", `/tappify/actions/${id}`, envelope(input)),
199
- procedure: (name, input = {}) => call("POST", `/tappify/procedures/${name}`, envelope(input)),
200
- context: async (id) => await call("GET", `/tappify/context/${id}`),
201
- event: async (name, payload) => {
202
- await call("POST", "/tappify/events", envelope({}, { name, payload }));
203
- },
204
- work: (operation, input) => call("POST", `/tappify/work/${operation}`, envelope(input)),
205
- raw: (method, path, body) => send(method, path, body === void 0 ? void 0 : JSON.stringify(body))
206
- };
207
- }
208
36
 
209
- // src/testing/fixtures.ts
210
- var fixtureApps = [
211
- {
212
- id: "app_ios",
213
- name: "Northlight",
214
- platform: "ios",
215
- storeId: "1490000001",
216
- bundleId: "ai.tappify.northlight"
217
- },
218
- {
219
- id: "app_android",
220
- name: "Northlight",
221
- platform: "android",
222
- storeId: "ai.tappify.northlight",
223
- bundleId: "ai.tappify.northlight"
224
- }
225
- ];
226
- var fixtureReleases = [
227
- {
228
- id: "rel_42",
229
- version: "4.2.0",
230
- build: "118",
231
- platform: "ios",
232
- state: "ready_for_sale",
233
- shippedAt: "2026-09-01T09:00:00.000Z"
234
- },
235
- {
236
- id: "rel_41",
237
- version: "4.1.0",
238
- build: "107",
239
- platform: "ios",
240
- state: "ready_for_sale",
241
- shippedAt: "2026-08-11T09:00:00.000Z"
242
- },
243
- {
244
- id: "rel_a42",
245
- version: "4.2.0",
246
- build: "4200",
247
- platform: "android",
248
- state: "published",
249
- shippedAt: "2026-09-02T09:00:00.000Z"
250
- }
251
- ];
252
- var fixtureKeywords = [
253
- {
254
- id: "kw_1",
255
- term: "photo editor",
256
- platform: "ios",
257
- country: "US",
258
- position: 4,
259
- popularity: 6.6
260
- },
261
- {
262
- id: "kw_2",
263
- term: "collage maker",
264
- platform: "ios",
265
- country: "US",
266
- position: 11,
267
- popularity: 5.3
268
- },
269
- {
270
- id: "kw_3",
271
- term: "photo editor",
272
- platform: "android",
273
- country: "US",
274
- position: 7,
275
- popularity: 6
276
- }
277
- ];
278
- var fixtureListings = [
279
- {
280
- platform: "ios",
281
- country: "US",
282
- locale: "en-US",
283
- title: "Northlight \u2014 Photo Editor",
284
- subtitle: "Edit, collage, share",
285
- description: "Northlight turns a camera roll into a finished post.",
286
- keywords: ["photo", "editor", "collage"],
287
- updatedAt: "2026-08-28T12:00:00.000Z"
288
- }
289
- ];
290
- var fixtureProject = {
291
- project: {
292
- id: "prj_north",
293
- name: "Northlight",
294
- platforms: ["ios", "android"]
295
- },
296
- apps: fixtureApps,
297
- releases: fixtureReleases
298
- };
299
- var SERIES_VALUES = {
300
- downloads: [1180, 1240, 1310, 1290, 1402, 1512, 1488],
301
- impressions: [21400, 22150, 22980, 22110, 24020, 25510, 25010],
302
- page_views: [8120, 8340, 8710, 8290, 9110, 9640, 9420],
303
- conversion_rate: [0.145, 0.149, 0.15, 0.156, 0.152, 0.157, 0.158]
304
- };
305
- function week() {
306
- return [
307
- "2026-09-01",
308
- "2026-09-02",
309
- "2026-09-03",
310
- "2026-09-04",
311
- "2026-09-05",
312
- "2026-09-06",
313
- "2026-09-07"
314
- ];
315
- }
316
- function fixtureSeries(metric) {
317
- const points = week().map((at, index) => ({
318
- at,
319
- value: SERIES_VALUES[metric][index]
320
- }));
321
- return {
322
- metric,
323
- unit: metric === "conversion_rate" ? "ratio" : "count",
324
- points
325
- };
326
- }
327
- var fixtureReviews = {
328
- total: 3,
329
- averageRating: 3.7,
330
- reviews: [
331
- {
332
- id: "rev_1",
333
- platform: "ios",
334
- country: "US",
335
- rating: 5,
336
- title: "Fast and clean",
337
- body: "The new collage layouts are exactly what I wanted.",
338
- author: "kbrady",
339
- submittedAt: "2026-09-05T18:22:00.000Z",
340
- replied: false
341
- },
342
- {
343
- id: "rev_2",
344
- platform: "ios",
345
- country: "GB",
346
- rating: 2,
347
- title: "Crashes on export",
348
- body: "Since 4.2 the export button closes the app.",
349
- author: null,
350
- submittedAt: "2026-09-04T08:10:00.000Z",
351
- replied: true
352
- },
353
- {
354
- id: "rev_3",
355
- platform: "android",
356
- country: "DE",
357
- rating: 4,
358
- title: null,
359
- body: "Gute App, aber der Export dauert lange.",
360
- author: "mgruber",
361
- submittedAt: "2026-09-03T16:45:00.000Z",
362
- replied: false
363
- }
364
- ]
365
- };
366
- var fixtureCrashes = {
367
- crashFreeRate: 99.42,
368
- issues: [
369
- {
370
- id: "crash_1",
371
- title: "ExportSession.finish \u2014 index out of range",
372
- count: 214,
373
- build: "118",
374
- firstSeenAt: "2026-09-01T11:02:00.000Z",
375
- lastSeenAt: "2026-09-07T21:40:00.000Z"
376
- },
377
- {
378
- id: "crash_2",
379
- title: "PhotoLibrary.load \u2014 permission revoked",
380
- count: 37,
381
- build: "118",
382
- firstSeenAt: "2026-09-02T07:15:00.000Z",
383
- lastSeenAt: "2026-09-06T13:05:00.000Z"
384
- }
385
- ]
386
- };
387
- var fixtureRevenue = {
388
- currency: "USD",
389
- mrr: 41200,
390
- refunds: 18,
391
- points: week().map((at, index) => ({
392
- at,
393
- value: [1310, 1355, 1401, 1388, 1470, 1525, 1502][index]
394
- }))
395
- };
396
- var fixtures = {
397
- project: fixtureProject,
398
- apps: fixtureApps,
399
- releases: fixtureReleases,
400
- keywords: fixtureKeywords,
401
- listings: fixtureListings,
402
- reviews: fixtureReviews,
403
- crashes: fixtureCrashes,
404
- revenue: fixtureRevenue,
405
- series: fixtureSeries
406
- };
407
- function answerFixtureQuery(query) {
408
- switch (query.kind) {
409
- case "project":
410
- return structuredClone(fixtureProject);
411
- case "series":
412
- return structuredClone(fixtureSeries(query.metric));
413
- case "keywords":
414
- return structuredClone({ keywords: fixtureKeywords });
415
- case "listing":
416
- return structuredClone({ listings: fixtureListings });
417
- case "reviews":
418
- return structuredClone(fixtureReviews);
419
- case "crashes":
420
- return structuredClone(fixtureCrashes);
421
- case "revenue":
422
- return structuredClone(fixtureRevenue);
423
- }
424
- }
425
-
426
- // src/testing/mock.ts
427
- var SINGLETON_ID = "singleton";
428
- var PROBE_KEYS = /* @__PURE__ */ new Set([
429
- "then",
430
- "toJSON",
431
- "$$typeof",
432
- "constructor",
433
- "prototype",
434
- "valueOf",
435
- "toString",
436
- "inspect",
437
- "asymmetricMatch",
438
- "nodeType"
439
- ]);
440
- function unknownCollectionError(collection) {
441
- return new (0, _chunk2DBSVKAUcjs.TapError)(
442
- "TAP_UNKNOWN_COLLECTION",
443
- `This mock exposes no storage collection called "${collection}". createTapMock({ storage: \u2026 }) was given an explicit map, so only the collections it names exist. Add "${collection}" to that map, or drop the storage option to expose every collection.`
444
- );
445
- }
446
- function singletonView(handle) {
447
- return {
448
- get: () => handle.get(),
449
- set: (document2) => handle.set(document2),
450
- patch: (partial) => handle.patch(partial)
451
- };
452
- }
453
- function collectionView(handle) {
454
- return {
455
- list: (listOptions) => handle.list(listOptions),
456
- get: (id) => handle.get(id),
457
- put: (id, document2) => handle.put(id, document2),
458
- delete: (id) => handle.delete(id)
459
- };
460
- }
461
- function scopeError(scope) {
462
- return new (0, _chunk2DBSVKAUcjs.TapError)(
463
- "TAP_SCOPE_MISSING",
464
- `This install has not granted ${scope}. Declare it under "scopes" in tappify.extension.json, or pass scopes: ["${scope}"] to renderWithTap() to test the granted path.`
465
- );
466
- }
467
- function asObject(value) {
468
- return typeof value === "object" && value !== null ? value : {};
469
- }
470
- function createTapMock(options = {}) {
471
- const granted = new Set(_nullishCoalesce(options.scopes, () => ( _chunkPYJMJF44cjs.SCOPE_KEYS)));
472
- const listeners = /* @__PURE__ */ new Map();
473
- const eventHandlers = /* @__PURE__ */ new Map();
474
- const state = /* @__PURE__ */ new Map();
475
- const store = /* @__PURE__ */ new Map();
476
- const portal = document.createElement("div");
477
- portal.dataset.tapPortal = "true";
478
- const calls = {
479
- navigations: [],
480
- searches: [],
481
- toasts: [],
482
- confirms: [],
483
- actions: [],
484
- telemetry: [],
485
- chats: [],
486
- externals: [],
487
- downloads: [],
488
- copies: [],
489
- cards: [],
490
- expands: 0,
491
- settingsOpens: 0
492
- };
493
- const emitChange = (key) => {
494
- for (const listener of _nullishCoalesce(listeners.get(key), () => ( []))) listener();
495
- };
496
- const subscribe = (key, listener) => {
497
- const set = _nullishCoalesce(listeners.get(key), () => ( /* @__PURE__ */ new Set()));
498
- set.add(listener);
499
- listeners.set(key, set);
500
- return () => {
501
- set.delete(listener);
502
- };
503
- };
504
- const withStorage = (run) => granted.has("storage:write") ? Promise.resolve(run()) : Promise.reject(scopeError("storage:write"));
505
- const bucket = (collection) => {
506
- const existing = store.get(collection);
507
- if (existing) return existing;
508
- const created = [];
509
- store.set(collection, created);
510
- return created;
511
- };
512
- function buildHandle(collection) {
513
- const find = (id) => bucket(collection).find((entry) => entry.id === id);
514
- const write = (id, data) => {
515
- const items = bucket(collection);
516
- const index = items.findIndex((entry) => entry.id === id);
517
- if (index === -1) items.push({ id, data });
518
- else items[index] = { id, data };
519
- emitChange(`storage:${collection}`);
520
- };
521
- return {
522
- get: (id) => withStorage(() => _nullishCoalesce(_optionalChain([find, 'call', _ => _(_nullishCoalesce(id, () => ( SINGLETON_ID))), 'optionalAccess', _2 => _2.data]), () => ( null))),
523
- set: (document2) => withStorage(() => {
524
- write(SINGLETON_ID, document2);
525
- }),
526
- patch: (partial) => withStorage(() => {
527
- const merged = { ...asObject(_optionalChain([find, 'call', _3 => _3(SINGLETON_ID), 'optionalAccess', _4 => _4.data])), ...partial };
528
- write(SINGLETON_ID, merged);
529
- return merged;
530
- }),
531
- list: () => withStorage(() => ({
532
- items: bucket(collection).filter((entry) => entry.id !== SINGLETON_ID).map((entry) => ({ ...asObject(entry.data), id: entry.id }))
533
- })),
534
- put: (id, document2) => withStorage(() => {
535
- write(id, document2);
536
- }),
537
- delete: (id) => withStorage(() => {
538
- const items = bucket(collection);
539
- const index = items.findIndex((entry) => entry.id === id);
540
- if (index !== -1) {
541
- items.splice(index, 1);
542
- emitChange(`storage:${collection}`);
543
- }
544
- })
545
- };
546
- }
547
- const handles = /* @__PURE__ */ new Map();
548
- const kinds = options.storage;
549
- const exposeHandle = (collection) => {
550
- const kind = _optionalChain([kinds, 'optionalAccess', _5 => _5[collection]]);
551
- if (kinds !== void 0 && kind === void 0) {
552
- throw unknownCollectionError(collection);
553
- }
554
- const handle = buildHandle(collection);
555
- if (kind === "singleton") return singletonView(handle);
556
- if (kind === "collection") return collectionView(handle);
557
- return handle;
558
- };
559
- const handleFor = (collection) => {
560
- if (PROBE_KEYS.has(collection)) return void 0;
561
- const existing = handles.get(collection);
562
- if (existing) return existing;
563
- const created = exposeHandle(collection);
564
- handles.set(collection, created);
565
- return created;
566
- };
567
- const storageTarget = {};
568
- const storage = new Proxy(storageTarget, {
569
- get: (_target, property) => typeof property === "string" ? handleFor(property) : void 0,
570
- has: () => true,
571
- ownKeys: () => [...store.keys()],
572
- getOwnPropertyDescriptor: () => ({ enumerable: true, configurable: true })
573
- });
574
- let calledProcedures = 0;
575
- let signedToken = null;
576
- function handlerToken() {
577
- if (options.handlerToken !== void 0) {
578
- return Promise.resolve(options.handlerToken);
579
- }
580
- _nullishCoalesce(signedToken, () => ( (signedToken = signTestToken(
581
- {
582
- installId: tap.extension.installId,
583
- extensionId: tap.extension.id,
584
- projectId: tap.extension.projectId,
585
- organizationId: tap.auth.organizationId,
586
- scopes: [...granted]
587
- },
588
- { extensionId: tap.extension.id }
589
- ))));
590
- return signedToken;
591
- }
592
- async function callProcedure(name, input) {
593
- const local = _optionalChain([options, 'access', _6 => _6.server, 'optionalAccess', _7 => _7[name]]);
594
- if (local) return local(input);
595
- if (options.handler) {
596
- const path = `/tappify/procedures/${name}`;
597
- calledProcedures += 1;
598
- const response = await options.handler(
599
- new Request(`https://vendor.test${path}`, {
600
- method: "POST",
601
- headers: {
602
- "content-type": "application/json",
603
- "x-tappify-event-id": `evt_${name}_${String(calledProcedures)}`,
604
- authorization: `Bearer ${await handlerToken()}`
605
- },
606
- body: callEnvelope({
607
- install: {
608
- id: tap.extension.installId,
609
- extensionId: tap.extension.id,
610
- projectId: tap.extension.projectId,
611
- organizationId: tap.auth.organizationId
612
- },
613
- filters: tap.filters,
614
- input
615
- })
616
- })
617
- );
618
- return readEnvelopeResponse(response, `POST ${path}`);
619
- }
620
- throw new (0, _chunk2DBSVKAUcjs.TapError)(
621
- "TAP_UNKNOWN_PROCEDURE",
622
- `No handler is registered for the procedure "${name}". Pass server: { ${name}: input => \u2026 } or handler: <your createTappifyHandler handler> to createTapMock().`
623
- );
624
- }
625
- const serverTarget = {};
626
- const tap = {
627
- extension: {
628
- id: _nullishCoalesce(options.extensionId, () => ( "starter")),
629
- name: _nullishCoalesce(options.extensionName, () => ( "Starter")),
630
- installId: _nullishCoalesce(options.installId, () => ( "ins_test")),
631
- projectId: "prj_north"
632
- },
633
- env: "dev",
634
- host: { version: "test", sdkMajors: [2] },
635
- auth: {
636
- token: "test-token",
637
- user: { id: "usr_test", role: "admin" },
638
- organizationId: "org_test",
639
- scopes: [...granted],
640
- can: (scope) => granted.has(scope)
641
- },
642
- project: {
643
- id: "prj_north",
644
- name: "Northlight",
645
- platforms: ["ios", "android"],
646
- apps: [],
647
- releases: [],
648
- keywords: [],
649
- ...options.project
650
- },
651
- filters: { ...DEFAULT_FILTERS, ...options.filters },
652
- theme: { mode: _nullishCoalesce(options.theme, () => ( "light")) },
653
- locale: "en-US",
654
- timezone: "UTC",
655
- format: {
656
- number: (value, formatOptions) => new Intl.NumberFormat("en-US", formatOptions).format(value),
657
- currency: (value, code) => new Intl.NumberFormat("en-US", {
658
- style: "currency",
659
- currency: code
660
- }).format(value),
661
- date: (value) => new Date(value).toISOString().slice(0, 10),
662
- relative: (value) => new Date(value).toISOString()
663
- },
664
- nav: {
665
- push: (path) => calls.navigations.push(path),
666
- setSearch: (params) => calls.searches.push(params),
667
- openSettings: () => {
668
- calls.settingsOpens += 1;
669
- },
670
- openChat: (prompt, context) => calls.chats.push({ prompt, context }),
671
- openExternal: (url) => calls.externals.push(url)
672
- },
673
- data: {
674
- query: (query) => {
675
- const scope = _chunkPYJMJF44cjs.QUERY_SCOPES[query.kind];
676
- if (!granted.has(scope)) return Promise.reject(scopeError(scope));
677
- return Promise.resolve(answerFixtureQuery(query));
678
- },
679
- subscribe: (event, handler) => {
680
- const key = String(event);
681
- const set = _nullishCoalesce(eventHandlers.get(key), () => ( /* @__PURE__ */ new Set()));
682
- const wrapped = (payload) => {
683
- handler(payload);
684
- };
685
- set.add(wrapped);
686
- eventHandlers.set(key, set);
687
- return () => {
688
- set.delete(wrapped);
689
- };
690
- }
691
- },
692
- server: new Proxy(serverTarget, {
693
- get: (_target, property) => (input) => callProcedure(String(property), input),
694
- has: () => true
695
- }),
696
- state: {
697
- get: (key) => {
698
- const value = state.get(key);
699
- return value === void 0 ? void 0 : value;
700
- },
701
- set: (key, value) => {
702
- state.set(key, value);
703
- emitChange(`state:${key}`);
704
- },
705
- subscribe: (key, handler) => subscribe(`state:${key}`, handler)
706
- },
707
- ui: {
708
- size: _nullishCoalesce(options.size, () => ( "slot")),
709
- toast: (message, tone = "neutral") => calls.toasts.push({ message, tone }),
710
- confirm: (confirmOptions) => {
711
- calls.confirms.push(confirmOptions);
712
- return Promise.resolve(_nullishCoalesce(options.confirmAnswer, () => ( true)));
713
- },
714
- openInChat: (card) => calls.cards.push(card),
715
- expand: () => {
716
- calls.expands += 1;
717
- },
718
- download: (blob, filename) => calls.downloads.push({ filename, size: blob.size }),
719
- copy: (text) => {
720
- calls.copies.push(text);
721
- return Promise.resolve();
722
- }
723
- },
724
- context: _nullishCoalesce(options.context, () => ( {})),
725
- params: _nullishCoalesce(options.params, () => ( {})),
726
- storage,
727
- telemetry: {
728
- event: (name, props) => calls.telemetry.push({ name, props })
729
- },
730
- actions: {
731
- run: (actionId, input) => {
732
- calls.actions.push({ actionId, input });
733
- return Promise.resolve({
734
- id: `run_${String(calls.actions.length)}`,
735
- actionId,
736
- status: "pending",
737
- requestedAt: (/* @__PURE__ */ new Date(0)).toISOString()
738
- });
739
- }
740
- },
741
- invalidate: () => void 0,
742
- __portal: portal,
743
- __subscribe: subscribe
744
- };
745
- return {
746
- tap,
747
- calls,
748
- portal,
749
- documents: (collection, documentId) => bucket(collection).filter((entry) => documentId === void 0 || entry.id === documentId).map((entry) => entry.data),
750
- emit: (event, payload) => {
751
- for (const handler of _nullishCoalesce(eventHandlers.get(String(event)), () => ( []))) {
752
- handler(payload);
753
- }
754
- },
755
- setFilters: (filters) => {
756
- tap.filters = filters;
757
- emitChange("filters");
758
- },
759
- setSize: (size) => {
760
- tap.ui = { ...tap.ui, size };
761
- emitChange("size");
762
- },
763
- setTheme: (mode) => {
764
- tap.theme = { mode };
765
- emitChange("theme");
766
- },
767
- setParams: (params) => {
768
- tap.params = params;
769
- emitChange("params");
770
- }
771
- };
772
- }
37
+ var _chunk7YKH4LZNcjs = require('../chunk-7YKH4LZN.cjs');
38
+ require('../chunk-6HETNZJY.cjs');
39
+ require('../chunk-Q7SFCCGT.cjs');
773
40
 
774
41
  // src/testing/render.tsx
775
42
  var _reactquery = require('@tanstack/react-query');
@@ -778,18 +45,18 @@ var _reactquery = require('@tanstack/react-query');
778
45
  var _react = require('@testing-library/react');
779
46
  var _jsxruntime = require('react/jsx-runtime');
780
47
  function renderWithTap(ui, options = {}) {
781
- const mock = _nullishCoalesce(options.mock, () => ( createTapMock(options)));
48
+ const mock = _nullishCoalesce(options.mock, () => ( _chunkBPCGXXMDcjs.createTapMock.call(void 0, options)));
782
49
  const queryClient = _nullishCoalesce(options.queryClient, () => ( new (0, _reactquery.QueryClient)({
783
50
  defaultOptions: { queries: { retry: false, gcTime: 0 } }
784
51
  })));
785
52
  const installId = mock.tap.extension.installId;
786
53
  mock.tap.invalidate = (name) => {
787
54
  void queryClient.invalidateQueries({
788
- queryKey: name === void 0 ? _chunk5AAPD5WVcjs.installPrefix.call(void 0, installId) : _chunk5AAPD5WVcjs.procedurePrefix.call(void 0, installId, name)
55
+ queryKey: name === void 0 ? _chunkGAUZYBXEcjs.installPrefix.call(void 0, installId) : _chunkGAUZYBXEcjs.procedurePrefix.call(void 0, installId, name)
789
56
  });
790
57
  };
791
58
  function Wrapper({ children }) {
792
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7KIKOH5Hcjs.TapHostProvider, { tap: mock.tap, children }) });
59
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _reactquery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVV7ELNRWcjs.TapHostProvider, { tap: mock.tap, children }) });
793
60
  }
794
61
  const result = _react.render.call(void 0, ui, { wrapper: Wrapper, container: options.container });
795
62
  result.baseElement.append(mock.portal);
@@ -808,7 +75,7 @@ function isPoint(value) {
808
75
  return pair !== null && pair.length === 2 && typeof pair[0] === "string" && typeof pair[1] === "number";
809
76
  }
810
77
  function validateMetricsResponse(response, metrics) {
811
- const series = list(_optionalChain([record, 'call', _8 => _8(response), 'optionalAccess', _9 => _9.series]));
78
+ const series = list(_optionalChain([record, 'call', _ => _(response), 'optionalAccess', _2 => _2.series]));
812
79
  if (series === null) {
813
80
  return [
814
81
  'A metrics response is { "series": [...] }. Return one entry per declared metric, even when it has no points.'
@@ -818,7 +85,7 @@ function validateMetricsResponse(response, metrics) {
818
85
  const declared = new Map(metrics.map((metric) => [metric.key, metric]));
819
86
  for (const [index, entry] of series.entries()) {
820
87
  const item = record(entry);
821
- const key = typeof _optionalChain([item, 'optionalAccess', _10 => _10.metric]) === "string" ? item.metric : null;
88
+ const key = typeof _optionalChain([item, 'optionalAccess', _3 => _3.metric]) === "string" ? item.metric : null;
822
89
  if (item === null || key === null) {
823
90
  issues.push(`series[${String(index)}] has no "metric" key.`);
824
91
  continue;
@@ -857,11 +124,67 @@ function validateToolResponse(value, returns) {
857
124
  `A "${returns}" tool returns an object the host draws as a card, not ${typeof value}.`
858
125
  ];
859
126
  }
860
- return _chunkPYJMJF44cjs.CARD_KEYS[returns].filter((key) => !(key in body)).map(
127
+ return _chunk7YKH4LZNcjs.CARD_KEYS[returns].filter((key) => !(key in body)).map(
861
128
  (key) => `A "${returns}" tool response needs a "${key}" key; the host draws the card from it.`
862
129
  );
863
130
  }
864
131
 
132
+ // src/testing/work-events.ts
133
+ function workCommentCreatedFixture(overrides = {}) {
134
+ return {
135
+ type: "comment.created",
136
+ externalItemId: "item_test",
137
+ providerEventId: "event_comment_test",
138
+ occurredAt: "2026-10-15T12:00:00.000Z",
139
+ dedupeKey: "item_test:event_comment_test",
140
+ comment: {
141
+ externalCommentId: "comment_test",
142
+ body: "A provider comment.",
143
+ author: { id: "author_test", displayName: "Sam" },
144
+ createdAt: "2026-10-15T12:00:00.000Z"
145
+ },
146
+ ...overrides
147
+ };
148
+ }
149
+ function workStatusChangedFixture(overrides = {}) {
150
+ return {
151
+ type: "status.changed",
152
+ externalItemId: "item_test",
153
+ providerEventId: "event_status_test",
154
+ occurredAt: "2026-10-15T12:00:00.000Z",
155
+ dedupeKey: "item_test:event_status_test",
156
+ status: { id: "resolved_test", label: "Resolved", stage: "done" },
157
+ ...overrides
158
+ };
159
+ }
160
+ function workItemDeletedFixture(overrides = {}) {
161
+ return {
162
+ type: "item.deleted",
163
+ externalItemId: "item_test",
164
+ providerEventId: "event_deleted_test",
165
+ occurredAt: "2026-10-15T12:00:00.000Z",
166
+ dedupeKey: "item_test:event_deleted_test",
167
+ ...overrides
168
+ };
169
+ }
170
+ async function signedWorkEventRequest(event, options) {
171
+ let request;
172
+ await _chunkEB5XWQAUcjs.sendWorkEvent.call(void 0, event, {
173
+ ...options,
174
+ fetch: (input, init) => {
175
+ request = new Request(input, init);
176
+ return Promise.resolve(new Response(null, { status: 202 }));
177
+ }
178
+ });
179
+ if (!request)
180
+ throw new Error("The work event sender did not produce a request.");
181
+ return request;
182
+ }
183
+
184
+
185
+
186
+
187
+
865
188
 
866
189
 
867
190
 
@@ -883,5 +206,5 @@ function validateToolResponse(value, returns) {
883
206
 
884
207
 
885
208
 
886
- exports.answerFixtureQuery = answerFixtureQuery; exports.createTapMock = createTapMock; exports.createTestClient = createTestClient; exports.fixtureApps = fixtureApps; exports.fixtureCrashes = fixtureCrashes; exports.fixtureKeywords = fixtureKeywords; exports.fixtureListings = fixtureListings; exports.fixtureProject = fixtureProject; exports.fixtureReleases = fixtureReleases; exports.fixtureRevenue = fixtureRevenue; exports.fixtureReviews = fixtureReviews; exports.fixtureSeries = fixtureSeries; exports.fixtures = fixtures; exports.installHostTheme = _chunk3YWVYA42cjs.installHostTheme; exports.registerTapMatchers = _chunk3YWVYA42cjs.registerTapMatchers; exports.renderWithTap = renderWithTap; exports.signTestToken = signTestToken; exports.tapMatchers = _chunk3YWVYA42cjs.tapMatchers; exports.testJwks = testJwks; exports.validateMetricsResponse = validateMetricsResponse; exports.validateToolResponse = validateToolResponse;
209
+ exports.answerFixtureQuery = _chunkBPCGXXMDcjs.answerFixtureQuery; exports.createTapMock = _chunkBPCGXXMDcjs.createTapMock; exports.createTestClient = _chunkBPCGXXMDcjs.createTestClient; exports.fixtureApps = _chunkBPCGXXMDcjs.fixtureApps; exports.fixtureCrashes = _chunkBPCGXXMDcjs.fixtureCrashes; exports.fixtureKeywords = _chunkBPCGXXMDcjs.fixtureKeywords; exports.fixtureListings = _chunkBPCGXXMDcjs.fixtureListings; exports.fixtureProject = _chunkBPCGXXMDcjs.fixtureProject; exports.fixtureReleases = _chunkBPCGXXMDcjs.fixtureReleases; exports.fixtureRevenue = _chunkBPCGXXMDcjs.fixtureRevenue; exports.fixtureReviews = _chunkBPCGXXMDcjs.fixtureReviews; exports.fixtureSeries = _chunkBPCGXXMDcjs.fixtureSeries; exports.fixtures = _chunkBPCGXXMDcjs.fixtures; exports.installHostTheme = _chunkO357OJXLcjs.installHostTheme; exports.registerTapMatchers = _chunkO357OJXLcjs.registerTapMatchers; exports.renderWithTap = renderWithTap; exports.signTestToken = _chunkBPCGXXMDcjs.signTestToken; exports.signedWorkEventRequest = signedWorkEventRequest; exports.tapMatchers = _chunkO357OJXLcjs.tapMatchers; exports.testJwks = _chunkBPCGXXMDcjs.testJwks; exports.validateMetricsResponse = validateMetricsResponse; exports.validateToolResponse = validateToolResponse; exports.workCommentCreatedFixture = workCommentCreatedFixture; exports.workItemDeletedFixture = workItemDeletedFixture; exports.workStatusChangedFixture = workStatusChangedFixture;
887
210
  //# sourceMappingURL=index.cjs.map