Skip to content

Commit e71732b

Browse files
authored
fix(db): improve IndexedDB error handling and optimization (#1433)
1 parent 30db93c commit e71732b

File tree

13 files changed

+170
-301
lines changed

13 files changed

+170
-301
lines changed

CLAUDE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
description: Use Bun instead of Node.js, npm, pnpm
3+
globs: '*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json'
4+
alwaysApply: false
5+
---
6+
7+
Default to using Bun instead of Node.js.
8+
9+
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
10+
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
11+
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
12+
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
13+
- Use `bunx <package> <command>` instead of `npx <package> <command>`
14+
- Bun automatically loads .env, so don't use dotenv.

bun.lock

Lines changed: 4 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 19 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@
1414
color: white;
1515
padding: 16px 24px;
1616
border-radius: 12px;
17-
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
17+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
1818
max-width: 350px;
1919
z-index: 10000;
2020
animation: slideIn 0.3s ease-out;
21-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
21+
font-family:
22+
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
2223
}
2324
.in-app-notification h4 {
2425
margin: 0 0 8px 0;
@@ -44,8 +45,14 @@
4445
opacity: 1;
4546
}
4647
@keyframes slideIn {
47-
from { transform: translateX(100%); opacity: 0; }
48-
to { transform: translateX(0); opacity: 1; }
48+
from {
49+
transform: translateX(100%);
50+
opacity: 0;
51+
}
52+
to {
53+
transform: translateX(0);
54+
opacity: 1;
55+
}
4956
}
5057
.demo-section {
5158
margin: 20px 0;
@@ -107,7 +114,7 @@ <h4>${notification.title || 'Notification'}</h4>
107114
// for testing consent required
108115
// OneSignal.setConsentRequired(true);
109116

110-
await OneSignal.init({
117+
OneSignal.init({
111118
appId,
112119
// requiresUserPrivacyConsent: true, // requires custom site sestting in dashboard
113120
// promptOptions: {
@@ -121,225 +128,21 @@ <h4>${notification.title || 'Notification'}</h4>
121128
// },
122129
// },
123130
});
131+
OneSignal.User.addTag('test', 'test');
124132

125-
// Demo: foregroundWillDisplay with preventDefault() and display()
126-
// Call preventDefault() synchronously to suppress the system notification.
127-
// Optionally call event.notification.display() later to re-show it.
128-
OneSignal.Notifications.addEventListener('foregroundWillDisplay', (event) => {
129-
console.log('[Demo] foregroundWillDisplay event received:', event);
130-
131-
// Display a counter every second and stop after 30 seconds
132-
let counter = 0;
133-
let secondsToWaitFor = 10
134-
const counterInterval = setInterval(() => {
135-
counter++;
136-
console.log(`[Demo] Counter: ${counter}`);
137-
if (counter >= secondsToWaitFor) {
138-
clearInterval(counterInterval);
139-
console.log(`[Demo] Counter stopped after ${secondsToWaitFor} seconds`);
140-
}
141-
}, 1000 * secondsToWaitFor);
142-
if (suppressWhenFocused && document.visibilityState === 'visible') {
143-
event.preventDefault();
144-
console.log('[Demo] Preventing system notification, showing in-app instead');
145-
showInAppNotification(event.notification);
146-
147-
// Uncomment below to also re-display the system notification after a delay:
148-
setTimeout(() => {
149-
console.log('[Demo] showing the notification after some async delay');
150-
event.notification.display();
151-
}, 6000);
152-
} else {
153-
console.log('[Demo] Allowing system notification to display');
154-
}
155-
});
133+
OneSignal.Notifications.addEventListener(
134+
'foregroundWillDisplay',
135+
(event) => {
136+
console.log('[Demo] foregroundWillDisplay event received:', event);
137+
},
138+
);
156139

157140
// OneSignal.setConsentRequired(true);
158141
});
159-
160-
// function pushSubscriptionChangeListener(event) {
161-
// console.warn('event.previous.id', event.previous.id);
162-
// console.warn('event.current.id', event.current.id);
163-
// console.warn('event.previous.token', event.previous.token);
164-
// console.warn('event.current.token', event.current.token);
165-
// console.warn('event.previous.optedIn', event.previous.optedIn);
166-
// console.warn('event.current.optedIn', event.current.optedIn);
167-
// }
168-
169-
// // uncomment to test push subscription change listener
170-
// OneSignalDeferred.push(function (OneSignal) {
171-
// OneSignal.User.PushSubscription.addEventListener('change', (e) => {
172-
// console.log('PushSubscription.addEventListener', e);
173-
// });
174-
// OneSignal.Notifications.addEventListener('change', (e) => {
175-
// console.log('Notifications.addEventListener', e);
176-
// });
177-
// OneSignal.Notifications.addEventListener('permissionChange', (e) => {
178-
// console.log('permissionChange', e);
179-
// });
180-
// });
181-
182-
// uncomment to test login
183-
// OneSignalDeferred.push(async function (OneSignal) {
184-
// await OneSignal.login('new-web-sdk');
185-
// OneSignal.User.addEmail('test@test.com');
186-
// });
187-
188-
function toggleSuppressNotifications(enabled) {
189-
suppressWhenFocused = enabled;
190-
document.getElementById('btn-suppress-on').classList.toggle('active', enabled);
191-
document.getElementById('btn-suppress-off').classList.toggle('active', !enabled);
192-
console.log('[Demo] Suppress notifications when focused:', enabled);
193-
}
194142
</script>
195143
</head>
196144
<body>
197145
<script type="module" src="/src/entries/pageSdkInit.ts"></script>
198146
<h1>OneSignal Dev</h1>
199-
<p>
200-
This html file is for local development with hot-reloading. To preview the
201-
bundle, it will use a separate html file in the preview folder.
202-
</p>
203-
204-
<div class="demo-section">
205-
<h3>Demo: Suppress Notifications When Tab is Focused</h3>
206-
<p>
207-
When enabled, push notifications will be suppressed when this tab is in focus.
208-
Instead of a system notification, an in-app notification will be shown.
209-
</p>
210-
<p>
211-
<strong>How to test:</strong>
212-
<ol>
213-
<li>Enable "Suppress when focused" below</li>
214-
<li>Send a test push notification from your OneSignal dashboard</li>
215-
<li>With this tab in focus, you'll see an in-app notification instead of a system notification</li>
216-
<li>With this tab in background, you'll see a normal system notification</li>
217-
</ol>
218-
</p>
219-
<div style="margin-top: 16px;">
220-
<button id="btn-suppress-on" class="toggle-btn" onclick="toggleSuppressNotifications(true)">
221-
Suppress when focused: ON
222-
</button>
223-
<button id="btn-suppress-off" class="toggle-btn active" onclick="toggleSuppressNotifications(false)">
224-
Suppress when focused: OFF
225-
</button>
226-
</div>
227-
</div>
228-
229-
<hr />
230-
<h2>App ID Migration Regression Test</h2>
231-
<p>
232-
Reproduces the issue where migrating App IDs on the same origin leaves the
233-
push subscription in an "unsubscribed" state. Open the browser console to
234-
observe each step.
235-
</p>
236-
<ol>
237-
<li>Enter <strong>App ID 1</strong> and click <em>Init &amp; Subscribe with App ID 1</em>. Grant notification permission when prompted.</li>
238-
<li>Enter <strong>App ID 2</strong> and click <em>Migrate to App ID 2</em>. The page reloads with the new App ID.</li>
239-
<li>Check the status panel below &mdash; <code>optedIn</code> should be <strong>true</strong> after migration.</li>
240-
</ol>
241-
242-
<div style="display:flex;gap:12px;flex-wrap:wrap;margin:12px 0">
243-
<label>
244-
App ID 1
245-
<input id="appId1" type="text" size="40" placeholder="paste App ID 1 here" />
246-
</label>
247-
<label>
248-
App ID 2
249-
<input id="appId2" type="text" size="40" placeholder="paste App ID 2 here" />
250-
</label>
251-
</div>
252-
253-
<div style="display:flex;gap:8px;flex-wrap:wrap;margin:8px 0">
254-
<button id="btnInit1">Init &amp; Subscribe with App ID 1</button>
255-
<button id="btnMigrate">Migrate to App ID 2 (reload)</button>
256-
<button id="btnStatus">Refresh Status</button>
257-
</div>
258-
259-
<h3>Subscription Status</h3>
260-
<pre id="statusOutput" style="background:#f4f4f4;padding:12px;border-radius:4px;overflow:auto;max-height:300px">
261-
Click "Refresh Status" after init to see current state.
262-
</pre>
263-
264-
<script>
265-
// Populate App ID inputs from query params if present
266-
const params = new URLSearchParams(window.location.search);
267-
if (params.get('app_id'))
268-
document.getElementById('appId1').value = params.get('app_id');
269-
if (params.get('app_id_2'))
270-
document.getElementById('appId2').value = params.get('app_id_2');
271-
272-
function log(msg) {
273-
console.log('[Migration Test]', msg);
274-
}
275-
276-
document.getElementById('btnInit1').addEventListener('click', () => {
277-
const id = document.getElementById('appId1').value.trim();
278-
if (!id) return alert('Enter App ID 1 first');
279-
log('Navigating with App ID 1: ' + id);
280-
const url = new URL(window.location.href);
281-
url.searchParams.set('app_id', id);
282-
window.location.href = url.toString();
283-
});
284-
285-
document.getElementById('btnMigrate').addEventListener('click', () => {
286-
const id2 = document.getElementById('appId2').value.trim();
287-
if (!id2) return alert('Enter App ID 2 first');
288-
log('Migrating to App ID 2: ' + id2);
289-
const url = new URL(window.location.href);
290-
url.searchParams.set('app_id', id2);
291-
url.searchParams.set('app_id_2', id2);
292-
window.location.href = url.toString();
293-
});
294-
295-
document.getElementById('btnStatus').addEventListener('click', refreshStatus);
296-
297-
async function refreshStatus() {
298-
const out = document.getElementById('statusOutput');
299-
try {
300-
const sub = OneSignal.User.PushSubscription;
301-
const info = {
302-
'App ID (config)': OneSignal.config?.appId,
303-
'Notification.permission': Notification.permission,
304-
'PushSubscription.id': sub.id,
305-
'PushSubscription.token': sub.token
306-
? sub.token.substring(0, 60) + '...'
307-
: null,
308-
'PushSubscription.optedIn': sub.optedIn,
309-
};
310-
out.textContent = JSON.stringify(info, null, 2);
311-
log('Status: ' + JSON.stringify(info));
312-
} catch (e) {
313-
out.textContent = 'Error reading status: ' + e.message;
314-
}
315-
}
316-
317-
// Auto-refresh status once SDK is ready
318-
window.OneSignalDeferred = window.OneSignalDeferred || [];
319-
OneSignalDeferred.push(function (OneSignal) {
320-
OneSignal.User.PushSubscription.addEventListener('change', (e) => {
321-
log('PushSubscription change event: ' + JSON.stringify(e));
322-
refreshStatus();
323-
});
324-
setTimeout(refreshStatus, 1000);
325-
});
326-
</script>
327-
328-
<script>
329-
// To check against race conditions
330-
// OneSignalDeferred.push(async function (OneSignal) {
331-
// await OneSignal.logout();
332-
// });
333-
334-
// to check against delayed OneSignalDeferred call, comment out the one in the head
335-
// setTimeout(async () => {
336-
// window.OneSignalDeferred = window.OneSignalDeferred || [];
337-
// OneSignalDeferred.push(async function (OneSignal) {
338-
// await OneSignal.init({
339-
// appId,
340-
// });
341-
// });
342-
// }, 5000);
343-
</script>
344147
</body>
345148
</html>

0 commit comments

Comments
 (0)