@buoy-gg/notifications 7.0.41 → 7.0.42

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 (71) hide show
  1. package/lib/commonjs/components/LocalNotificationTest.js +1 -185
  2. package/lib/commonjs/components/NotificationTestView.js +1 -329
  3. package/lib/commonjs/components/NotificationToolView.js +1 -673
  4. package/lib/commonjs/components/notificationStyles.js +1 -292
  5. package/lib/commonjs/expo.js +1 -247
  6. package/lib/commonjs/index.js +1 -148
  7. package/lib/commonjs/json.js +1 -58
  8. package/lib/commonjs/payload.js +1 -68
  9. package/lib/commonjs/preset.js +1 -56
  10. package/lib/commonjs/preview.js +1 -18
  11. package/lib/commonjs/recorder.js +1 -339
  12. package/lib/commonjs/runtime.js +1 -110
  13. package/lib/commonjs/storage.js +1 -61
  14. package/lib/commonjs/types.js +0 -1
  15. package/lib/module/components/LocalNotificationTest.js +1 -180
  16. package/lib/module/components/NotificationTestView.js +1 -324
  17. package/lib/module/components/NotificationToolView.js +1 -668
  18. package/lib/module/components/notificationStyles.js +1 -288
  19. package/lib/module/expo.js +1 -241
  20. package/lib/module/index.js +1 -13
  21. package/lib/module/json.js +1 -51
  22. package/lib/module/payload.js +1 -63
  23. package/lib/module/preset.js +1 -50
  24. package/lib/module/preview.js +1 -14
  25. package/lib/module/recorder.js +1 -332
  26. package/lib/module/runtime.js +1 -103
  27. package/lib/module/storage.js +1 -56
  28. package/lib/module/types.js +0 -1
  29. package/package.json +2 -2
  30. package/lib/commonjs/components/LocalNotificationTest.js.map +0 -1
  31. package/lib/commonjs/components/NotificationTestView.js.map +0 -1
  32. package/lib/commonjs/components/NotificationToolView.js.map +0 -1
  33. package/lib/commonjs/components/notificationStyles.js.map +0 -1
  34. package/lib/commonjs/expo.js.map +0 -1
  35. package/lib/commonjs/index.js.map +0 -1
  36. package/lib/commonjs/json.js.map +0 -1
  37. package/lib/commonjs/payload.js.map +0 -1
  38. package/lib/commonjs/preset.js.map +0 -1
  39. package/lib/commonjs/preview.js.map +0 -1
  40. package/lib/commonjs/recorder.js.map +0 -1
  41. package/lib/commonjs/runtime.js.map +0 -1
  42. package/lib/commonjs/storage.js.map +0 -1
  43. package/lib/commonjs/types.js.map +0 -1
  44. package/lib/module/components/LocalNotificationTest.js.map +0 -1
  45. package/lib/module/components/NotificationTestView.js.map +0 -1
  46. package/lib/module/components/NotificationToolView.js.map +0 -1
  47. package/lib/module/components/notificationStyles.js.map +0 -1
  48. package/lib/module/expo.js.map +0 -1
  49. package/lib/module/index.js.map +0 -1
  50. package/lib/module/json.js.map +0 -1
  51. package/lib/module/payload.js.map +0 -1
  52. package/lib/module/preset.js.map +0 -1
  53. package/lib/module/preview.js.map +0 -1
  54. package/lib/module/recorder.js.map +0 -1
  55. package/lib/module/runtime.js.map +0 -1
  56. package/lib/module/storage.js.map +0 -1
  57. package/lib/module/types.js.map +0 -1
  58. package/lib/typescript/components/LocalNotificationTest.d.ts.map +0 -1
  59. package/lib/typescript/components/NotificationTestView.d.ts.map +0 -1
  60. package/lib/typescript/components/NotificationToolView.d.ts.map +0 -1
  61. package/lib/typescript/components/notificationStyles.d.ts.map +0 -1
  62. package/lib/typescript/expo.d.ts.map +0 -1
  63. package/lib/typescript/index.d.ts.map +0 -1
  64. package/lib/typescript/json.d.ts.map +0 -1
  65. package/lib/typescript/payload.d.ts.map +0 -1
  66. package/lib/typescript/preset.d.ts.map +0 -1
  67. package/lib/typescript/preview.d.ts.map +0 -1
  68. package/lib/typescript/recorder.d.ts.map +0 -1
  69. package/lib/typescript/runtime.d.ts.map +0 -1
  70. package/lib/typescript/storage.d.ts.map +0 -1
  71. package/lib/typescript/types.d.ts.map +0 -1
