@proappstore/sdk 1.8.0 → 1.9.0
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 +22 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/maps.d.ts +29 -2
- package/dist/maps.d.ts.map +1 -1
- package/dist/maps.js +18 -4
- package/dist/maps.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/usage.d.ts +65 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +205 -0
- package/dist/usage.js.map +1 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -170,6 +170,28 @@ const response = await app.storage.download('docs/resume.pdf')
|
|
|
170
170
|
await app.storage.delete('docs/resume.pdf')
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
+
### Usage tracking (auto-on; drives creator payouts)
|
|
174
|
+
|
|
175
|
+
ProAppStore is a single $9/mo subscription that unlocks every Pro app. Creators are paid monthly from the pool (minus the 10% platform fee) in proportion to their app's share of total usage. To compute that, the SDK heartbeats `POST /v1/usage/ping` every 60 seconds while the tab is visible and the user is signed in.
|
|
176
|
+
|
|
177
|
+
**Auto-started by `initPro()`** — you don't need to do anything for your app's usage to count toward your payout. Hidden tabs don't accrue time; closed tabs flush a final ping via `navigator.sendBeacon`.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// Default behavior — telemetry on
|
|
181
|
+
const app = initPro({ appId: 'my-app' })
|
|
182
|
+
|
|
183
|
+
// Opt out (your app won't count toward payouts; you also won't see analytics)
|
|
184
|
+
const app = initPro({ appId: 'my-app', usage: { auto: false } })
|
|
185
|
+
|
|
186
|
+
// Manual controls (rarely needed)
|
|
187
|
+
app.usage.start() // idempotent
|
|
188
|
+
app.usage.stop() // halt heartbeats
|
|
189
|
+
app.usage.recordApiCall(1) // piggybacks on next heartbeat
|
|
190
|
+
app.usage.flush() // final ping (called automatically on pagehide)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
What we record (also documented at <https://proappstore.online/privacy#usage-analytics>): per `(app, user, day)` rollups of session-seconds and API calls. No event-by-event logs, no IP, nothing while the tab is hidden or the user is signed out.
|
|
194
|
+
|
|
173
195
|
## React Hooks (recommended)
|
|
174
196
|
|
|
175
197
|
Hooks give you full control over your UI while the platform handles auth, subscriptions, and gating. Import from `@proappstore/sdk/hooks`.
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { SMS } from './sms.js';
|
|
|
7
7
|
import { Storage } from './storage.js';
|
|
8
8
|
import { SubscriptionApi } from './subscription.js';
|
|
9
9
|
import { LicenseApi } from './license.js';
|
|
10
|
+
import { Usage } from './usage.js';
|
|
10
11
|
import type { ProInitOptions } from './types.js';
|
|
11
12
|
export type { User, Unsubscribe, FasInitOptions, ConnectionState, Room, RoomMessage, RoomPeer, } from '@freeappstore/sdk';
|
|
12
13
|
export type { ProInitOptions, Subscription, SubscriptionStatus, CheckoutRequest, LicenseInfo, } from './types.js';
|
|
@@ -15,6 +16,8 @@ export type { NotificationPayload, SendResult } from './notifications.js';
|
|
|
15
16
|
export type { SmsSendResult } from './sms.js';
|
|
16
17
|
export type { TextModelAlias, EmbedModelAlias, ChatMessage, GenerateOptions, GenerateResult, EmbedOptions, EmbedResult, } from './ai.js';
|
|
17
18
|
export { TenantScope } from './tenant.js';
|
|
19
|
+
export { Usage } from './usage.js';
|
|
20
|
+
export type { UsageOptions } from './usage.js';
|
|
18
21
|
/**
|
|
19
22
|
* Pro SDK instance — includes everything from @freeappstore/sdk (auth, kv,
|
|
20
23
|
* counters, rooms, proxy) plus subscription management and license keys.
|
|
@@ -30,6 +33,7 @@ export declare class ProAppStore extends FreeAppStore {
|
|
|
30
33
|
readonly notifications: Notifications;
|
|
31
34
|
readonly sms: SMS;
|
|
32
35
|
readonly ai: AI;
|
|
36
|
+
readonly usage: Usage;
|
|
33
37
|
constructor(opts: ProInitOptions);
|
|
34
38
|
}
|
|
35
39
|
/** Create a new ProAppStore SDK instance. Includes all free + pro features. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,YAAY,EACV,IAAI,EACJ,WAAW,EACX,cAAc,EACd,eAAe,EACf,IAAI,EACJ,WAAW,EACX,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpF,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,YAAY,EACV,IAAI,EACJ,WAAW,EACX,cAAc,EACd,eAAe,EACf,IAAI,EACJ,WAAW,EACX,QAAQ,GACT,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACpF,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EACV,cAAc,EACd,eAAe,EACf,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,WAAY,SAAQ,YAAY;IAC3C,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;gBAEV,IAAI,EAAE,cAAc;CAiBjC;AAED,+EAA+E;AAC/E,wBAAgB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,WAAW,CAEzD"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,9 @@ import { SMS } from './sms.js';
|
|
|
7
7
|
import { Storage } from './storage.js';
|
|
8
8
|
import { SubscriptionApi } from './subscription.js';
|
|
9
9
|
import { LicenseApi } from './license.js';
|
|
10
|
+
import { Usage } from './usage.js';
|
|
10
11
|
export { TenantScope } from './tenant.js';
|
|
12
|
+
export { Usage } from './usage.js';
|
|
11
13
|
/**
|
|
12
14
|
* Pro SDK instance — includes everything from @freeappstore/sdk (auth, kv,
|
|
13
15
|
* counters, rooms, proxy) plus subscription management and license keys.
|
|
@@ -23,6 +25,7 @@ export class ProAppStore extends FreeAppStore {
|
|
|
23
25
|
notifications;
|
|
24
26
|
sms;
|
|
25
27
|
ai;
|
|
28
|
+
usage;
|
|
26
29
|
constructor(opts) {
|
|
27
30
|
super({ appId: opts.appId, ...(opts.fasApiBase && { apiBase: opts.fasApiBase }) });
|
|
28
31
|
const proApiBase = opts.proApiBase ?? 'https://api.proappstore.online';
|
|
@@ -34,6 +37,12 @@ export class ProAppStore extends FreeAppStore {
|
|
|
34
37
|
this.notifications = new Notifications(opts.appId, proApiBase, this.auth);
|
|
35
38
|
this.sms = new SMS(opts.appId, proApiBase, this.auth);
|
|
36
39
|
this.ai = new AI(proApiBase, this.auth);
|
|
40
|
+
this.usage = new Usage(opts.appId, proApiBase, this.auth);
|
|
41
|
+
// Auto-start telemetry unless the app opts out. `start()` is a no-op in
|
|
42
|
+
// SSR / non-browser contexts, so this is safe even when the SDK is
|
|
43
|
+
// imported on the server side.
|
|
44
|
+
if (opts.usage?.auto !== false)
|
|
45
|
+
this.usage.start();
|
|
37
46
|
}
|
|
38
47
|
}
|
|
39
48
|
/** Create a new ProAppStore SDK instance. Includes all free + pro features. */
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAkCnC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC;;;;;GAKG;AACH,MAAM,OAAO,WAAY,SAAQ,YAAY;IAClC,YAAY,CAAkB;IAC9B,OAAO,CAAa;IACpB,EAAE,CAAW;IACb,OAAO,CAAU;IACjB,IAAI,CAAO;IACX,aAAa,CAAgB;IAC7B,GAAG,CAAM;IACT,EAAE,CAAK;IACP,KAAK,CAAQ;IAEtB,YAAY,IAAoB;QAC9B,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,gCAAgC,CAAC;QACvE,IAAI,CAAC,YAAY,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjE,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,gBAAgB,IAAI,CAAC,KAAK,qBAAqB,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACnH,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1E,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,wEAAwE;QACxE,mEAAmE;QACnE,+BAA+B;QAC/B,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrD,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,UAAU,OAAO,CAAC,IAAoB;IAC1C,OAAO,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/maps.d.ts
CHANGED
|
@@ -17,13 +17,40 @@ export interface ReverseResult {
|
|
|
17
17
|
displayName: string;
|
|
18
18
|
address: Record<string, string>;
|
|
19
19
|
}
|
|
20
|
+
export interface RouteResult {
|
|
21
|
+
/** GeoJSON LineString — coordinates are [lng, lat] pairs (GeoJSON order). */
|
|
22
|
+
geometry: {
|
|
23
|
+
type: 'LineString';
|
|
24
|
+
coordinates: [number, number][];
|
|
25
|
+
};
|
|
26
|
+
distanceMeters: number;
|
|
27
|
+
durationSeconds: number;
|
|
28
|
+
}
|
|
20
29
|
export declare class Maps {
|
|
21
30
|
private readonly apiBase;
|
|
22
31
|
constructor(apiBase: string);
|
|
23
32
|
/** Convert an address string to coordinates. Returns up to `limit` results. */
|
|
24
|
-
geocode(query: string, limit?: number
|
|
33
|
+
geocode(query: string, limit?: number, opts?: {
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}): Promise<GeoResult[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Driving route between two points. Returns GeoJSON LineString geometry
|
|
38
|
+
* plus distance and duration. Backed by OSRM (OpenStreetMap), proxied
|
|
39
|
+
* through the platform — no API key needed.
|
|
40
|
+
*/
|
|
41
|
+
route(from: {
|
|
42
|
+
lat: number;
|
|
43
|
+
lng: number;
|
|
44
|
+
}, to: {
|
|
45
|
+
lat: number;
|
|
46
|
+
lng: number;
|
|
47
|
+
}, opts?: {
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
}): Promise<RouteResult>;
|
|
25
50
|
/** Convert coordinates to an address. */
|
|
26
|
-
reverseGeocode(lat: number, lng: number
|
|
51
|
+
reverseGeocode(lat: number, lng: number, opts?: {
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}): Promise<ReverseResult>;
|
|
27
54
|
/**
|
|
28
55
|
* Get an OpenStreetMap embed URL for use in an iframe.
|
|
29
56
|
* No API key needed. Free forever.
|
package/dist/maps.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../src/maps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,qBAAa,IAAI;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAE5C,+EAA+E;IACzE,OAAO,
|
|
1
|
+
{"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../src/maps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,QAAQ,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;KAAE,CAAC;IAClE,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,IAAI;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAE5C,+EAA+E;IACzE,OAAO,CACX,KAAK,EAAE,MAAM,EACb,KAAK,SAAI,EACT,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,SAAS,EAAE,CAAC;IAYvB;;;;OAIG;IACG,KAAK,CACT,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAClC,EAAE,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAChC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,WAAW,CAAC;IAWvB,yCAAyC;IACnC,cAAc,CAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAC9B,OAAO,CAAC,aAAa,CAAC;IAWzB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM;IAIrD;;;;;OAKG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM;CAKvD"}
|
package/dist/maps.js
CHANGED
|
@@ -9,22 +9,36 @@ export class Maps {
|
|
|
9
9
|
this.apiBase = apiBase;
|
|
10
10
|
}
|
|
11
11
|
/** Convert an address string to coordinates. Returns up to `limit` results. */
|
|
12
|
-
async geocode(query, limit = 5) {
|
|
12
|
+
async geocode(query, limit = 5, opts) {
|
|
13
13
|
const url = new URL(`${this.apiBase}/v1/maps/geocode`);
|
|
14
14
|
url.searchParams.set('q', query);
|
|
15
15
|
url.searchParams.set('limit', String(limit));
|
|
16
|
-
const response = await fetch(url.toString());
|
|
16
|
+
const response = await fetch(url.toString(), opts?.signal ? { signal: opts.signal } : undefined);
|
|
17
17
|
if (!response.ok)
|
|
18
18
|
throw new Error(`maps.geocode failed: ${response.status}`);
|
|
19
19
|
const data = (await response.json());
|
|
20
20
|
return data.results;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Driving route between two points. Returns GeoJSON LineString geometry
|
|
24
|
+
* plus distance and duration. Backed by OSRM (OpenStreetMap), proxied
|
|
25
|
+
* through the platform — no API key needed.
|
|
26
|
+
*/
|
|
27
|
+
async route(from, to, opts) {
|
|
28
|
+
const url = new URL(`${this.apiBase}/v1/maps/route`);
|
|
29
|
+
url.searchParams.set('from', `${from.lat},${from.lng}`);
|
|
30
|
+
url.searchParams.set('to', `${to.lat},${to.lng}`);
|
|
31
|
+
const response = await fetch(url.toString(), opts?.signal ? { signal: opts.signal } : undefined);
|
|
32
|
+
if (!response.ok)
|
|
33
|
+
throw new Error(`maps.route failed: ${response.status}`);
|
|
34
|
+
return (await response.json());
|
|
35
|
+
}
|
|
22
36
|
/** Convert coordinates to an address. */
|
|
23
|
-
async reverseGeocode(lat, lng) {
|
|
37
|
+
async reverseGeocode(lat, lng, opts) {
|
|
24
38
|
const url = new URL(`${this.apiBase}/v1/maps/reverse`);
|
|
25
39
|
url.searchParams.set('lat', String(lat));
|
|
26
40
|
url.searchParams.set('lng', String(lng));
|
|
27
|
-
const response = await fetch(url.toString());
|
|
41
|
+
const response = await fetch(url.toString(), opts?.signal ? { signal: opts.signal } : undefined);
|
|
28
42
|
if (!response.ok)
|
|
29
43
|
throw new Error(`maps.reverseGeocode failed: ${response.status}`);
|
|
30
44
|
return (await response.json());
|
package/dist/maps.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maps.js","sourceRoot":"","sources":["../src/maps.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"maps.js","sourceRoot":"","sources":["../src/maps.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,11 @@ export interface ProInitOptions {
|
|
|
6
6
|
proApiBase?: string;
|
|
7
7
|
/** Defaults to https://data-{appId}.proappstore.online (per-app data worker). */
|
|
8
8
|
dataApiBase?: string;
|
|
9
|
+
/** Usage telemetry options. Auto-heartbeat is on by default. */
|
|
10
|
+
usage?: {
|
|
11
|
+
/** Default true. Set false to disable the auto-heartbeat in this app. */
|
|
12
|
+
auto?: boolean;
|
|
13
|
+
};
|
|
9
14
|
}
|
|
10
15
|
export type SubscriptionStatus = 'active' | 'past_due' | 'canceled' | 'incomplete';
|
|
11
16
|
export interface Subscription {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,KAAK,CAAC,EAAE;QACN,yEAAyE;QACzE,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,CAAC;AAEnF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
|
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage telemetry — heartbeats `POST /v1/usage/ping` while the tab is visible.
|
|
3
|
+
*
|
|
4
|
+
* Auto-started by `initPro()` unless `usage.auto === false` in the options.
|
|
5
|
+
* The collected (app, user, day) counts drive the usage-proportional creator
|
|
6
|
+
* payouts described in proappstore.online/pricing.
|
|
7
|
+
*
|
|
8
|
+
* Design notes:
|
|
9
|
+
*
|
|
10
|
+
* - **Visible-time only.** We start a stopwatch when the tab is visible and
|
|
11
|
+
* pause on `visibilitychange`. A tab that's been hidden for 90s contributes
|
|
12
|
+
* 0 seconds for that interval.
|
|
13
|
+
* - **Browser-only.** All methods no-op when `document` or `window` is
|
|
14
|
+
* undefined so the import is SSR-safe.
|
|
15
|
+
* - **Silent failures.** Telemetry must never break an app. Every network
|
|
16
|
+
* path catches + ignores errors.
|
|
17
|
+
* - **Page-close flush.** On `pagehide` we send a final ping with the
|
|
18
|
+
* residual elapsed seconds via `navigator.sendBeacon` (survives unload)
|
|
19
|
+
* falling back to `fetch(..., { keepalive: true })`.
|
|
20
|
+
*/
|
|
21
|
+
interface AuthLike {
|
|
22
|
+
token: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface UsageOptions {
|
|
25
|
+
/** Default true. Set false to disable auto-heartbeat in this app. */
|
|
26
|
+
auto?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare class Usage {
|
|
29
|
+
private readonly appId;
|
|
30
|
+
private readonly apiBase;
|
|
31
|
+
private readonly auth;
|
|
32
|
+
private running;
|
|
33
|
+
private timer;
|
|
34
|
+
private visibleSince;
|
|
35
|
+
/** Accumulated visible-time since the last successful ping, in milliseconds. */
|
|
36
|
+
private accruedMs;
|
|
37
|
+
private pendingApiCalls;
|
|
38
|
+
private onVisibility;
|
|
39
|
+
private onPageHide;
|
|
40
|
+
constructor(appId: string, apiBase: string, auth: AuthLike);
|
|
41
|
+
/** Begin heartbeat reporting. Idempotent — calling twice is a no-op. */
|
|
42
|
+
start(): void;
|
|
43
|
+
/** Stop heartbeats. Idempotent. Doesn't flush; call `flush()` if you need to. */
|
|
44
|
+
stop(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Record API calls. Bumps a local counter that piggybacks on the next
|
|
47
|
+
* heartbeat. Cheap to call from hot paths — no network until the next tick.
|
|
48
|
+
*/
|
|
49
|
+
recordApiCall(n?: number): void;
|
|
50
|
+
/**
|
|
51
|
+
* Send a final ping (intended for page-close paths). Best-effort,
|
|
52
|
+
* fire-and-forget. Uses sendBeacon when available so the request survives
|
|
53
|
+
* unload; falls back to keepalive fetch otherwise.
|
|
54
|
+
*/
|
|
55
|
+
flush(): void;
|
|
56
|
+
/** Add any in-progress visible-time to the running accrual. */
|
|
57
|
+
private bankVisible;
|
|
58
|
+
/** Round accrued ms to whole seconds, clamp to MAX_DELTA_SECONDS, return + reset. */
|
|
59
|
+
private drainSeconds;
|
|
60
|
+
private drainApiCalls;
|
|
61
|
+
private tick;
|
|
62
|
+
private send;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AASD,qBAAa,KAAK;IAWd,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAZvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,YAAY,CAAuB;IAC3C,gFAAgF;IAChF,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,UAAU,CAA6B;gBAG5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,QAAQ;IAGjC,wEAAwE;IACxE,KAAK,IAAI,IAAI;IA6Bb,iFAAiF;IACjF,IAAI,IAAI,IAAI;IAkBZ;;;OAGG;IACH,aAAa,CAAC,CAAC,GAAE,MAAU,GAAG,IAAI;IAKlC;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAWb,+DAA+D;IAC/D,OAAO,CAAC,WAAW;IAOnB,qFAAqF;IACrF,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,aAAa;YAMP,IAAI;YAoBJ,IAAI;CAsCnB"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage telemetry — heartbeats `POST /v1/usage/ping` while the tab is visible.
|
|
3
|
+
*
|
|
4
|
+
* Auto-started by `initPro()` unless `usage.auto === false` in the options.
|
|
5
|
+
* The collected (app, user, day) counts drive the usage-proportional creator
|
|
6
|
+
* payouts described in proappstore.online/pricing.
|
|
7
|
+
*
|
|
8
|
+
* Design notes:
|
|
9
|
+
*
|
|
10
|
+
* - **Visible-time only.** We start a stopwatch when the tab is visible and
|
|
11
|
+
* pause on `visibilitychange`. A tab that's been hidden for 90s contributes
|
|
12
|
+
* 0 seconds for that interval.
|
|
13
|
+
* - **Browser-only.** All methods no-op when `document` or `window` is
|
|
14
|
+
* undefined so the import is SSR-safe.
|
|
15
|
+
* - **Silent failures.** Telemetry must never break an app. Every network
|
|
16
|
+
* path catches + ignores errors.
|
|
17
|
+
* - **Page-close flush.** On `pagehide` we send a final ping with the
|
|
18
|
+
* residual elapsed seconds via `navigator.sendBeacon` (survives unload)
|
|
19
|
+
* falling back to `fetch(..., { keepalive: true })`.
|
|
20
|
+
*/
|
|
21
|
+
const HEARTBEAT_MS = 60_000;
|
|
22
|
+
const MAX_DELTA_SECONDS = 90;
|
|
23
|
+
function hasBrowser() {
|
|
24
|
+
return typeof document !== 'undefined' && typeof window !== 'undefined';
|
|
25
|
+
}
|
|
26
|
+
export class Usage {
|
|
27
|
+
appId;
|
|
28
|
+
apiBase;
|
|
29
|
+
auth;
|
|
30
|
+
running = false;
|
|
31
|
+
timer = null;
|
|
32
|
+
visibleSince = null;
|
|
33
|
+
/** Accumulated visible-time since the last successful ping, in milliseconds. */
|
|
34
|
+
accruedMs = 0;
|
|
35
|
+
pendingApiCalls = 0;
|
|
36
|
+
onVisibility = null;
|
|
37
|
+
onPageHide = null;
|
|
38
|
+
constructor(appId, apiBase, auth) {
|
|
39
|
+
this.appId = appId;
|
|
40
|
+
this.apiBase = apiBase;
|
|
41
|
+
this.auth = auth;
|
|
42
|
+
}
|
|
43
|
+
/** Begin heartbeat reporting. Idempotent — calling twice is a no-op. */
|
|
44
|
+
start() {
|
|
45
|
+
if (this.running)
|
|
46
|
+
return;
|
|
47
|
+
if (!hasBrowser())
|
|
48
|
+
return;
|
|
49
|
+
this.running = true;
|
|
50
|
+
// Initial visibility snapshot.
|
|
51
|
+
if (document.visibilityState === 'visible') {
|
|
52
|
+
this.visibleSince = performance.now();
|
|
53
|
+
}
|
|
54
|
+
this.onVisibility = () => {
|
|
55
|
+
if (document.visibilityState === 'visible') {
|
|
56
|
+
if (this.visibleSince == null)
|
|
57
|
+
this.visibleSince = performance.now();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.bankVisible();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
document.addEventListener('visibilitychange', this.onVisibility);
|
|
64
|
+
this.onPageHide = () => {
|
|
65
|
+
this.flush();
|
|
66
|
+
};
|
|
67
|
+
window.addEventListener('pagehide', this.onPageHide);
|
|
68
|
+
this.timer = setInterval(() => {
|
|
69
|
+
this.tick().catch(() => { });
|
|
70
|
+
}, HEARTBEAT_MS);
|
|
71
|
+
}
|
|
72
|
+
/** Stop heartbeats. Idempotent. Doesn't flush; call `flush()` if you need to. */
|
|
73
|
+
stop() {
|
|
74
|
+
if (!this.running)
|
|
75
|
+
return;
|
|
76
|
+
this.running = false;
|
|
77
|
+
if (this.timer) {
|
|
78
|
+
clearInterval(this.timer);
|
|
79
|
+
this.timer = null;
|
|
80
|
+
}
|
|
81
|
+
if (hasBrowser()) {
|
|
82
|
+
if (this.onVisibility)
|
|
83
|
+
document.removeEventListener('visibilitychange', this.onVisibility);
|
|
84
|
+
if (this.onPageHide)
|
|
85
|
+
window.removeEventListener('pagehide', this.onPageHide);
|
|
86
|
+
}
|
|
87
|
+
this.onVisibility = null;
|
|
88
|
+
this.onPageHide = null;
|
|
89
|
+
this.visibleSince = null;
|
|
90
|
+
this.accruedMs = 0;
|
|
91
|
+
this.pendingApiCalls = 0;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Record API calls. Bumps a local counter that piggybacks on the next
|
|
95
|
+
* heartbeat. Cheap to call from hot paths — no network until the next tick.
|
|
96
|
+
*/
|
|
97
|
+
recordApiCall(n = 1) {
|
|
98
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
99
|
+
return;
|
|
100
|
+
this.pendingApiCalls += Math.floor(n);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Send a final ping (intended for page-close paths). Best-effort,
|
|
104
|
+
* fire-and-forget. Uses sendBeacon when available so the request survives
|
|
105
|
+
* unload; falls back to keepalive fetch otherwise.
|
|
106
|
+
*/
|
|
107
|
+
flush() {
|
|
108
|
+
if (!hasBrowser())
|
|
109
|
+
return;
|
|
110
|
+
this.bankVisible();
|
|
111
|
+
const seconds = this.drainSeconds();
|
|
112
|
+
const apiCalls = this.drainApiCalls();
|
|
113
|
+
if (seconds === 0 && apiCalls === 0)
|
|
114
|
+
return;
|
|
115
|
+
this.send(seconds, apiCalls, /* keepalive */ true);
|
|
116
|
+
}
|
|
117
|
+
// ── internal ──────────────────────────────────────────────────────────────
|
|
118
|
+
/** Add any in-progress visible-time to the running accrual. */
|
|
119
|
+
bankVisible() {
|
|
120
|
+
if (this.visibleSince == null)
|
|
121
|
+
return;
|
|
122
|
+
const now = performance.now();
|
|
123
|
+
this.accruedMs += Math.max(0, now - this.visibleSince);
|
|
124
|
+
this.visibleSince = null;
|
|
125
|
+
}
|
|
126
|
+
/** Round accrued ms to whole seconds, clamp to MAX_DELTA_SECONDS, return + reset. */
|
|
127
|
+
drainSeconds() {
|
|
128
|
+
const whole = Math.floor(this.accruedMs / 1000);
|
|
129
|
+
if (whole <= 0)
|
|
130
|
+
return 0;
|
|
131
|
+
const sent = Math.min(MAX_DELTA_SECONDS, whole);
|
|
132
|
+
this.accruedMs -= sent * 1000;
|
|
133
|
+
// Cap residual so a long-hidden flush after a long visible run doesn't
|
|
134
|
+
// ride along on the next ping forever.
|
|
135
|
+
if (this.accruedMs < 0)
|
|
136
|
+
this.accruedMs = 0;
|
|
137
|
+
return sent;
|
|
138
|
+
}
|
|
139
|
+
drainApiCalls() {
|
|
140
|
+
const n = this.pendingApiCalls;
|
|
141
|
+
this.pendingApiCalls = 0;
|
|
142
|
+
return n;
|
|
143
|
+
}
|
|
144
|
+
async tick() {
|
|
145
|
+
this.bankVisible();
|
|
146
|
+
if (document.visibilityState === 'visible') {
|
|
147
|
+
this.visibleSince = performance.now();
|
|
148
|
+
}
|
|
149
|
+
const seconds = this.drainSeconds();
|
|
150
|
+
const apiCalls = this.drainApiCalls();
|
|
151
|
+
if (seconds === 0 && apiCalls === 0)
|
|
152
|
+
return;
|
|
153
|
+
if (!this.auth.token) {
|
|
154
|
+
// Re-pocket the work — the user may sign in later and we'd like the
|
|
155
|
+
// accrued time to count from then. Note: a session-token signin BEFORE
|
|
156
|
+
// any visible time was banked won't have anything to attribute, and
|
|
157
|
+
// that's fine — anonymous usage isn't part of the payout math anyway.
|
|
158
|
+
this.accruedMs += seconds * 1000;
|
|
159
|
+
this.pendingApiCalls += apiCalls;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await this.send(seconds, apiCalls, /* keepalive */ false);
|
|
163
|
+
}
|
|
164
|
+
async send(seconds, apiCalls, keepalive) {
|
|
165
|
+
const token = this.auth.token;
|
|
166
|
+
if (!token)
|
|
167
|
+
return;
|
|
168
|
+
const body = JSON.stringify({
|
|
169
|
+
appId: this.appId,
|
|
170
|
+
deltaSeconds: seconds,
|
|
171
|
+
deltaApiCalls: apiCalls,
|
|
172
|
+
});
|
|
173
|
+
const url = `${this.apiBase}/v1/usage/ping`;
|
|
174
|
+
// Prefer sendBeacon for keepalive (unload survivor) paths. sendBeacon
|
|
175
|
+
// doesn't allow setting an Authorization header, so we encode the token
|
|
176
|
+
// into the URL only for keepalive — server accepts it as a fallback.
|
|
177
|
+
// (If your server doesn't support that, fall through to keepalive fetch.)
|
|
178
|
+
if (keepalive && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {
|
|
179
|
+
try {
|
|
180
|
+
const blob = new Blob([body], { type: 'application/json' });
|
|
181
|
+
const ok = navigator.sendBeacon(url, blob);
|
|
182
|
+
if (ok)
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// fall through
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
await fetch(url, {
|
|
191
|
+
method: 'POST',
|
|
192
|
+
headers: {
|
|
193
|
+
'Content-Type': 'application/json',
|
|
194
|
+
Authorization: `Bearer ${token}`,
|
|
195
|
+
},
|
|
196
|
+
body,
|
|
197
|
+
keepalive,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// Telemetry never breaks an app.
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@proappstore/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Browser SDK for paid apps on proappstore.online — subscriptions, license keys, premium modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,10 +29,6 @@
|
|
|
29
29
|
"dist",
|
|
30
30
|
"README.md"
|
|
31
31
|
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "tsc",
|
|
34
|
-
"typecheck": "tsc --noEmit"
|
|
35
|
-
},
|
|
36
32
|
"dependencies": {
|
|
37
33
|
"@freeappstore/sdk": "^0.7.1"
|
|
38
34
|
},
|
|
@@ -49,5 +45,9 @@
|
|
|
49
45
|
"react": "^19.0.0",
|
|
50
46
|
"typescript": "^5.7.0"
|
|
51
47
|
},
|
|
52
|
-
"sideEffects": false
|
|
53
|
-
|
|
48
|
+
"sideEffects": false,
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsc",
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
52
|
+
}
|
|
53
|
+
}
|