@cloudparse/up-miniapps-sdk 0.6.0 → 0.6.1
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/dist/index.browser.min.js +19 -19
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +156 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +162 -1
- package/dist/index.d.ts +162 -1
- package/dist/index.js +155 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -70,6 +70,8 @@ interface IUserProfile {
|
|
|
70
70
|
countryCode: string;
|
|
71
71
|
/** Phone number without country code. */
|
|
72
72
|
localNumber: string;
|
|
73
|
+
/** How the user's account was created/registered. */
|
|
74
|
+
registrationType: "up" | "apple" | "google";
|
|
73
75
|
/** Admin status. */
|
|
74
76
|
admin: boolean;
|
|
75
77
|
/** UP points balance. */
|
|
@@ -1608,4 +1610,163 @@ interface ApiServiceClient {
|
|
|
1608
1610
|
*/
|
|
1609
1611
|
declare function createApiService(options: CreateApiServiceOptions): ApiServiceClient;
|
|
1610
1612
|
|
|
1611
|
-
|
|
1613
|
+
interface WsMessage {
|
|
1614
|
+
event?: string;
|
|
1615
|
+
[key: string]: unknown;
|
|
1616
|
+
}
|
|
1617
|
+
interface BaseWsServiceOptions<TMessage extends WsMessage> {
|
|
1618
|
+
/**
|
|
1619
|
+
* The REST client from `createApiService` — reused here for two things:
|
|
1620
|
+
* its live `wsUrl` (so this shares the exact same URL resolution as
|
|
1621
|
+
* every REST/GraphQL call, no separate copy to go stale), and its
|
|
1622
|
+
* `post()` to mint a short-lived WS auth ticket in production (see
|
|
1623
|
+
* `ticketPath` below).
|
|
1624
|
+
*/
|
|
1625
|
+
api: Pick<ApiServiceClient, "post" | "wsUrl">;
|
|
1626
|
+
/**
|
|
1627
|
+
* REST path (relative, via `api.post`) that mints a short-lived,
|
|
1628
|
+
* single-use ticket for the WS handshake — a mini-app's JS never holds
|
|
1629
|
+
* its own real bearer token in production (`sdk.network.request` proxies
|
|
1630
|
+
* every REST/GraphQL call through the native host shell, which injects
|
|
1631
|
+
* auth on its own side; a raw browser `WebSocket` has no equivalent
|
|
1632
|
+
* bridge and no way to set a custom header, so it authenticates via a
|
|
1633
|
+
* ticket fetched over that same working REST path instead). Expected to
|
|
1634
|
+
* return `{ ticket: string }`. Defaults to `"/ws-ticket"`, matching the
|
|
1635
|
+
* established backend convention (see up-miniapps-backend's
|
|
1636
|
+
* `GetWSTicket`). Pass `null` to disable ticket auth entirely — only
|
|
1637
|
+
* appropriate for a mini-app whose backend has no ws-ticket route yet,
|
|
1638
|
+
* or a genuinely public route (see `requireAuth` below).
|
|
1639
|
+
*/
|
|
1640
|
+
ticketPath?: string | null;
|
|
1641
|
+
/**
|
|
1642
|
+
* Raw JWT to use when NOT running inside the native shell (standalone
|
|
1643
|
+
* dev browser) — the consuming app reads its own build-time
|
|
1644
|
+
* `import.meta.env.VITE_DEV_TOKEN` and passes it here; the SDK itself
|
|
1645
|
+
* has no access to a consuming app's Vite env (this package is bundled
|
|
1646
|
+
* by tsup, not Vite). Only ever used outside the shell — a ticket is
|
|
1647
|
+
* always preferred when `isRunningInsideNativeShell()` is true.
|
|
1648
|
+
*/
|
|
1649
|
+
devToken?: string | null;
|
|
1650
|
+
/**
|
|
1651
|
+
* Overrides the resolved WS URL outright, for a mini-app whose WS
|
|
1652
|
+
* gateway genuinely lives somewhere `api.wsUrl` doesn't cover. Most
|
|
1653
|
+
* consumers should leave this unset and rely on `api.wsUrl`.
|
|
1654
|
+
*/
|
|
1655
|
+
baseUrl?: string;
|
|
1656
|
+
/**
|
|
1657
|
+
* Extra static query params appended to every connection URL. Browsers
|
|
1658
|
+
* (and this WebView) give a raw `WebSocket` no custom-header API — a
|
|
1659
|
+
* query param is the closest equivalent, e.g. for a custom auth scheme
|
|
1660
|
+
* on top of the ticket/token this already sends.
|
|
1661
|
+
*/
|
|
1662
|
+
query?: Record<string, string>;
|
|
1663
|
+
/**
|
|
1664
|
+
* When unset/`true` (the default), `connect()` refuses — warns and
|
|
1665
|
+
* delays rather than opening an unauthenticated socket — if neither a
|
|
1666
|
+
* ticket nor `devToken` is available. This is a deliberate safety net:
|
|
1667
|
+
* a channel-scoped app (ticket-authorized per-room access) accidentally
|
|
1668
|
+
* shipping with no auth configured would silently become an open room,
|
|
1669
|
+
* not a loud failure.
|
|
1670
|
+
*
|
|
1671
|
+
* Set to `false` only for a backend route that's genuinely public with
|
|
1672
|
+
* no per-connection identity at all — e.g. up-miniapps-by-night's `/ws`,
|
|
1673
|
+
* which has no auth middleware by design, broadcasts the same public
|
|
1674
|
+
* data to every connection, and has no rooms to gate. `connect()` then
|
|
1675
|
+
* opens the socket with no ticket/token query param whatsoever. Pair
|
|
1676
|
+
* with `ticketPath: null` (no point minting a ticket nobody checks).
|
|
1677
|
+
*/
|
|
1678
|
+
requireAuth?: boolean;
|
|
1679
|
+
}
|
|
1680
|
+
/** Options for the channel-scoped mode — pass `channelField` to subscribe/unsubscribe to specific rooms. */
|
|
1681
|
+
interface CreateChannelWsServiceOptions<TMessage extends WsMessage = WsMessage> extends BaseWsServiceOptions<TMessage> {
|
|
1682
|
+
/**
|
|
1683
|
+
* Name of the field on each message that identifies which "room"/channel
|
|
1684
|
+
* it belongs to (e.g. `"groupUuid"`, `"gameUuid"`). Also the field name
|
|
1685
|
+
* used in the `{action, [channelField]: id}` subscribe/unsubscribe wire
|
|
1686
|
+
* messages sent to the backend. Presence of this field is what selects
|
|
1687
|
+
* channel mode over broadcast mode — see `CreateBroadcastWsServiceOptions`.
|
|
1688
|
+
*/
|
|
1689
|
+
channelField: string;
|
|
1690
|
+
}
|
|
1691
|
+
/** Options for broadcast mode — omit `channelField` for a single global socket with no room concept. */
|
|
1692
|
+
interface CreateBroadcastWsServiceOptions<TMessage extends WsMessage = WsMessage> extends BaseWsServiceOptions<TMessage> {
|
|
1693
|
+
channelField?: undefined;
|
|
1694
|
+
}
|
|
1695
|
+
type CreateWsServiceOptions<TMessage extends WsMessage = WsMessage> = CreateChannelWsServiceOptions<TMessage> | CreateBroadcastWsServiceOptions<TMessage>;
|
|
1696
|
+
interface WsServiceClient<TMessage extends WsMessage = WsMessage> {
|
|
1697
|
+
/** Opens the connection if not already open/connecting. Safe to call repeatedly. */
|
|
1698
|
+
connect(): Promise<void>;
|
|
1699
|
+
/** Closes the connection and cancels any pending reconnect — no further automatic reconnect happens until `connect()`/`subscribe()` is called again. */
|
|
1700
|
+
disconnect(): void;
|
|
1701
|
+
/**
|
|
1702
|
+
* Subscribes to every message for one channel id. Sends the shared
|
|
1703
|
+
* `{action: "subscribe", [channelField]: id}` wire message automatically
|
|
1704
|
+
* on the first subscriber for that channel (and `"unsubscribe"` on the
|
|
1705
|
+
* last one leaving), and implicitly calls `connect()`. Returns an
|
|
1706
|
+
* unsubscribe function. Multiple concurrent channel ids are fully
|
|
1707
|
+
* supported — each gets its own wire subscribe/unsubscribe message and
|
|
1708
|
+
* its own dispatch, independent of every other channel's subscribers.
|
|
1709
|
+
*/
|
|
1710
|
+
subscribe(channelId: string, callback: (message: TMessage) => void): () => void;
|
|
1711
|
+
/**
|
|
1712
|
+
* Subscribes to every message this socket ever receives, regardless of
|
|
1713
|
+
* channel — no wire message is sent for this (there's nothing to
|
|
1714
|
+
* subscribe/unsubscribe to, it's just an additional tap on the same
|
|
1715
|
+
* stream). Runs *alongside* any active `subscribe()` channel
|
|
1716
|
+
* subscriptions, socket.io-style ("join specific rooms AND listen
|
|
1717
|
+
* globally at once") — a message matching an active channel id is
|
|
1718
|
+
* delivered to both that channel's subscribers and every `onMessage`
|
|
1719
|
+
* listener. Implicitly calls `connect()`. Returns an unsubscribe
|
|
1720
|
+
* function.
|
|
1721
|
+
*/
|
|
1722
|
+
onMessage(callback: (message: TMessage) => void): () => void;
|
|
1723
|
+
}
|
|
1724
|
+
interface BroadcastWsServiceClient<TMessage extends WsMessage = WsMessage> {
|
|
1725
|
+
/** Opens the connection if not already open/connecting. Safe to call repeatedly. */
|
|
1726
|
+
connect(): Promise<void>;
|
|
1727
|
+
/** Closes the connection and cancels any pending reconnect. */
|
|
1728
|
+
disconnect(): void;
|
|
1729
|
+
/**
|
|
1730
|
+
* Subscribes to every message this socket ever receives — there's no
|
|
1731
|
+
* room/channel concept in broadcast mode, so no subscribe/unsubscribe
|
|
1732
|
+
* wire message is ever sent; the backend just pushes to every connected
|
|
1733
|
+
* client. Implicitly calls `connect()`. Returns an unsubscribe function.
|
|
1734
|
+
*/
|
|
1735
|
+
onMessage(callback: (message: TMessage) => void): () => void;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Creates a reconnecting, (usually) authenticated WebSocket client — the WS
|
|
1739
|
+
* counterpart to `createApiService`. Centralizes exactly what every
|
|
1740
|
+
* `up-miniapps-*` app was independently hand-rolling with small drifting
|
|
1741
|
+
* bugs (one app's WS URL was captured once at construction and never
|
|
1742
|
+
* recomputed for the whole session; another always used a dev-only token
|
|
1743
|
+
* even in production, so it could never actually authenticate on a real
|
|
1744
|
+
* device): live URL resolution, ticket-based production auth with a
|
|
1745
|
+
* standalone-dev-token fallback, and exponential-backoff reconnect.
|
|
1746
|
+
*
|
|
1747
|
+
* Two modes, selected by whether `channelField` is present:
|
|
1748
|
+
* - **Channel mode** (`channelField` set): room-scoped pub/sub, matches
|
|
1749
|
+
* up-miniapps-split/up-miniapps-cursor's group/game-room shape. Returns a
|
|
1750
|
+
* `WsServiceClient` with `subscribe(channelId, cb)` — multiple concurrent
|
|
1751
|
+
* channel ids are fully supported — PLUS `onMessage(cb)`, a catch-all that
|
|
1752
|
+
* runs alongside any active channel subscriptions (socket.io-style: join
|
|
1753
|
+
* specific rooms and listen globally at the same time, on one socket).
|
|
1754
|
+
* - **Broadcast mode** (`channelField` omitted): one global socket, no
|
|
1755
|
+
* rooms, no subscribe/unsubscribe wire protocol — every message goes to
|
|
1756
|
+
* every listener. Matches up-miniapps-by-night's public live-update feed
|
|
1757
|
+
* (reactions/flash/favorite counts), which has no per-room access to gate
|
|
1758
|
+
* in the first place. Returns a `BroadcastWsServiceClient` with only
|
|
1759
|
+
* `onMessage(cb)` (no `subscribe` — there's no channel id to subscribe to).
|
|
1760
|
+
*
|
|
1761
|
+
* Deliberately stays a thin transport in both modes, same boundary as
|
|
1762
|
+
* `createApiService`: message *content* interpretation (e.g. treating one
|
|
1763
|
+
* event name as carrying real payload while every other message is a bare
|
|
1764
|
+
* cache-invalidation ping) belongs in each app's own thin wrapper around
|
|
1765
|
+
* this, not here — apps differ enough in what they consider safe to expose
|
|
1766
|
+
* over WS that baking that policy into the SDK would be the wrong
|
|
1767
|
+
* boundary.
|
|
1768
|
+
*/
|
|
1769
|
+
declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateChannelWsServiceOptions<TMessage>): WsServiceClient<TMessage>;
|
|
1770
|
+
declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateBroadcastWsServiceOptions<TMessage>): BroadcastWsServiceClient<TMessage>;
|
|
1771
|
+
|
|
1772
|
+
export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,8 @@ interface IUserProfile {
|
|
|
70
70
|
countryCode: string;
|
|
71
71
|
/** Phone number without country code. */
|
|
72
72
|
localNumber: string;
|
|
73
|
+
/** How the user's account was created/registered. */
|
|
74
|
+
registrationType: "up" | "apple" | "google";
|
|
73
75
|
/** Admin status. */
|
|
74
76
|
admin: boolean;
|
|
75
77
|
/** UP points balance. */
|
|
@@ -1608,4 +1610,163 @@ interface ApiServiceClient {
|
|
|
1608
1610
|
*/
|
|
1609
1611
|
declare function createApiService(options: CreateApiServiceOptions): ApiServiceClient;
|
|
1610
1612
|
|
|
1611
|
-
|
|
1613
|
+
interface WsMessage {
|
|
1614
|
+
event?: string;
|
|
1615
|
+
[key: string]: unknown;
|
|
1616
|
+
}
|
|
1617
|
+
interface BaseWsServiceOptions<TMessage extends WsMessage> {
|
|
1618
|
+
/**
|
|
1619
|
+
* The REST client from `createApiService` — reused here for two things:
|
|
1620
|
+
* its live `wsUrl` (so this shares the exact same URL resolution as
|
|
1621
|
+
* every REST/GraphQL call, no separate copy to go stale), and its
|
|
1622
|
+
* `post()` to mint a short-lived WS auth ticket in production (see
|
|
1623
|
+
* `ticketPath` below).
|
|
1624
|
+
*/
|
|
1625
|
+
api: Pick<ApiServiceClient, "post" | "wsUrl">;
|
|
1626
|
+
/**
|
|
1627
|
+
* REST path (relative, via `api.post`) that mints a short-lived,
|
|
1628
|
+
* single-use ticket for the WS handshake — a mini-app's JS never holds
|
|
1629
|
+
* its own real bearer token in production (`sdk.network.request` proxies
|
|
1630
|
+
* every REST/GraphQL call through the native host shell, which injects
|
|
1631
|
+
* auth on its own side; a raw browser `WebSocket` has no equivalent
|
|
1632
|
+
* bridge and no way to set a custom header, so it authenticates via a
|
|
1633
|
+
* ticket fetched over that same working REST path instead). Expected to
|
|
1634
|
+
* return `{ ticket: string }`. Defaults to `"/ws-ticket"`, matching the
|
|
1635
|
+
* established backend convention (see up-miniapps-backend's
|
|
1636
|
+
* `GetWSTicket`). Pass `null` to disable ticket auth entirely — only
|
|
1637
|
+
* appropriate for a mini-app whose backend has no ws-ticket route yet,
|
|
1638
|
+
* or a genuinely public route (see `requireAuth` below).
|
|
1639
|
+
*/
|
|
1640
|
+
ticketPath?: string | null;
|
|
1641
|
+
/**
|
|
1642
|
+
* Raw JWT to use when NOT running inside the native shell (standalone
|
|
1643
|
+
* dev browser) — the consuming app reads its own build-time
|
|
1644
|
+
* `import.meta.env.VITE_DEV_TOKEN` and passes it here; the SDK itself
|
|
1645
|
+
* has no access to a consuming app's Vite env (this package is bundled
|
|
1646
|
+
* by tsup, not Vite). Only ever used outside the shell — a ticket is
|
|
1647
|
+
* always preferred when `isRunningInsideNativeShell()` is true.
|
|
1648
|
+
*/
|
|
1649
|
+
devToken?: string | null;
|
|
1650
|
+
/**
|
|
1651
|
+
* Overrides the resolved WS URL outright, for a mini-app whose WS
|
|
1652
|
+
* gateway genuinely lives somewhere `api.wsUrl` doesn't cover. Most
|
|
1653
|
+
* consumers should leave this unset and rely on `api.wsUrl`.
|
|
1654
|
+
*/
|
|
1655
|
+
baseUrl?: string;
|
|
1656
|
+
/**
|
|
1657
|
+
* Extra static query params appended to every connection URL. Browsers
|
|
1658
|
+
* (and this WebView) give a raw `WebSocket` no custom-header API — a
|
|
1659
|
+
* query param is the closest equivalent, e.g. for a custom auth scheme
|
|
1660
|
+
* on top of the ticket/token this already sends.
|
|
1661
|
+
*/
|
|
1662
|
+
query?: Record<string, string>;
|
|
1663
|
+
/**
|
|
1664
|
+
* When unset/`true` (the default), `connect()` refuses — warns and
|
|
1665
|
+
* delays rather than opening an unauthenticated socket — if neither a
|
|
1666
|
+
* ticket nor `devToken` is available. This is a deliberate safety net:
|
|
1667
|
+
* a channel-scoped app (ticket-authorized per-room access) accidentally
|
|
1668
|
+
* shipping with no auth configured would silently become an open room,
|
|
1669
|
+
* not a loud failure.
|
|
1670
|
+
*
|
|
1671
|
+
* Set to `false` only for a backend route that's genuinely public with
|
|
1672
|
+
* no per-connection identity at all — e.g. up-miniapps-by-night's `/ws`,
|
|
1673
|
+
* which has no auth middleware by design, broadcasts the same public
|
|
1674
|
+
* data to every connection, and has no rooms to gate. `connect()` then
|
|
1675
|
+
* opens the socket with no ticket/token query param whatsoever. Pair
|
|
1676
|
+
* with `ticketPath: null` (no point minting a ticket nobody checks).
|
|
1677
|
+
*/
|
|
1678
|
+
requireAuth?: boolean;
|
|
1679
|
+
}
|
|
1680
|
+
/** Options for the channel-scoped mode — pass `channelField` to subscribe/unsubscribe to specific rooms. */
|
|
1681
|
+
interface CreateChannelWsServiceOptions<TMessage extends WsMessage = WsMessage> extends BaseWsServiceOptions<TMessage> {
|
|
1682
|
+
/**
|
|
1683
|
+
* Name of the field on each message that identifies which "room"/channel
|
|
1684
|
+
* it belongs to (e.g. `"groupUuid"`, `"gameUuid"`). Also the field name
|
|
1685
|
+
* used in the `{action, [channelField]: id}` subscribe/unsubscribe wire
|
|
1686
|
+
* messages sent to the backend. Presence of this field is what selects
|
|
1687
|
+
* channel mode over broadcast mode — see `CreateBroadcastWsServiceOptions`.
|
|
1688
|
+
*/
|
|
1689
|
+
channelField: string;
|
|
1690
|
+
}
|
|
1691
|
+
/** Options for broadcast mode — omit `channelField` for a single global socket with no room concept. */
|
|
1692
|
+
interface CreateBroadcastWsServiceOptions<TMessage extends WsMessage = WsMessage> extends BaseWsServiceOptions<TMessage> {
|
|
1693
|
+
channelField?: undefined;
|
|
1694
|
+
}
|
|
1695
|
+
type CreateWsServiceOptions<TMessage extends WsMessage = WsMessage> = CreateChannelWsServiceOptions<TMessage> | CreateBroadcastWsServiceOptions<TMessage>;
|
|
1696
|
+
interface WsServiceClient<TMessage extends WsMessage = WsMessage> {
|
|
1697
|
+
/** Opens the connection if not already open/connecting. Safe to call repeatedly. */
|
|
1698
|
+
connect(): Promise<void>;
|
|
1699
|
+
/** Closes the connection and cancels any pending reconnect — no further automatic reconnect happens until `connect()`/`subscribe()` is called again. */
|
|
1700
|
+
disconnect(): void;
|
|
1701
|
+
/**
|
|
1702
|
+
* Subscribes to every message for one channel id. Sends the shared
|
|
1703
|
+
* `{action: "subscribe", [channelField]: id}` wire message automatically
|
|
1704
|
+
* on the first subscriber for that channel (and `"unsubscribe"` on the
|
|
1705
|
+
* last one leaving), and implicitly calls `connect()`. Returns an
|
|
1706
|
+
* unsubscribe function. Multiple concurrent channel ids are fully
|
|
1707
|
+
* supported — each gets its own wire subscribe/unsubscribe message and
|
|
1708
|
+
* its own dispatch, independent of every other channel's subscribers.
|
|
1709
|
+
*/
|
|
1710
|
+
subscribe(channelId: string, callback: (message: TMessage) => void): () => void;
|
|
1711
|
+
/**
|
|
1712
|
+
* Subscribes to every message this socket ever receives, regardless of
|
|
1713
|
+
* channel — no wire message is sent for this (there's nothing to
|
|
1714
|
+
* subscribe/unsubscribe to, it's just an additional tap on the same
|
|
1715
|
+
* stream). Runs *alongside* any active `subscribe()` channel
|
|
1716
|
+
* subscriptions, socket.io-style ("join specific rooms AND listen
|
|
1717
|
+
* globally at once") — a message matching an active channel id is
|
|
1718
|
+
* delivered to both that channel's subscribers and every `onMessage`
|
|
1719
|
+
* listener. Implicitly calls `connect()`. Returns an unsubscribe
|
|
1720
|
+
* function.
|
|
1721
|
+
*/
|
|
1722
|
+
onMessage(callback: (message: TMessage) => void): () => void;
|
|
1723
|
+
}
|
|
1724
|
+
interface BroadcastWsServiceClient<TMessage extends WsMessage = WsMessage> {
|
|
1725
|
+
/** Opens the connection if not already open/connecting. Safe to call repeatedly. */
|
|
1726
|
+
connect(): Promise<void>;
|
|
1727
|
+
/** Closes the connection and cancels any pending reconnect. */
|
|
1728
|
+
disconnect(): void;
|
|
1729
|
+
/**
|
|
1730
|
+
* Subscribes to every message this socket ever receives — there's no
|
|
1731
|
+
* room/channel concept in broadcast mode, so no subscribe/unsubscribe
|
|
1732
|
+
* wire message is ever sent; the backend just pushes to every connected
|
|
1733
|
+
* client. Implicitly calls `connect()`. Returns an unsubscribe function.
|
|
1734
|
+
*/
|
|
1735
|
+
onMessage(callback: (message: TMessage) => void): () => void;
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Creates a reconnecting, (usually) authenticated WebSocket client — the WS
|
|
1739
|
+
* counterpart to `createApiService`. Centralizes exactly what every
|
|
1740
|
+
* `up-miniapps-*` app was independently hand-rolling with small drifting
|
|
1741
|
+
* bugs (one app's WS URL was captured once at construction and never
|
|
1742
|
+
* recomputed for the whole session; another always used a dev-only token
|
|
1743
|
+
* even in production, so it could never actually authenticate on a real
|
|
1744
|
+
* device): live URL resolution, ticket-based production auth with a
|
|
1745
|
+
* standalone-dev-token fallback, and exponential-backoff reconnect.
|
|
1746
|
+
*
|
|
1747
|
+
* Two modes, selected by whether `channelField` is present:
|
|
1748
|
+
* - **Channel mode** (`channelField` set): room-scoped pub/sub, matches
|
|
1749
|
+
* up-miniapps-split/up-miniapps-cursor's group/game-room shape. Returns a
|
|
1750
|
+
* `WsServiceClient` with `subscribe(channelId, cb)` — multiple concurrent
|
|
1751
|
+
* channel ids are fully supported — PLUS `onMessage(cb)`, a catch-all that
|
|
1752
|
+
* runs alongside any active channel subscriptions (socket.io-style: join
|
|
1753
|
+
* specific rooms and listen globally at the same time, on one socket).
|
|
1754
|
+
* - **Broadcast mode** (`channelField` omitted): one global socket, no
|
|
1755
|
+
* rooms, no subscribe/unsubscribe wire protocol — every message goes to
|
|
1756
|
+
* every listener. Matches up-miniapps-by-night's public live-update feed
|
|
1757
|
+
* (reactions/flash/favorite counts), which has no per-room access to gate
|
|
1758
|
+
* in the first place. Returns a `BroadcastWsServiceClient` with only
|
|
1759
|
+
* `onMessage(cb)` (no `subscribe` — there's no channel id to subscribe to).
|
|
1760
|
+
*
|
|
1761
|
+
* Deliberately stays a thin transport in both modes, same boundary as
|
|
1762
|
+
* `createApiService`: message *content* interpretation (e.g. treating one
|
|
1763
|
+
* event name as carrying real payload while every other message is a bare
|
|
1764
|
+
* cache-invalidation ping) belongs in each app's own thin wrapper around
|
|
1765
|
+
* this, not here — apps differ enough in what they consider safe to expose
|
|
1766
|
+
* over WS that baking that policy into the SDK would be the wrong
|
|
1767
|
+
* boundary.
|
|
1768
|
+
*/
|
|
1769
|
+
declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateChannelWsServiceOptions<TMessage>): WsServiceClient<TMessage>;
|
|
1770
|
+
declare function createWsService<TMessage extends WsMessage = WsMessage>(options: CreateBroadcastWsServiceOptions<TMessage>): BroadcastWsServiceClient<TMessage>;
|
|
1771
|
+
|
|
1772
|
+
export { type ApiServiceClient, type BridgeMessageType, BridgeMocker, type BridgeMockerProps, type BroadcastWsServiceClient, type CenterCallbackParams, type CreateApiServiceOptions, type CreateBroadcastWsServiceOptions, type CreateChannelWsServiceOptions, type CreateWsServiceOptions, type CustomControl, DebugConsole, type DebugConsoleProps, type DeclarativeJourneyOptions, type DrawerState, type EtaData, type FidelityTransactionTypeType, type FlyToParams, GeolocationEvent, GlobalEvent, type HapticStyleType, type IBridgeEnvelope, type IContextState, type IEdgeInsets, type IFidelityBalance, type IFidelityHistoryParams, type IFidelityTransaction, type IGenerateQrCodeOptions, type IInitializationOptions, type IInitializationResponse, type ILocationData, type INetworkOptions, type INetworkResponse, type IPaymentRequest, type IPickImageResult, type ISaveImageResult, type IUserProfile, type LiveRoutingOptions, type LiveRoutingResult, type LocationStreamConfig, Map, MapControls, MapControlsContext, type MapControlsProps, type MapControlsState, type MapInsets, MapMenu, MapMenuDivider, type MapMenuDividerProps, MapMenuFooter, type MapMenuFooterProps, MapMenuItem, type MapMenuItemProps, type MapMenuProps, MapMenuTitle, type MapMenuTitleProps, type MapProps, type MenuItem, MiniAppSDK, MockLocationContext, type MockLocationContextType, type NetworkMethodType, type POI, QRScanner, type QRScannerProps, RouteLayer, type RouteLayerProps, RouteRequest, RouteResponse, RouteStep, type SDKEvent, SDKMapProvider, SDKProvider, type SDKProviderProps, type ScrollConfig, type StreamAccelerometerData, type StreamHeadingData, type StreamLocationData, type StreamUpdatePayload, type SwipeAxisPriority, SwipeCarousel, type SwipeCarouselItem, type SwipeCarouselProps, type SwipeCarouselVerticalDragConfig, UIEvent, type UseJourneyOptions, type UseJourneyResult, type UserLocationState, type WsMessage, type WsServiceClient, createApiService, createWsService, sdk as default, renderMap, sdk, useIsMocked, useJourney, useLiveRouting, useMapControls, useMockLocation, useRoute, useTrimmedRoute, useUserLocation };
|
package/dist/index.js
CHANGED
|
@@ -62,6 +62,13 @@ var Button = React.forwardRef(
|
|
|
62
62
|
);
|
|
63
63
|
Button.displayName = "Button";
|
|
64
64
|
|
|
65
|
+
// src/utils/environment.ts
|
|
66
|
+
function isRunningInsideNativeShell() {
|
|
67
|
+
if (typeof window === "undefined") return false;
|
|
68
|
+
const w = window;
|
|
69
|
+
return w.__UP_REACT_NATIVE_APP__ === true || !!w.ReactNativeWebView;
|
|
70
|
+
}
|
|
71
|
+
|
|
65
72
|
// src/bridge.ts
|
|
66
73
|
var BridgeTimeoutError = class extends Error {
|
|
67
74
|
};
|
|
@@ -234,8 +241,7 @@ var Bridge = class {
|
|
|
234
241
|
* Determine environment. Check flag or cache result.
|
|
235
242
|
*/
|
|
236
243
|
isNative() {
|
|
237
|
-
|
|
238
|
-
return window.__UP_REACT_NATIVE_APP__ === true || !!window.ReactNativeWebView;
|
|
244
|
+
return isRunningInsideNativeShell();
|
|
239
245
|
}
|
|
240
246
|
};
|
|
241
247
|
|
|
@@ -1995,14 +2001,14 @@ var useUserLocation = () => {
|
|
|
1995
2001
|
});
|
|
1996
2002
|
const mapPayload = useCallback3((payload) => {
|
|
1997
2003
|
const coords = payload.location?.coords || payload.coords;
|
|
1998
|
-
const headingData = payload.heading
|
|
2004
|
+
const headingData = payload.heading;
|
|
1999
2005
|
const newCoords = coords ? [coords.longitude, coords.latitude] : null;
|
|
2000
2006
|
let heading = null;
|
|
2001
2007
|
if (headingData?.trueHeading !== void 0 && headingData.trueHeading >= 0) {
|
|
2002
2008
|
heading = headingData.trueHeading;
|
|
2003
2009
|
} else if (headingData?.magneticHeading !== void 0 && headingData.magneticHeading >= 0) {
|
|
2004
2010
|
heading = headingData.magneticHeading;
|
|
2005
|
-
} else if (headingData?.heading !== null && headingData
|
|
2011
|
+
} else if (headingData?.heading !== null && headingData?.heading >= 0) {
|
|
2006
2012
|
heading = headingData.heading;
|
|
2007
2013
|
}
|
|
2008
2014
|
return {
|
|
@@ -2479,7 +2485,14 @@ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
|
2479
2485
|
var MockRadiusLayer = ({
|
|
2480
2486
|
center,
|
|
2481
2487
|
radiusMeters,
|
|
2482
|
-
color
|
|
2488
|
+
// Neutral gray, not any one app's accent color — this debug aid is shared
|
|
2489
|
+
// across every mini-app (each with its own, different palette), so it
|
|
2490
|
+
// shouldn't default to a color that reads as "part of the app" (was
|
|
2491
|
+
// #39ff88, a neon green/yellow left over from an earlier shared theme,
|
|
2492
|
+
// reported as looking like an unwanted yellow border around the user's
|
|
2493
|
+
// position marker in up-miniapps-explore, which has since moved to a
|
|
2494
|
+
// pastel palette with no neon accents at all).
|
|
2495
|
+
color = "#e2e8f0"
|
|
2483
2496
|
}) => {
|
|
2484
2497
|
const data = useMemo4(
|
|
2485
2498
|
() => buildGeoCircle(center, radiusMeters),
|
|
@@ -3474,7 +3487,7 @@ var loadImage2 = (src) => new Promise((resolve, reject) => {
|
|
|
3474
3487
|
});
|
|
3475
3488
|
|
|
3476
3489
|
// package.json
|
|
3477
|
-
var version = "0.6.
|
|
3490
|
+
var version = "0.6.1";
|
|
3478
3491
|
|
|
3479
3492
|
// src/sdk.ts
|
|
3480
3493
|
function deepFreeze(obj) {
|
|
@@ -5071,6 +5084,141 @@ function createApiService(options) {
|
|
|
5071
5084
|
};
|
|
5072
5085
|
}
|
|
5073
5086
|
|
|
5087
|
+
// src/services/wsService.ts
|
|
5088
|
+
function createWsService(options) {
|
|
5089
|
+
const channelField = options.channelField;
|
|
5090
|
+
let ws = null;
|
|
5091
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
5092
|
+
const globalListeners = /* @__PURE__ */ new Set();
|
|
5093
|
+
let reconnectTimeout = null;
|
|
5094
|
+
let reconnectDelay = 1e3;
|
|
5095
|
+
let isConnecting = false;
|
|
5096
|
+
const getWsUrl = () => options.baseUrl || options.api.wsUrl || "";
|
|
5097
|
+
const sendAction = (action, channelId) => {
|
|
5098
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
5099
|
+
ws.send(JSON.stringify({ action, [channelField]: channelId }));
|
|
5100
|
+
}
|
|
5101
|
+
};
|
|
5102
|
+
const scheduleReconnect = () => {
|
|
5103
|
+
if (reconnectTimeout) clearTimeout(reconnectTimeout);
|
|
5104
|
+
reconnectTimeout = setTimeout(() => {
|
|
5105
|
+
reconnectDelay = Math.min(reconnectDelay * 2, 3e4);
|
|
5106
|
+
connect();
|
|
5107
|
+
}, reconnectDelay);
|
|
5108
|
+
};
|
|
5109
|
+
const connect = async () => {
|
|
5110
|
+
if (ws?.readyState === WebSocket.OPEN || ws?.readyState === WebSocket.CONNECTING || isConnecting) {
|
|
5111
|
+
return;
|
|
5112
|
+
}
|
|
5113
|
+
isConnecting = true;
|
|
5114
|
+
try {
|
|
5115
|
+
const wsUrl = getWsUrl();
|
|
5116
|
+
if (!wsUrl) {
|
|
5117
|
+
console.warn(
|
|
5118
|
+
"[WS] No WebSocket backend URL available, connection delayed."
|
|
5119
|
+
);
|
|
5120
|
+
isConnecting = false;
|
|
5121
|
+
return;
|
|
5122
|
+
}
|
|
5123
|
+
let authParams = {};
|
|
5124
|
+
if (isRunningInsideNativeShell() && options.ticketPath !== null) {
|
|
5125
|
+
const ticketResponse = await options.api.post(
|
|
5126
|
+
options.ticketPath ?? "/ws-ticket"
|
|
5127
|
+
);
|
|
5128
|
+
authParams = { ticket: ticketResponse.data.ticket };
|
|
5129
|
+
} else if (options.devToken) {
|
|
5130
|
+
const rawJwt = options.devToken.startsWith("Bearer ") ? options.devToken.slice(7) : options.devToken;
|
|
5131
|
+
authParams = { token: rawJwt };
|
|
5132
|
+
} else if (options.requireAuth === false) {
|
|
5133
|
+
} else {
|
|
5134
|
+
console.warn("[WS] No auth available, connection delayed.");
|
|
5135
|
+
isConnecting = false;
|
|
5136
|
+
return;
|
|
5137
|
+
}
|
|
5138
|
+
const params = new URLSearchParams({ ...options.query, ...authParams });
|
|
5139
|
+
const query = params.toString();
|
|
5140
|
+
ws = new WebSocket(query ? `${wsUrl}?${query}` : wsUrl);
|
|
5141
|
+
ws.onopen = () => {
|
|
5142
|
+
isConnecting = false;
|
|
5143
|
+
reconnectDelay = 1e3;
|
|
5144
|
+
if (channelField) {
|
|
5145
|
+
for (const channelId of subscriptions.keys()) {
|
|
5146
|
+
sendAction("subscribe", channelId);
|
|
5147
|
+
}
|
|
5148
|
+
}
|
|
5149
|
+
};
|
|
5150
|
+
ws.onmessage = (event) => {
|
|
5151
|
+
try {
|
|
5152
|
+
const payload = JSON.parse(event.data);
|
|
5153
|
+
if (channelField) {
|
|
5154
|
+
const channelId = payload[channelField];
|
|
5155
|
+
if (typeof channelId === "string") {
|
|
5156
|
+
const callbacks = subscriptions.get(channelId);
|
|
5157
|
+
if (callbacks) {
|
|
5158
|
+
for (const cb of callbacks) cb(payload);
|
|
5159
|
+
}
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5162
|
+
for (const cb of globalListeners) cb(payload);
|
|
5163
|
+
} catch (err) {
|
|
5164
|
+
console.error("[WS] Failed to parse message:", err);
|
|
5165
|
+
}
|
|
5166
|
+
};
|
|
5167
|
+
ws.onclose = () => {
|
|
5168
|
+
isConnecting = false;
|
|
5169
|
+
scheduleReconnect();
|
|
5170
|
+
};
|
|
5171
|
+
ws.onerror = (err) => {
|
|
5172
|
+
console.error("[WS] error:", err);
|
|
5173
|
+
isConnecting = false;
|
|
5174
|
+
ws?.close();
|
|
5175
|
+
};
|
|
5176
|
+
} catch (err) {
|
|
5177
|
+
console.error("[WS] Failed to establish connection:", err);
|
|
5178
|
+
isConnecting = false;
|
|
5179
|
+
scheduleReconnect();
|
|
5180
|
+
}
|
|
5181
|
+
};
|
|
5182
|
+
const disconnect = () => {
|
|
5183
|
+
if (reconnectTimeout) {
|
|
5184
|
+
clearTimeout(reconnectTimeout);
|
|
5185
|
+
reconnectTimeout = null;
|
|
5186
|
+
}
|
|
5187
|
+
if (ws) {
|
|
5188
|
+
ws.onclose = null;
|
|
5189
|
+
ws.close();
|
|
5190
|
+
ws = null;
|
|
5191
|
+
}
|
|
5192
|
+
};
|
|
5193
|
+
const subscribe = (channelId, callback) => {
|
|
5194
|
+
const isNewChannel = !subscriptions.has(channelId);
|
|
5195
|
+
if (isNewChannel) subscriptions.set(channelId, /* @__PURE__ */ new Set());
|
|
5196
|
+
subscriptions.get(channelId)?.add(callback);
|
|
5197
|
+
if (isNewChannel) sendAction("subscribe", channelId);
|
|
5198
|
+
connect();
|
|
5199
|
+
return () => {
|
|
5200
|
+
const set = subscriptions.get(channelId);
|
|
5201
|
+
if (!set) return;
|
|
5202
|
+
set.delete(callback);
|
|
5203
|
+
if (set.size === 0) {
|
|
5204
|
+
subscriptions.delete(channelId);
|
|
5205
|
+
sendAction("unsubscribe", channelId);
|
|
5206
|
+
}
|
|
5207
|
+
};
|
|
5208
|
+
};
|
|
5209
|
+
const onMessage = (callback) => {
|
|
5210
|
+
globalListeners.add(callback);
|
|
5211
|
+
connect();
|
|
5212
|
+
return () => {
|
|
5213
|
+
globalListeners.delete(callback);
|
|
5214
|
+
};
|
|
5215
|
+
};
|
|
5216
|
+
if (channelField) {
|
|
5217
|
+
return { connect, disconnect, onMessage, subscribe };
|
|
5218
|
+
}
|
|
5219
|
+
return { connect, disconnect, onMessage };
|
|
5220
|
+
}
|
|
5221
|
+
|
|
5074
5222
|
// src/index.ts
|
|
5075
5223
|
var src_default = sdk;
|
|
5076
5224
|
export {
|
|
@@ -5095,6 +5243,7 @@ export {
|
|
|
5095
5243
|
SwipeCarousel,
|
|
5096
5244
|
UIEvent,
|
|
5097
5245
|
createApiService,
|
|
5246
|
+
createWsService,
|
|
5098
5247
|
src_default as default,
|
|
5099
5248
|
handleClearRoute,
|
|
5100
5249
|
handleDrawRoute,
|