@@ -1,339 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.NotificationRecorder = void 0;
7
- exports.expoMetadata = expoMetadata;
8
- exports.responseKey = responseKey;
9
- var _json = require("./json");
10
- const PREFIX = "buoy.notifications.v1.";
11
- const SESSION = PREFIX + "session";
12
- const TOKENS = PREFIX + "tokens";
13
- const EVENT = PREFIX + "event.";
14
- const MAX_RECORD_BYTES = 16 * 1024;
15
- const MAX_JOURNAL_BYTES = 512 * 1024;
16
- const MAX_RECORDS = 200;
17
- /** Recording runs independently of the desktop's snapshot subscriptions. */
18
- class NotificationRecorder {
19
- state = {
20
- version: 1,
21
- ready: false,
22
- provider: null,
23
- providerVersion: null,
24
- platform: "unknown",
25
- appId: null,
26
- capabilities: [],
27
- durable: false,
28
- storageError: null,
29
- evicted: 0,
30
- session: null,
31
- events: [],
32
- tokens: [],
33
- permissions: null,
34
- presented: null
35
- };
36
- listeners = new Set();
37
- sequence = 0;
38
- queue = Promise.resolve();
39
- constructor(options = {}) {
40
- this.options = options;
41
- this.now = options.now ?? Date.now;
42
- this.processId = options.processId ?? `${this.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
43
- this.state.durable = !!options.storage && options.durable === true;
44
- this.ready = this.hydrate();
45
- this.queue = this.ready;
46
- }
47
- getSnapshot = () => this.state;
48
- subscribe = listener => {
49
- this.listeners.add(listener);
50
- return () => {
51
- this.listeners.delete(listener);
52
- };
53
- };
54
- update(patch) {
55
- this.state = {
56
- ...this.state,
57
- ...patch
58
- };
59
- for (const listener of this.listeners) {
60
- try {
61
- listener();
62
- } catch {/* Observers cannot interrupt app callbacks. */}
63
- }
64
- }
65
- configure(patch) {
66
- this.update(patch);
67
- }
68
- allowed() {
69
- return this.options.enabled?.() ?? true;
70
- }
71
- storageFailure(error) {
72
- this.update({
73
- storageError: error instanceof Error ? error.message : String(error),
74
- durable: false
75
- });
76
- }
77
- serial(task) {
78
- const next = this.queue.then(task);
79
- this.queue = next.catch(() => {});
80
- return next;
81
- }
82
- async hydrate() {
83
- if (!this.allowed()) {
84
- this.update({
85
- ready: true
86
- });
87
- return;
88
- }
89
- if (this.options.durability) {
90
- try {
91
- this.update({
92
- durable: await this.options.durability
93
- });
94
- } catch (error) {
95
- this.storageFailure(error);
96
- }
97
- }
98
- const storage = this.options.storage;
99
- let explicitlyStopped = false;
100
- if (storage) try {
101
- const rawSession = await storage.getItem(SESSION);
102
- explicitlyStopped = rawSession === "null";
103
- if (rawSession) {
104
- const s = JSON.parse(rawSession);
105
- if (s && typeof s.runId === "string" && Number.isFinite(s.expiresAt) && s.expiresAt > this.now()) this.update({
106
- session: s
107
- });
108
- }
109
- const rawTokens = await storage.getItem(TOKENS);
110
- if (rawTokens) {
111
- const tokens = JSON.parse(rawTokens);
112
- if (Array.isArray(tokens)) this.update({
113
- tokens: tokens.filter(t => t && ["apns", "fcm", "expo"].includes(t.type) && typeof t.value === "string").slice(-10)
114
- });
115
- }
116
- const keys = (await storage.getAllKeys()).filter(key => key.startsWith(EVENT)).sort();
117
- const records = [];
118
- for (const key of keys) {
119
- try {
120
- const raw = await storage.getItem(key);
121
- if (!raw || (0, _json.byteLength)(raw) > MAX_RECORD_BYTES) {
122
- await storage.removeItem(key);
123
- continue;
124
- }
125
- const record = JSON.parse(raw);
126
- if (typeof record.id === "string" && typeof record.kind === "string" && Number.isFinite(record.capturedAt)) records.push(record);else await storage.removeItem(key);
127
- } catch {
128
- await storage.removeItem(key);
129
- }
130
- }
131
- records.sort((a, b) => a.capturedAt - b.capturedAt || a.sequence - b.sequence || a.id.localeCompare(b.id));
132
- this.update({
133
- events: records
134
- });
135
- await this.prune();
136
- } catch (error) {
137
- this.storageFailure(error);
138
- }
139
- if (this.options.autoStart && !this.state.session && !explicitlyStopped) {
140
- const startedAt = this.now();
141
- const session = {
142
- runId: this.processId,
143
- startedAt,
144
- expiresAt: startedAt + 30 * 60 * 1000
145
- };
146
- try {
147
- await storage?.setItem(SESSION, JSON.stringify(session));
148
- } catch (error) {
149
- this.storageFailure(error);
150
- }
151
- this.update({
152
- session
153
- });
154
- }
155
- this.update({
156
- ready: true
157
- });
158
- }
159
- async setCaptureSession(runId, durationMs = 30 * 60 * 1000) {
160
- if (!this.allowed()) throw new Error("Notification capture is disabled in this build.");
161
- if (runId !== null && (typeof runId !== "string" || !runId.trim() || runId.length > 128)) throw new Error("runId must contain 1 to 128 characters, or be null to stop capture.");
162
- if (!Number.isFinite(durationMs) || durationMs < 1000 || durationMs > 60 * 60 * 1000) throw new Error("Capture duration must be between 1 second and 1 hour.");
163
- return this.serial(async () => {
164
- const startedAt = this.now();
165
- const session = runId === null ? null : {
166
- runId,
167
- startedAt,
168
- expiresAt: startedAt + durationMs
169
- };
170
- try {
171
- if (this.options.storage) await this.options.storage.setItem(SESSION, JSON.stringify(session));
172
- } catch (error) {
173
- this.storageFailure(error);
174
- throw new Error("Could not persist the capture session. Keep the app open and check storage.");
175
- }
176
- this.update({
177
- session
178
- });
179
- return {
180
- session,
181
- durable: this.state.durable
182
- };
183
- });
184
- }
185
- record(kind, raw, metadata = {}) {
186
- const capturedAt = this.now();
187
- const observedAppState = this.options.appState?.() ?? "unknown";
188
- const clean = (0, _json.json)(raw);
189
- return this.serial(async () => {
190
- if (!this.allowed()) return null;
191
- const session = this.state.session;
192
- if (!session || session.expiresAt <= capturedAt) {
193
- if (session) this.update({
194
- session: null
195
- });
196
- return null;
197
- }
198
- const clipped = (value, max = 512) => typeof value === "string" ? value.slice(0, max) : null;
199
- const dedupeKey = clipped(metadata.dedupeKey, 2048);
200
- if (dedupeKey && this.state.events.some(e => e.dedupeKey === dedupeKey)) return null;
201
- const record = {
202
- id: `${this.processId}-${++this.sequence}`,
203
- processId: this.processId,
204
- sequence: this.sequence,
205
- capturedAt,
206
- runId: session.runId,
207
- kind,
208
- provider: clipped(metadata.provider, 64) ?? this.state.provider ?? "app",
209
- observedAppState,
210
- notificationId: clipped(metadata.notificationId),
211
- testId: clipped(metadata.testId),
212
- title: clipped(metadata.title, 1024),
213
- actionIdentifier: clipped(metadata.actionIdentifier),
214
- ...(dedupeKey ? {
215
- dedupeKey
216
- } : {}),
217
- raw: clean
218
- };
219
- if ((0, _json.byteLength)(JSON.stringify(record)) > MAX_RECORD_BYTES) {
220
- record.raw = {
221
- note: "Payload exceeded the 16 KiB capture limit."
222
- };
223
- record.truncated = true;
224
- }
225
- this.update({
226
- events: [...this.state.events, record]
227
- });
228
- try {
229
- await this.options.storage?.setItem(EVENT + record.id, JSON.stringify(record));
230
- } catch (error) {
231
- this.storageFailure(error);
232
- }
233
- // Keep the in-memory bound even when the disk is full or unavailable.
234
- try {
235
- await this.prune();
236
- } catch (error) {
237
- this.storageFailure(error);
238
- }
239
- return record;
240
- });
241
- }
242
- async prune() {
243
- const events = [...this.state.events];
244
- const sizes = events.map(e => (0, _json.byteLength)(JSON.stringify(e)));
245
- let bytes = sizes.reduce((sum, size) => sum + size, 0);
246
- const removed = [];
247
- while (events.length > MAX_RECORDS || bytes > MAX_JOURNAL_BYTES) {
248
- removed.push(events.shift());
249
- bytes -= sizes.shift();
250
- }
251
- if (removed.length) this.update({
252
- events,
253
- evicted: this.state.evicted + removed.length
254
- });
255
- for (const event of removed) await this.options.storage?.removeItem(EVENT + event.id);
256
- }
257
- async clearCapturedEvents() {
258
- return this.serial(async () => {
259
- const events = this.state.events;
260
- for (const event of events) await this.options.storage?.removeItem(EVENT + event.id);
261
- this.update({
262
- events: [],
263
- evicted: 0
264
- });
265
- return {
266
- cleared: true
267
- };
268
- });
269
- }
270
- async observeToken(type, value, metadata = {}) {
271
- if (!this.allowed()) return;
272
- if (!value || value.length > 8192) throw new Error("The notification token is empty or too long.");
273
- return this.serial(async () => {
274
- const token = {
275
- type,
276
- value,
277
- observedAt: this.now(),
278
- ...(typeof metadata.projectId === "string" ? {
279
- projectId: metadata.projectId.slice(0, 256)
280
- } : {}),
281
- ...(typeof metadata.environment === "string" ? {
282
- environment: metadata.environment.slice(0, 256)
283
- } : {})
284
- };
285
- const tokens = [...this.state.tokens.filter(t => !(t.type === type && t.projectId === metadata.projectId && t.environment === metadata.environment)), token].slice(-10);
286
- this.update({
287
- tokens
288
- });
289
- try {
290
- await this.options.storage?.setItem(TOKENS, JSON.stringify(tokens));
291
- } catch (error) {
292
- this.storageFailure(error);
293
- }
294
- });
295
- }
296
- setPermissions(permissions) {
297
- const value = (0, _json.json)(permissions);
298
- this.update({
299
- permissions: (0, _json.byteLength)(JSON.stringify(value)) <= MAX_RECORD_BYTES ? value : {
300
- note: "Permission result exceeded the capture limit."
301
- }
302
- });
303
- }
304
- setPresented(presented) {
305
- const value = (0, _json.json)(presented);
306
- if ((0, _json.byteLength)(JSON.stringify(value)) <= 128 * 1024) this.update({
307
- presented: value
308
- });else this.update({
309
- presented: {
310
- note: "System tray result exceeded 128 KiB. Inspect fewer presented notifications in the app.",
311
- count: Array.isArray(presented) ? presented.length : null
312
- }
313
- });
314
- }
315
- async flush() {
316
- await this.queue;
317
- }
318
- }
319
- exports.NotificationRecorder = NotificationRecorder;
320
- function expoMetadata(value) {
321
- const raw = (0, _json.object)(value);
322
- const notification = (0, _json.object)(raw.notification ?? value);
323
- const request = (0, _json.object)(notification.request);
324
- const content = (0, _json.object)(request.content);
325
- const payload = (0, _json.object)((0, _json.object)(request.trigger).payload);
326
- const data = (0, _json.object)(content.data ?? payload.body);
327
- return {
328
- notificationId: (0, _json.string)(request.identifier),
329
- testId: (0, _json.string)(data.__buoyTestId),
330
- title: (0, _json.string)(content.title),
331
- actionIdentifier: (0, _json.string)(raw.actionIdentifier)
332
- };
333
- }
334
- function responseKey(value) {
335
- const raw = (0, _json.object)(value);
336
- const notification = (0, _json.object)(raw.notification);
337
- return JSON.stringify([(0, _json.object)(notification.request).identifier, notification.date, raw.actionIdentifier, raw.userText]);
338
- }
339
- //# sourceMappingURL=recorder.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.NotificationRecorder=void 0;exports.expoMetadata=expoMetadata;exports.responseKey=responseKey;var _json=require("./json");const PREFIX="buoy.notifications.v1.";const SESSION=PREFIX+"session";const TOKENS=PREFIX+"tokens";const EVENT=PREFIX+"event.";const MAX_RECORD_BYTES=16*1024;const MAX_JOURNAL_BYTES=512*1024;const MAX_RECORDS=200;class NotificationRecorder{state={version:1,ready:false,provider:null,providerVersion:null,platform:"unknown",appId:null,capabilities:[],durable:false,storageError:null,evicted:0,session:null,events:[],tokens:[],permissions:null,presented:null};listeners=new Set;sequence=0;queue=Promise.resolve();constructor(t={}){this.options=t;this.now=t.now??Date.now;this.processId=t.processId??`${this.now().toString(36)}-${Math.random().toString(36).slice(2)}`;this.state.durable=!!t.storage&&t.durable===true;this.ready=this.hydrate();this.queue=this.ready}getSnapshot=()=>this.state;subscribe=t=>{this.listeners.add(t);return()=>{this.listeners.delete(t)}};update(t){this.state={...this.state,...t};for(const e of this.listeners){try{e()}catch{}}}configure(t){this.update(t)}allowed(){return this.options.enabled?.()??true}storageFailure(t){this.update({storageError:t instanceof Error?t.message:String(t),durable:false})}serial(t){const e=this.queue.then(t);this.queue=e.catch(()=>{});return e}async hydrate(){if(!this.allowed()){this.update({ready:true});return}if(this.options.durability){try{this.update({durable:await this.options.durability})}catch(s){this.storageFailure(s)}}const t=this.options.storage;let e=false;if(t)try{const s=await t.getItem(SESSION);e=s==="null";if(s){const i=JSON.parse(s);if(i&&typeof i.runId==="string"&&Number.isFinite(i.expiresAt)&&i.expiresAt>this.now())this.update({session:i})}const r=await t.getItem(TOKENS);if(r){const i=JSON.parse(r);if(Array.isArray(i))this.update({tokens:i.filter(o=>o&&["apns","fcm","expo"].includes(o.type)&&typeof o.value==="string").slice(-10)})}const n=(await t.getAllKeys()).filter(i=>i.startsWith(EVENT)).sort();const a=[];for(const i of n){try{const o=await t.getItem(i);if(!o||(0,_json.byteLength)(o)>MAX_RECORD_BYTES){await t.removeItem(i);continue}const c=JSON.parse(o);if(typeof c.id==="string"&&typeof c.kind==="string"&&Number.isFinite(c.capturedAt))a.push(c);else await t.removeItem(i)}catch{await t.removeItem(i)}}a.sort((i,o)=>i.capturedAt-o.capturedAt||i.sequence-o.sequence||i.id.localeCompare(o.id));this.update({events:a});await this.prune()}catch(s){this.storageFailure(s)}if(this.options.autoStart&&!this.state.session&&!e){const s=this.now();const r={runId:this.processId,startedAt:s,expiresAt:s+30*60*1e3};try{await t?.setItem(SESSION,JSON.stringify(r))}catch(n){this.storageFailure(n)}this.update({session:r})}this.update({ready:true})}async setCaptureSession(t,e=30*60*1e3){if(!this.allowed())throw new Error("Notification capture is disabled in this build.");if(t!==null&&(typeof t!=="string"||!t.trim()||t.length>128))throw new Error("runId must contain 1 to 128 characters, or be null to stop capture.");if(!Number.isFinite(e)||e<1e3||e>60*60*1e3)throw new Error("Capture duration must be between 1 second and 1 hour.");return this.serial(async()=>{const s=this.now();const r=t===null?null:{runId:t,startedAt:s,expiresAt:s+e};try{if(this.options.storage)await this.options.storage.setItem(SESSION,JSON.stringify(r))}catch(n){this.storageFailure(n);throw new Error("Could not persist the capture session. Keep the app open and check storage.")}this.update({session:r});return{session:r,durable:this.state.durable}})}record(t,e,s={}){const r=this.now();const n=this.options.appState?.()??"unknown";const a=(0,_json.json)(e);return this.serial(async()=>{if(!this.allowed())return null;const i=this.state.session;if(!i||i.expiresAt<=r){if(i)this.update({session:null});return null}const o=(u,l=512)=>typeof u==="string"?u.slice(0,l):null;const c=o(s.dedupeKey,2048);if(c&&this.state.events.some(u=>u.dedupeKey===c))return null;const d={id:`${this.processId}-${++this.sequence}`,processId:this.processId,sequence:this.sequence,capturedAt:r,runId:i.runId,kind:t,provider:o(s.provider,64)??this.state.provider??"app",observedAppState:n,notificationId:o(s.notificationId),testId:o(s.testId),title:o(s.title,1024),actionIdentifier:o(s.actionIdentifier),...c?{dedupeKey:c}:{},raw:a};if((0,_json.byteLength)(JSON.stringify(d))>MAX_RECORD_BYTES){d.raw={note:"Payload exceeded the 16 KiB capture limit."};d.truncated=true}this.update({events:[...this.state.events,d]});try{await this.options.storage?.setItem(EVENT+d.id,JSON.stringify(d))}catch(u){this.storageFailure(u)}try{await this.prune()}catch(u){this.storageFailure(u)}return d})}async prune(){const t=[...this.state.events];const e=t.map(n=>(0,_json.byteLength)(JSON.stringify(n)));let s=e.reduce((n,a)=>n+a,0);const r=[];while(t.length>MAX_RECORDS||s>MAX_JOURNAL_BYTES){r.push(t.shift());s-=e.shift()}if(r.length)this.update({events:t,evicted:this.state.evicted+r.length});for(const n of r)await this.options.storage?.removeItem(EVENT+n.id)}async clearCapturedEvents(){return this.serial(async()=>{const t=this.state.events;for(const e of t)await this.options.storage?.removeItem(EVENT+e.id);this.update({events:[],evicted:0});return{cleared:true}})}async observeToken(t,e,s={}){if(!this.allowed())return;if(!e||e.length>8192)throw new Error("The notification token is empty or too long.");return this.serial(async()=>{const r={type:t,value:e,observedAt:this.now(),...typeof s.projectId==="string"?{projectId:s.projectId.slice(0,256)}:{},...typeof s.environment==="string"?{environment:s.environment.slice(0,256)}:{}};const n=[...this.state.tokens.filter(a=>!(a.type===t&&a.projectId===s.projectId&&a.environment===s.environment)),r].slice(-10);this.update({tokens:n});try{await this.options.storage?.setItem(TOKENS,JSON.stringify(n))}catch(a){this.storageFailure(a)}})}setPermissions(t){const e=(0,_json.json)(t);this.update({permissions:(0,_json.byteLength)(JSON.stringify(e))<=MAX_RECORD_BYTES?e:{note:"Permission result exceeded the capture limit."}})}setPresented(t){const e=(0,_json.json)(t);if((0,_json.byteLength)(JSON.stringify(e))<=128*1024)this.update({presented:e});else this.update({presented:{note:"System tray result exceeded 128 KiB. Inspect fewer presented notifications in the app.",count:Array.isArray(t)?t.length:null}})}async flush(){await this.queue}}exports.NotificationRecorder=NotificationRecorder;function expoMetadata(h){const t=(0,_json.object)(h);const e=(0,_json.object)(t.notification??h);const s=(0,_json.object)(e.request);const r=(0,_json.object)(s.content);const n=(0,_json.object)((0,_json.object)(s.trigger).payload);const a=(0,_json.object)(r.data??n.body);return{notificationId:(0,_json.string)(s.identifier),testId:(0,_json.string)(a.__buoyTestId),title:(0,_json.string)(r.title),actionIdentifier:(0,_json.string)(t.actionIdentifier)}}function responseKey(h){const t=(0,_json.object)(h);const e=(0,_json.object)(t.notification);return JSON.stringify([(0,_json.object)(e.request).identifier,e.date,t.actionIdentifier,t.userText])}
@@ -1,110 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.captureEnabled = captureEnabled;
7
- exports.getNotificationRecorder = getNotificationRecorder;
8
- exports.installExpoNotificationCapture = installExpoNotificationCapture;
9
- exports.notificationSyncAdapter = void 0;
10
- var _reactNative = require("react-native");
11
- var _storage = require("./storage");
12
- var _recorder = require("./recorder");
13
- var _expo = require("./expo");
14
- var _json = require("./json");
15
- const globals = globalThis;
16
- function captureEnabled(enableInRelease = false) {
17
- return typeof __DEV__ !== "undefined" && __DEV__ || enableInRelease === true;
18
- }
19
- function getNotificationRecorder() {
20
- return globals.__buoyNotificationsV1?.recorder ?? null;
21
- }
22
- function installExpoNotificationCapture(sdk, options = {}) {
23
- if (!captureEnabled(options.enableInRelease)) return null;
24
- const key = JSON.stringify([options.platform ?? _reactNative.Platform.OS, options.appId, options.providerVersion, options.projectId, options.enableInRelease, options.preview]);
25
- let runtime = globals.__buoyNotificationsV1;
26
- if (!runtime) {
27
- const persistence = options.storage ? {
28
- storage: options.storage,
29
- durable: options.durable === true
30
- } : (0, _storage.defaultNotificationStorage)();
31
- const recorder = new _recorder.NotificationRecorder({
32
- ...persistence,
33
- enabled: () => captureEnabled(options.enableInRelease),
34
- appState: () => _reactNative.AppState.currentState ?? "unknown",
35
- autoStart: true
36
- });
37
- runtime = {
38
- recorder
39
- };
40
- globals.__buoyNotificationsV1 = runtime;
41
- }
42
- if (runtime.sdk !== sdk || runtime.key !== key) {
43
- runtime.attachment?.dispose();
44
- runtime.attachment = (0, _expo.attachExpoNotifications)(runtime.recorder, sdk, {
45
- ...options,
46
- platform: options.platform ?? _reactNative.Platform.OS
47
- });
48
- runtime.sdk = sdk;
49
- runtime.key = key;
50
- }
51
- return runtime.recorder;
52
- }
53
- const emptyRecorder = new _recorder.NotificationRecorder();
54
- function current() {
55
- const runtime = globals.__buoyNotificationsV1;
56
- if (!runtime) throw new Error("Install Expo notification capture in the app entry point, before rendering the root component.");
57
- return runtime;
58
- }
59
- const notificationSyncAdapter = exports.notificationSyncAdapter = {
60
- version: 1,
61
- getSnapshot: () => (getNotificationRecorder() ?? emptyRecorder).getSnapshot(),
62
- subscribe: listener => (getNotificationRecorder() ?? emptyRecorder).subscribe(listener),
63
- actions: {
64
- getSnapshot: () => notificationSyncAdapter.getSnapshot(),
65
- getCapabilities: () => {
66
- const {
67
- ready,
68
- provider,
69
- providerVersion,
70
- platform,
71
- appId,
72
- capabilities,
73
- durable,
74
- storageError
75
- } = notificationSyncAdapter.getSnapshot();
76
- return {
77
- ready,
78
- provider,
79
- providerVersion,
80
- platform,
81
- appId,
82
- capabilities,
83
- durable,
84
- storageError
85
- };
86
- },
87
- getEvent(params) {
88
- const {
89
- id
90
- } = (0, _json.object)(params);
91
- if (typeof id !== "string") throw new Error("Provide the captured event id.");
92
- return current().recorder.getSnapshot().events.find(event => event.id === id) ?? null;
93
- },
94
- async setCaptureSession(params) {
95
- const {
96
- runId,
97
- durationMs
98
- } = (0, _json.object)(params);
99
- if (typeof runId !== "string" && runId !== null) throw new Error("Provide runId, or null to stop capture.");
100
- if (durationMs !== undefined && typeof durationMs !== "number") throw new Error("durationMs must be a number.");
101
- return current().recorder.setCaptureSession(runId, durationMs);
102
- },
103
- clearCapturedEvents: () => current().recorder.clearCapturedEvents(),
104
- getPermissions: () => current().attachment.actions.getPermissions(),
105
- listPresented: () => current().attachment.actions.listPresented(),
106
- refreshToken: params => current().attachment.actions.refreshToken(params),
107
- scheduleLocal: params => current().attachment.actions.scheduleLocal(params)
108
- }
109
- };
110
- //# sourceMappingURL=runtime.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.captureEnabled=captureEnabled;exports.getNotificationRecorder=getNotificationRecorder;exports.installExpoNotificationCapture=installExpoNotificationCapture;exports.notificationSyncAdapter=void 0;var _reactNative=require("react-native");var _storage=require("./storage");var _recorder=require("./recorder");var _expo=require("./expo");var _json=require("./json");const globals=globalThis;function captureEnabled(t=false){return typeof __DEV__!=="undefined"&&__DEV__||t===true}function getNotificationRecorder(){return globals.__buoyNotificationsV1?.recorder??null}function installExpoNotificationCapture(t,e={}){if(!captureEnabled(e.enableInRelease))return null;const o=JSON.stringify([e.platform??_reactNative.Platform.OS,e.appId,e.providerVersion,e.projectId,e.enableInRelease,e.preview]);let r=globals.__buoyNotificationsV1;if(!r){const n=e.storage?{storage:e.storage,durable:e.durable===true}:(0,_storage.defaultNotificationStorage)();const a=new _recorder.NotificationRecorder({...n,enabled:()=>captureEnabled(e.enableInRelease),appState:()=>_reactNative.AppState.currentState??"unknown",autoStart:true});r={recorder:a};globals.__buoyNotificationsV1=r}if(r.sdk!==t||r.key!==o){r.attachment?.dispose();r.attachment=(0,_expo.attachExpoNotifications)(r.recorder,t,{...e,platform:e.platform??_reactNative.Platform.OS});r.sdk=t;r.key=o}return r.recorder}const emptyRecorder=new _recorder.NotificationRecorder;function current(){const t=globals.__buoyNotificationsV1;if(!t)throw new Error("Install Expo notification capture in the app entry point, before rendering the root component.");return t}const notificationSyncAdapter=exports.notificationSyncAdapter={version:1,getSnapshot:()=>(getNotificationRecorder()??emptyRecorder).getSnapshot(),subscribe:t=>(getNotificationRecorder()??emptyRecorder).subscribe(t),actions:{getSnapshot:()=>notificationSyncAdapter.getSnapshot(),getCapabilities:()=>{const{ready:t,provider:e,providerVersion:o,platform:r,appId:n,capabilities:a,durable:i,storageError:c}=notificationSyncAdapter.getSnapshot();return{ready:t,provider:e,providerVersion:o,platform:r,appId:n,capabilities:a,durable:i,storageError:c}},getEvent(t){const{id:e}=(0,_json.object)(t);if(typeof e!=="string")throw new Error("Provide the captured event id.");return current().recorder.getSnapshot().events.find(o=>o.id===e)??null},async setCaptureSession(t){const{runId:e,durationMs:o}=(0,_json.object)(t);if(typeof e!=="string"&&e!==null)throw new Error("Provide runId, or null to stop capture.");if(o!==void 0&&typeof o!=="number")throw new Error("durationMs must be a number.");return current().recorder.setCaptureSession(e,o)},clearCapturedEvents:()=>current().recorder.clearCapturedEvents(),getPermissions:()=>current().attachment.actions.getPermissions(),listPresented:()=>current().attachment.actions.listPresented(),refreshToken:t=>current().attachment.actions.refreshToken(t),scheduleLocal:t=>current().attachment.actions.scheduleLocal(t)}};
@@ -1,61 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.createExpoNotificationStorage = createExpoNotificationStorage;
7
- exports.defaultNotificationStorage = defaultNotificationStorage;
8
- /** Propagates native I/O failures so capture never acknowledges a memory fallback as durable. */
9
- function createExpoNotificationStorage(fs) {
10
- if (!fs.documentDirectory) throw new Error("Expo FileSystem has no persistent document directory.");
11
- const directory = fs.documentDirectory + "buoy-notifications/";
12
- const pathFor = key => directory + encodeURIComponent(key) + ".json";
13
- return {
14
- async getItem(key) {
15
- const path = pathFor(key);
16
- return (await fs.getInfoAsync(path)).exists ? fs.readAsStringAsync(path) : null;
17
- },
18
- async setItem(key, value) {
19
- if (!(await fs.getInfoAsync(directory)).exists) await fs.makeDirectoryAsync(directory, {
20
- intermediates: true
21
- });
22
- await fs.writeAsStringAsync(pathFor(key), value);
23
- },
24
- async removeItem(key) {
25
- await fs.deleteAsync(pathFor(key), {
26
- idempotent: true
27
- });
28
- },
29
- async getAllKeys() {
30
- if (!(await fs.getInfoAsync(directory)).exists) return [];
31
- return (await fs.readDirectoryAsync(directory)).filter(file => file.endsWith(".json")).flatMap(file => {
32
- try {
33
- return [decodeURIComponent(file.slice(0, -5))];
34
- } catch {
35
- return [];
36
- }
37
- });
38
- }
39
- };
40
- }
41
- function defaultNotificationStorage() {
42
- try {
43
- const fs = require("expo-file-system/legacy");
44
- if (fs.documentDirectory && typeof fs.writeAsStringAsync === "function") return {
45
- storage: createExpoNotificationStorage(fs),
46
- durable: true
47
- };
48
- } catch {/* An app can provide its own storage when Expo FileSystem is absent. */}
49
- try {
50
- const module = require("@react-native-async-storage/async-storage");
51
- const storage = module.default ?? module;
52
- if (typeof storage.getItem === "function" && typeof storage.setItem === "function" && typeof storage.getAllKeys === "function") return {
53
- storage,
54
- durable: true
55
- };
56
- } catch {/* Capture remains available in memory. */}
57
- return {
58
- durable: false
59
- };
60
- }
61
- //# sourceMappingURL=storage.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.createExpoNotificationStorage=createExpoNotificationStorage;exports.defaultNotificationStorage=defaultNotificationStorage;function createExpoNotificationStorage(t){if(!t.documentDirectory)throw new Error("Expo FileSystem has no persistent document directory.");const r=t.documentDirectory+"buoy-notifications/";const o=e=>r+encodeURIComponent(e)+".json";return{async getItem(e){const n=o(e);return(await t.getInfoAsync(n)).exists?t.readAsStringAsync(n):null},async setItem(e,n){if(!(await t.getInfoAsync(r)).exists)await t.makeDirectoryAsync(r,{intermediates:true});await t.writeAsStringAsync(o(e),n)},async removeItem(e){await t.deleteAsync(o(e),{idempotent:true})},async getAllKeys(){if(!(await t.getInfoAsync(r)).exists)return[];return(await t.readDirectoryAsync(r)).filter(e=>e.endsWith(".json")).flatMap(e=>{try{return[decodeURIComponent(e.slice(0,-5))]}catch{return[]}})}}}function defaultNotificationStorage(){try{const t=require("expo-file-system/legacy");if(t.documentDirectory&&typeof t.writeAsStringAsync==="function")return{storage:createExpoNotificationStorage(t),durable:true}}catch{}try{const t=require("@react-native-async-storage/async-storage");const r=t.default??t;if(typeof r.getItem==="function"&&typeof r.setItem==="function"&&typeof r.getAllKeys==="function")return{storage:r,durable:true}}catch{}return{durable:false}}
@@ -1,2 +1 @@
1
1
  "use strict";
2
- //# sourceMappingURL=types.js.map