sitepong 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -0
- package/dist/entries/rn.js +53 -1
- package/dist/entries/rn.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -596,6 +596,144 @@ Content inside `<SensitiveView>` is replaced with a black rectangle in recorded
|
|
|
596
596
|
| `bufferDuration` | `10000` (10s) | `60000` (60s) | Rolling buffer size in ms |
|
|
597
597
|
| `maxDuration` | `3600000` | `3600000` | Max recording duration in ms |
|
|
598
598
|
|
|
599
|
+
### Push Notifications & Live Activities
|
|
600
|
+
|
|
601
|
+
Native APNs (iOS) and FCM (Android) push notifications, plus iOS Live Activity updates. SitePong sends directly to Apple/Google — no Expo Push service in the path.
|
|
602
|
+
|
|
603
|
+
#### Token lifecycle
|
|
604
|
+
|
|
605
|
+
There are two halves to push: the **client SDK** registers device tokens with the SitePong ingest server, and the **server-side Push API** sends notifications to those tokens.
|
|
606
|
+
|
|
607
|
+
```
|
|
608
|
+
[App launches]
|
|
609
|
+
↓
|
|
610
|
+
[Notifications.getDevicePushTokenAsync()] ← OS gives you a native token
|
|
611
|
+
↓
|
|
612
|
+
[registerDeviceToken(token, opts)] ← SDK POSTs to /api/push/tokens
|
|
613
|
+
↓ with X-API-Key: sp_live_xxx
|
|
614
|
+
[Token stored in SitePong]
|
|
615
|
+
↓
|
|
616
|
+
[identify('user-123')] ← SDK auto re-registers token
|
|
617
|
+
↓ with user_id (via lazy hook)
|
|
618
|
+
[Your backend → POST /api/push/send] ← server-only sp_push_xxx key
|
|
619
|
+
↓
|
|
620
|
+
[SitePong → APNs / FCM → Device]
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### 1. Install permission and get the native token
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
npx expo install expo-notifications
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
```typescript
|
|
630
|
+
import * as Notifications from 'expo-notifications';
|
|
631
|
+
import * as Device from 'expo-device';
|
|
632
|
+
import { Platform } from 'react-native';
|
|
633
|
+
|
|
634
|
+
if (!Device.isDevice) return; // simulator can't receive push
|
|
635
|
+
|
|
636
|
+
const { status } = await Notifications.requestPermissionsAsync();
|
|
637
|
+
if (status !== 'granted') return;
|
|
638
|
+
|
|
639
|
+
// Returns the raw native token (APNs hex on iOS, FCM token on Android)
|
|
640
|
+
const { data: token } = await Notifications.getDevicePushTokenAsync();
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
#### 2. Register the token with SitePong
|
|
644
|
+
|
|
645
|
+
```typescript
|
|
646
|
+
import { registerDeviceToken } from '@sitepong/sdk/react-native';
|
|
647
|
+
import { Platform } from 'react-native';
|
|
648
|
+
|
|
649
|
+
registerDeviceToken(token, {
|
|
650
|
+
platform: Platform.OS as 'ios' | 'android',
|
|
651
|
+
environment: __DEV__ ? 'sandbox' : 'production',
|
|
652
|
+
userId: 'user-123', // optional — can be set later via identify()
|
|
653
|
+
});
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
This makes a `POST /api/push/tokens` request to the ingest server with `X-API-Key: <your SDK key>`. The body includes the token, `token_type` (`apns`/`fcm`), `device_id`, `user_id`, `platform`, app version, device model, and OS version. The server upserts by `(token, environment)` so re-registration is idempotent.
|
|
657
|
+
|
|
658
|
+
#### 3. User identification (automatic)
|
|
659
|
+
|
|
660
|
+
When you call `identify(userId)`, the SDK automatically re-registers all cached push, Live Activity, and push-to-start tokens with the new `user_id`. **You do not need to call `registerDeviceToken()` again after login.**
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
import { identify } from '@sitepong/sdk/react-native';
|
|
664
|
+
|
|
665
|
+
// Token already registered anonymously at app launch
|
|
666
|
+
// Now user logs in:
|
|
667
|
+
identify('user-123');
|
|
668
|
+
// → SDK re-POSTs /api/push/tokens with user_id: "user-123"
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
The hook is installed lazily the first time any `register*` function is called, so it works whether you use `SitePongRNProvider` or call `initRN()` directly.
|
|
672
|
+
|
|
673
|
+
#### 4. Send notifications from your backend
|
|
674
|
+
|
|
675
|
+
Generate a separate **Push API key** (prefix `sp_push_`) from the Notifications tab in the SitePong dashboard. This is **not** the SDK key — it's server-only and has permission to send pushes.
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
curl -X POST https://api.sitepong.com/api/push/send \
|
|
679
|
+
-H "Authorization: Bearer sp_push_xxxxxxxxxxxxxxxx" \
|
|
680
|
+
-H "Content-Type: application/json" \
|
|
681
|
+
-d '{
|
|
682
|
+
"title": "Order Shipped",
|
|
683
|
+
"body": "Your order #1234 is on its way",
|
|
684
|
+
"data": { "orderId": "1234" },
|
|
685
|
+
"target": { "user_ids": ["user-123"] }
|
|
686
|
+
}'
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Targeting options (provide at least one):
|
|
690
|
+
|
|
691
|
+
- `user_ids: string[]` — sends to all active devices for these users
|
|
692
|
+
- `device_ids: string[]` — sends to specific SitePong device IDs
|
|
693
|
+
- `tokens: string[]` — sends directly to raw APNs/FCM tokens
|
|
694
|
+
|
|
695
|
+
#### Live Activities (iOS)
|
|
696
|
+
|
|
697
|
+
Register the per-instance push token from your native bridge:
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
import {
|
|
701
|
+
registerLiveActivityToken,
|
|
702
|
+
registerPushToStartToken,
|
|
703
|
+
endLiveActivity,
|
|
704
|
+
} from '@sitepong/sdk/react-native';
|
|
705
|
+
|
|
706
|
+
// When ActivityKit gives you a push token for a running activity
|
|
707
|
+
registerLiveActivityToken('DeliveryActivityAttributes', activity.id, pushToken, {
|
|
708
|
+
environment: 'production',
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
// Or register a push-to-start token (iOS 17.2+) so the activity can be launched remotely
|
|
712
|
+
registerPushToStartToken('DeliveryActivityAttributes', pushToStartToken, {
|
|
713
|
+
environment: 'production',
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// When the activity ends, deactivate its token
|
|
717
|
+
endLiveActivity('DeliveryActivityAttributes', activity.id);
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
#### Token invalidation
|
|
721
|
+
|
|
722
|
+
When APNs or FCM reports a token as invalid (app uninstalled, notifications disabled, token rotated), SitePong marks it inactive on the server side and stops sending. No client action needed. To force a refresh after an OS-level token change, call `registerDeviceToken()` again with the new token.
|
|
723
|
+
|
|
724
|
+
#### Endpoint reference
|
|
725
|
+
|
|
726
|
+
| Method | Path | Auth | SDK function |
|
|
727
|
+
|---|---|---|---|
|
|
728
|
+
| POST | `/api/push/tokens` | `X-API-Key: sp_live_*` | `registerDeviceToken()` |
|
|
729
|
+
| POST | `/api/push/live-activity-tokens` | `X-API-Key: sp_live_*` | `registerLiveActivityToken()` |
|
|
730
|
+
| POST | `/api/push/push-to-start-tokens` | `X-API-Key: sp_live_*` | `registerPushToStartToken()` |
|
|
731
|
+
| DELETE | `/api/push/live-activity-tokens` | `X-API-Key: sp_live_*` | `endLiveActivity()` |
|
|
732
|
+
| POST | `/api/push/send` | `Authorization: Bearer sp_push_*` | (server-side only) |
|
|
733
|
+
| POST | `/api/push/live-activity` | `Authorization: Bearer sp_push_*` | (server-side only) |
|
|
734
|
+
|
|
735
|
+
Default ingest endpoint: `https://ingest.sitepong.com`. Override via the `endpoint` option in `initRN()` or `SitePongRNProvider`.
|
|
736
|
+
|
|
599
737
|
### Device Intelligence (React Native)
|
|
600
738
|
|
|
601
739
|
Persistent device identification that **survives app reinstalls**. Requires the `@sitepong/device-id` native module.
|
package/dist/entries/rn.js
CHANGED
|
@@ -3160,7 +3160,20 @@ var RNPerformanceManager = class {
|
|
|
3160
3160
|
};
|
|
3161
3161
|
|
|
3162
3162
|
// src/react-native/push.ts
|
|
3163
|
+
var identifyHookInstalled = false;
|
|
3164
|
+
function ensureIdentifyHookInstalled() {
|
|
3165
|
+
if (identifyHookInstalled) return;
|
|
3166
|
+
identifyHookInstalled = true;
|
|
3167
|
+
try {
|
|
3168
|
+
const c = sitepong;
|
|
3169
|
+
if (typeof c.registerIdentifyHook === "function") {
|
|
3170
|
+
c.registerIdentifyHook(reRegisterTokensWithUserId);
|
|
3171
|
+
}
|
|
3172
|
+
} catch {
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3163
3175
|
var cachedDeviceContext = null;
|
|
3176
|
+
var registeredPushToken = null;
|
|
3164
3177
|
var registeredLiveActivityTokens = /* @__PURE__ */ new Map();
|
|
3165
3178
|
var registeredPushToStartTokens = /* @__PURE__ */ new Map();
|
|
3166
3179
|
function getEndpoint() {
|
|
@@ -3241,9 +3254,10 @@ async function deleteFromIngest(path, body) {
|
|
|
3241
3254
|
}
|
|
3242
3255
|
}
|
|
3243
3256
|
function registerDeviceToken(token, options) {
|
|
3257
|
+
ensureIdentifyHookInstalled();
|
|
3244
3258
|
const device = getDeviceContext();
|
|
3245
3259
|
const tokenType = options.platform === "ios" ? "apns" : "fcm";
|
|
3246
|
-
|
|
3260
|
+
registeredPushToken = { token, environment: options.environment };
|
|
3247
3261
|
postToIngest("/api/push/tokens", {
|
|
3248
3262
|
native_device_token: token,
|
|
3249
3263
|
token_type: tokenType,
|
|
@@ -3257,6 +3271,7 @@ function registerDeviceToken(token, options) {
|
|
|
3257
3271
|
});
|
|
3258
3272
|
}
|
|
3259
3273
|
function registerLiveActivityToken(activityType, activityId, pushToken, options) {
|
|
3274
|
+
ensureIdentifyHookInstalled();
|
|
3260
3275
|
const device = getDeviceContext();
|
|
3261
3276
|
const userId = getUserId();
|
|
3262
3277
|
const key = `${activityType}:${activityId}`;
|
|
@@ -3276,6 +3291,7 @@ function registerLiveActivityToken(activityType, activityId, pushToken, options)
|
|
|
3276
3291
|
});
|
|
3277
3292
|
}
|
|
3278
3293
|
function registerPushToStartToken(activityType, pushToStartToken, options) {
|
|
3294
|
+
ensureIdentifyHookInstalled();
|
|
3279
3295
|
const device = getDeviceContext();
|
|
3280
3296
|
const userId = getUserId();
|
|
3281
3297
|
registeredPushToStartTokens.set(activityType, {
|
|
@@ -3299,6 +3315,42 @@ function endLiveActivity(activityType, activityId) {
|
|
|
3299
3315
|
activity_id: activityId
|
|
3300
3316
|
});
|
|
3301
3317
|
}
|
|
3318
|
+
function reRegisterTokensWithUserId(userId) {
|
|
3319
|
+
if (registeredPushToken) {
|
|
3320
|
+
const device = getDeviceContext();
|
|
3321
|
+
postToIngest("/api/push/tokens", {
|
|
3322
|
+
expo_push_token: registeredPushToken.token,
|
|
3323
|
+
environment: registeredPushToken.environment,
|
|
3324
|
+
device_id: device.deviceId,
|
|
3325
|
+
user_id: userId,
|
|
3326
|
+
platform: device.platform,
|
|
3327
|
+
app_version: device.appVersion,
|
|
3328
|
+
device_model: device.deviceModel,
|
|
3329
|
+
os_version: device.osVersion
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
for (const entry of registeredLiveActivityTokens.values()) {
|
|
3333
|
+
const device = getDeviceContext();
|
|
3334
|
+
postToIngest("/api/push/live-activity-tokens", {
|
|
3335
|
+
activity_type: entry.activityType,
|
|
3336
|
+
activity_id: entry.activityId,
|
|
3337
|
+
push_token: entry.token,
|
|
3338
|
+
environment: entry.environment,
|
|
3339
|
+
device_id: device.deviceId,
|
|
3340
|
+
user_id: userId
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
for (const entry of registeredPushToStartTokens.values()) {
|
|
3344
|
+
const device = getDeviceContext();
|
|
3345
|
+
postToIngest("/api/push/push-to-start-tokens", {
|
|
3346
|
+
activity_type: entry.activityType,
|
|
3347
|
+
push_to_start_token: entry.token,
|
|
3348
|
+
environment: entry.environment,
|
|
3349
|
+
device_id: device.deviceId,
|
|
3350
|
+
user_id: userId
|
|
3351
|
+
});
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3302
3354
|
var SitePongRNContext = react.createContext({
|
|
3303
3355
|
isInitialized: false,
|
|
3304
3356
|
performanceManager: null
|