@optizio/merchant-identity 0.2.0 → 0.5.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.d.ts +297 -2
- package/dist/index.js +130 -2
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Consumed by:
|
|
5
5
|
* - the `merchant-identity` service Worker, which implements `IdentityClient`
|
|
6
|
-
* against the shared D1, and
|
|
6
|
+
* and `RevenueClient` against the shared D1, and
|
|
7
7
|
* - portfolio apps (DiscountKit, CodeBulk, Stackable), which call the service
|
|
8
|
-
* over an RPC service binding through the `identity()`
|
|
8
|
+
* over an RPC service binding through the `identity()` / `revenue()` seams
|
|
9
|
+
* below.
|
|
9
10
|
*
|
|
10
11
|
* This package holds only types + pure helpers, so it has no Cloudflare or
|
|
11
12
|
* runtime dependencies and is safe to import anywhere.
|
|
@@ -177,3 +178,297 @@ export declare const NOOP_IDENTITY: IdentityClient;
|
|
|
177
178
|
* any call sites.
|
|
178
179
|
*/
|
|
179
180
|
export declare function identity(binding: IdentityClient | null | undefined, disabled?: boolean | string): IdentityClient;
|
|
181
|
+
/**
|
|
182
|
+
* Every amount below is an integer in the currency's minor units (cents for
|
|
183
|
+
* USD), never a float, and is quoted in the service's report currency
|
|
184
|
+
* (`REVENUE_REPORT_CURRENCY`, USD by default). Amounts the Partner API reported
|
|
185
|
+
* in another currency are stored raw but excluded from these aggregates and
|
|
186
|
+
* counted in the sync status, so a non-zero `skippedCurrencyRows` means the
|
|
187
|
+
* numbers below are understating the portfolio.
|
|
188
|
+
*/
|
|
189
|
+
export declare const MINOR_UNIT_SCALE = 2;
|
|
190
|
+
/**
|
|
191
|
+
* Render minor units as a plain decimal string (`123456` -> `"1234.56"`).
|
|
192
|
+
* String math throughout: passing these through a float would round-trip
|
|
193
|
+
* large amounts inexactly, and the point of minor units is exactness.
|
|
194
|
+
*/
|
|
195
|
+
export declare function minorUnitsToDecimal(minor: number, scale?: number): string;
|
|
196
|
+
/** `app_gid` sentinel for the portfolio-wide rollup row. */
|
|
197
|
+
export declare const PORTFOLIO_APP_GID = "*";
|
|
198
|
+
export type ChargeStatus = 'active' | 'frozen' | 'canceled' | 'declined' | 'expired';
|
|
199
|
+
/** How a charge's amount is normalised into MRR. */
|
|
200
|
+
export type BillingInterval = 'MONTHLY' | 'ANNUAL';
|
|
201
|
+
export type MovementType = 'new' | 'expansion' | 'contraction' | 'churn' | 'reactivation' | 'frozen' | 'unfrozen';
|
|
202
|
+
export declare const MOVEMENT_TYPES: readonly MovementType[];
|
|
203
|
+
export type TrialOutcome = 'trialing' | 'converted' | 'canceled' | 'expired' | 'declined' | 'uninstalled';
|
|
204
|
+
/** The three Partner API feeds the sync engine polls. */
|
|
205
|
+
export type SyncFeed = 'transactions' | 'app_events' | 'account_events' | 'subscriptions';
|
|
206
|
+
export type SyncMode = 'backfill' | 'incremental';
|
|
207
|
+
export interface RevenueCharge {
|
|
208
|
+
chargeGid: string;
|
|
209
|
+
appGid: string;
|
|
210
|
+
/** Shopify client_id of the app, i.e. `merchant_apps.app_id`. */
|
|
211
|
+
apiKey: string | null;
|
|
212
|
+
appName: string | null;
|
|
213
|
+
shopKey: string;
|
|
214
|
+
shopDomain: string | null;
|
|
215
|
+
status: ChargeStatus;
|
|
216
|
+
amountMinor: number;
|
|
217
|
+
currencyCode: string | null;
|
|
218
|
+
interval: BillingInterval;
|
|
219
|
+
/** Monthly-normalised list price: what the plan costs before any discount. */
|
|
220
|
+
grossMrrMinor: number;
|
|
221
|
+
/** Monthly-normalised discount taken off `grossMrrMinor`. Never negative. */
|
|
222
|
+
discountMinor: number;
|
|
223
|
+
/** When the discount runs out; null for one that never does, or no discount. */
|
|
224
|
+
discountExpiresAt: string | null;
|
|
225
|
+
/**
|
|
226
|
+
* Monthly-normalised **net of discount**: what the shop is actually billed.
|
|
227
|
+
* `grossMrrMinor - discountMinor`, and 0 alongside a 0 gross while the charge is
|
|
228
|
+
* trialing. A frozen charge keeps its MRR — Shopify resumes billing at the same
|
|
229
|
+
* price when the store settles up.
|
|
230
|
+
*/
|
|
231
|
+
mrrMinor: number;
|
|
232
|
+
/** The shop has asked to cancel at the end of the current cycle. */
|
|
233
|
+
cancelAtEndOfCycle: boolean;
|
|
234
|
+
/**
|
|
235
|
+
* When this charge's terms were last read from the live subscription. Null means
|
|
236
|
+
* they are still only what the event history implied, so a discount on this
|
|
237
|
+
* charge would not be reflected yet.
|
|
238
|
+
*/
|
|
239
|
+
reconciledAt: string | null;
|
|
240
|
+
planName: string | null;
|
|
241
|
+
planHandle: string | null;
|
|
242
|
+
billingOn: string | null;
|
|
243
|
+
isTrial: boolean;
|
|
244
|
+
firstActivatedAt: string | null;
|
|
245
|
+
lastEventAt: string | null;
|
|
246
|
+
terminatedAt: string | null;
|
|
247
|
+
firstPaidAt: string | null;
|
|
248
|
+
lastPaidAt: string | null;
|
|
249
|
+
paidSaleCount: number;
|
|
250
|
+
}
|
|
251
|
+
/** Everything the support viewer needs about one store's billing. */
|
|
252
|
+
export interface MerchantRevenueSummary {
|
|
253
|
+
shopDomain: string;
|
|
254
|
+
shopKey: string;
|
|
255
|
+
/** Report currency the minor-unit amounts are quoted in. */
|
|
256
|
+
currencyCode: string;
|
|
257
|
+
/** Sum of `mrrMinor` (net of discounts) across active, non-trialing charges. */
|
|
258
|
+
mrrMinor: number;
|
|
259
|
+
/** The same sum before discounts, i.e. at list price. */
|
|
260
|
+
grossMrrMinor: number;
|
|
261
|
+
/** `grossMrrMinor - mrrMinor`: what discounts take off this store's bill. */
|
|
262
|
+
discountMinor: number;
|
|
263
|
+
charges: RevenueCharge[];
|
|
264
|
+
lifetimeGrossMinor: number;
|
|
265
|
+
lifetimeNetMinor: number;
|
|
266
|
+
firstPaidAt: string | null;
|
|
267
|
+
lastPaidAt: string | null;
|
|
268
|
+
activeTrials: number;
|
|
269
|
+
/** Null when the store has no derived rows yet (never billed, or unsynced). */
|
|
270
|
+
computedAt: string | null;
|
|
271
|
+
}
|
|
272
|
+
/** One UTC day of the derived series: stock metrics at end of day, flows for the day. */
|
|
273
|
+
export interface MrrSeriesPoint {
|
|
274
|
+
date: string;
|
|
275
|
+
/** Net of discounts: `grossMrrMinor - discountMinor`. */
|
|
276
|
+
mrrMinor: number;
|
|
277
|
+
/** List price of everything billing that day, before discounts. */
|
|
278
|
+
grossMrrMinor: number;
|
|
279
|
+
discountMinor: number;
|
|
280
|
+
/** The part of `discountMinor` that has an end date or cycles remaining. */
|
|
281
|
+
expiringDiscountMinor: number;
|
|
282
|
+
subscriptionMrrMinor: number;
|
|
283
|
+
usageMrrMinor: number;
|
|
284
|
+
activeSubscriptions: number;
|
|
285
|
+
activeTrials: number;
|
|
286
|
+
payingMerchants: number;
|
|
287
|
+
activeInstalls: number;
|
|
288
|
+
newMinor: number;
|
|
289
|
+
expansionMinor: number;
|
|
290
|
+
contractionMinor: number;
|
|
291
|
+
churnMinor: number;
|
|
292
|
+
reactivationMinor: number;
|
|
293
|
+
installs: number;
|
|
294
|
+
uninstalls: number;
|
|
295
|
+
trialsStarted: number;
|
|
296
|
+
trialsConverted: number;
|
|
297
|
+
trialsLost: number;
|
|
298
|
+
grossMinor: number;
|
|
299
|
+
netMinor: number;
|
|
300
|
+
}
|
|
301
|
+
export interface MovementBreakdown {
|
|
302
|
+
from: string;
|
|
303
|
+
to: string;
|
|
304
|
+
appGid: string;
|
|
305
|
+
openingMrrMinor: number;
|
|
306
|
+
closingMrrMinor: number;
|
|
307
|
+
newMinor: number;
|
|
308
|
+
expansionMinor: number;
|
|
309
|
+
contractionMinor: number;
|
|
310
|
+
churnMinor: number;
|
|
311
|
+
reactivationMinor: number;
|
|
312
|
+
/** Signed sum of the components; equals closing - opening subscription MRR. */
|
|
313
|
+
netMinor: number;
|
|
314
|
+
counts: Record<MovementType, number>;
|
|
315
|
+
}
|
|
316
|
+
export interface TrialFunnelCohort {
|
|
317
|
+
/** `YYYY-MM` of the trial start. */
|
|
318
|
+
cohort: string;
|
|
319
|
+
trialsStarted: number;
|
|
320
|
+
converted: number;
|
|
321
|
+
canceled: number;
|
|
322
|
+
expired: number;
|
|
323
|
+
declined: number;
|
|
324
|
+
uninstalled: number;
|
|
325
|
+
stillTrialing: number;
|
|
326
|
+
/** `converted / trialsStarted`, 0 when the cohort is empty. */
|
|
327
|
+
conversionRate: number;
|
|
328
|
+
convertedMrrMinor: number;
|
|
329
|
+
}
|
|
330
|
+
export interface SyncFeedStatus {
|
|
331
|
+
feed: SyncFeed;
|
|
332
|
+
scope: string;
|
|
333
|
+
mode: SyncMode;
|
|
334
|
+
windowStart: string | null;
|
|
335
|
+
windowEnd: string | null;
|
|
336
|
+
watermarkAt: string | null;
|
|
337
|
+
/**
|
|
338
|
+
* The feed has read everything there is. For the `subscriptions` recheck, which has
|
|
339
|
+
* no history to walk, it means nothing was stale when it last looked — so it dips
|
|
340
|
+
* back to false while a backlog drains, and the coordinator reads it to know there
|
|
341
|
+
* is a pass to come back for.
|
|
342
|
+
*/
|
|
343
|
+
backfillComplete: boolean;
|
|
344
|
+
pagesTotal: number;
|
|
345
|
+
rowsTotal: number;
|
|
346
|
+
lastRunAt: string | null;
|
|
347
|
+
lastSuccessAt: string | null;
|
|
348
|
+
lastError: string | null;
|
|
349
|
+
lastErrorAt: string | null;
|
|
350
|
+
consecutiveFailures: number;
|
|
351
|
+
}
|
|
352
|
+
export interface ReplayAppStatus {
|
|
353
|
+
appGid: string;
|
|
354
|
+
appName: string | null;
|
|
355
|
+
apiKey: string | null;
|
|
356
|
+
dirty: boolean;
|
|
357
|
+
lastReplayAt: string | null;
|
|
358
|
+
lastReplayMs: number | null;
|
|
359
|
+
eventsReplayed: number | null;
|
|
360
|
+
throughAt: string | null;
|
|
361
|
+
skippedCurrencyRows: number;
|
|
362
|
+
lastError: string | null;
|
|
363
|
+
}
|
|
364
|
+
/** How current the live-subscription reconciliation is. */
|
|
365
|
+
export interface SubscriptionReconciliationStatus {
|
|
366
|
+
/** (app, shop) pairs whose live subscription has been read at least once. */
|
|
367
|
+
checkedPairs: number;
|
|
368
|
+
/**
|
|
369
|
+
* Pairs the recheck owes a read: past the recheck interval, or never read at all.
|
|
370
|
+
*
|
|
371
|
+
* Counted over the pairs it will actually revisit — an active or frozen charge, or
|
|
372
|
+
* recent subscription activity with the app still installed — rather than over
|
|
373
|
+
* stored rows, so it is not bounded by `checkedPairs`. A pair that leaves that set
|
|
374
|
+
* keeps the timestamp of its last read and can never be refreshed, so counting it
|
|
375
|
+
* would hold this above 0 for good. Reaches 0 when the pass is caught up, which
|
|
376
|
+
* makes it the figure to alert on.
|
|
377
|
+
*/
|
|
378
|
+
stalePairs: number;
|
|
379
|
+
/** Pairs the API reports as having no live subscription. */
|
|
380
|
+
absentSubscriptions: number;
|
|
381
|
+
/**
|
|
382
|
+
* Pairs we could not ask about, because the feeds have never given us a shop GID
|
|
383
|
+
* and `activeSubscription` takes one. Held apart from `absentSubscriptions` so a
|
|
384
|
+
* shop we cannot identify is never read as a cancellation; the GID is recovered
|
|
385
|
+
* from any feed that carries it, so this should be 0 and is worth an alert when
|
|
386
|
+
* it is not.
|
|
387
|
+
*/
|
|
388
|
+
unresolvedPairs: number;
|
|
389
|
+
/**
|
|
390
|
+
* Live subscriptions whose charge we have never seen in the event history. Each
|
|
391
|
+
* one is revenue we cannot price, because the API exposes the discount but not
|
|
392
|
+
* the plan amount, so this should be 0 and is worth an alert when it is not.
|
|
393
|
+
*/
|
|
394
|
+
unpricedSubscriptions: number;
|
|
395
|
+
/**
|
|
396
|
+
* How current the recheck is: the oldest read among the pairs it still revisits, on
|
|
397
|
+
* the same reasoning as `stalePairs`. Null before the first read.
|
|
398
|
+
*/
|
|
399
|
+
oldestCheckedAt: string | null;
|
|
400
|
+
}
|
|
401
|
+
export interface RevenueSyncStatus {
|
|
402
|
+
currencyCode: string;
|
|
403
|
+
/** True when the service has no Partner token or is explicitly disabled. */
|
|
404
|
+
disabled: boolean;
|
|
405
|
+
feeds: SyncFeedStatus[];
|
|
406
|
+
apps: ReplayAppStatus[];
|
|
407
|
+
dirtyApps: number;
|
|
408
|
+
reconciliation: SubscriptionReconciliationStatus;
|
|
409
|
+
/**
|
|
410
|
+
* How current the raw layer is: the *oldest* watermark across the ingesting feeds,
|
|
411
|
+
* since the numbers are only complete up to whichever feed is furthest behind. The
|
|
412
|
+
* subscription recheck is not an ingesting feed and does not count towards it — see
|
|
413
|
+
* `reconciliation.oldestCheckedAt` for that.
|
|
414
|
+
*/
|
|
415
|
+
watermarkAt: string | null;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Scope for the aggregate reads. `appGid` and `apiKey` both select a single app
|
|
419
|
+
* (`apiKey` being the Shopify client_id an app already knows about itself);
|
|
420
|
+
* passing neither reads the portfolio rollup.
|
|
421
|
+
*/
|
|
422
|
+
export interface RevenueScope {
|
|
423
|
+
appGid?: string;
|
|
424
|
+
apiKey?: string;
|
|
425
|
+
}
|
|
426
|
+
export interface MrrSeriesQuery extends RevenueScope {
|
|
427
|
+
/** Inclusive `YYYY-MM-DD`. Defaults to 90 days before `to`. */
|
|
428
|
+
from?: string;
|
|
429
|
+
/** Inclusive `YYYY-MM-DD`. Defaults to the latest computed day. */
|
|
430
|
+
to?: string;
|
|
431
|
+
/** Hard cap on returned points (most recent kept). Defaults to 400. */
|
|
432
|
+
limit?: number;
|
|
433
|
+
}
|
|
434
|
+
export interface MovementQuery extends RevenueScope {
|
|
435
|
+
from: string;
|
|
436
|
+
to: string;
|
|
437
|
+
}
|
|
438
|
+
export interface TrialFunnelQuery extends RevenueScope {
|
|
439
|
+
/** Inclusive `YYYY-MM` cohort bounds. Default: the last 12 months. */
|
|
440
|
+
fromMonth?: string;
|
|
441
|
+
toMonth?: string;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* The read surface over derived Partner revenue, exposed by the same Worker as
|
|
445
|
+
* `IdentityClient` (entrypoint `MerchantRevenue`) because both own the same D1.
|
|
446
|
+
* Reads never touch the Partner API: they read tables the sync + replay have
|
|
447
|
+
* already built, so they are cheap and safe to call per request.
|
|
448
|
+
*
|
|
449
|
+
* `requestSync` / `requestReplay` are internal operator hooks, not app-facing;
|
|
450
|
+
* they only nudge the sync coordinator and return immediately.
|
|
451
|
+
*/
|
|
452
|
+
export interface RevenueClient {
|
|
453
|
+
getMerchantRevenue(shopDomain: string): Promise<MerchantRevenueSummary>;
|
|
454
|
+
getMrrSeries(query?: MrrSeriesQuery): Promise<MrrSeriesPoint[]>;
|
|
455
|
+
getMovementBreakdown(query: MovementQuery): Promise<MovementBreakdown>;
|
|
456
|
+
getTrialFunnel(query?: TrialFunnelQuery): Promise<TrialFunnelCohort[]>;
|
|
457
|
+
getSyncStatus(): Promise<RevenueSyncStatus>;
|
|
458
|
+
requestSync(reason?: string): Promise<void>;
|
|
459
|
+
requestReplay(appGid?: string): Promise<void>;
|
|
460
|
+
}
|
|
461
|
+
/** Empty summary for a store with no billing history (or no service). */
|
|
462
|
+
export declare function emptyMerchantRevenue(shopDomain: string, currencyCode?: string): MerchantRevenueSummary;
|
|
463
|
+
/**
|
|
464
|
+
* No-op client used when the service is unavailable (local dev) or explicitly
|
|
465
|
+
* disabled via `REVENUE_DISABLED`. Reads return empty rather than throwing so a
|
|
466
|
+
* dashboard renders zeroes instead of failing.
|
|
467
|
+
*/
|
|
468
|
+
export declare const NOOP_REVENUE: RevenueClient;
|
|
469
|
+
/**
|
|
470
|
+
* Single seam for the revenue binding, mirroring `identity()`: returns the real
|
|
471
|
+
* binding when present and enabled, otherwise `NOOP_REVENUE`, so an app renders
|
|
472
|
+
* without the service bound.
|
|
473
|
+
*/
|
|
474
|
+
export declare function revenue(binding: RevenueClient | null | undefined, disabled?: boolean | string): RevenueClient;
|
package/dist/index.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Consumed by:
|
|
5
5
|
* - the `merchant-identity` service Worker, which implements `IdentityClient`
|
|
6
|
-
* against the shared D1, and
|
|
6
|
+
* and `RevenueClient` against the shared D1, and
|
|
7
7
|
* - portfolio apps (DiscountKit, CodeBulk, Stackable), which call the service
|
|
8
|
-
* over an RPC service binding through the `identity()`
|
|
8
|
+
* over an RPC service binding through the `identity()` / `revenue()` seams
|
|
9
|
+
* below.
|
|
9
10
|
*
|
|
10
11
|
* This package holds only types + pure helpers, so it has no Cloudflare or
|
|
11
12
|
* runtime dependencies and is safe to import anywhere.
|
|
@@ -78,3 +79,130 @@ export function identity(binding, disabled) {
|
|
|
78
79
|
}
|
|
79
80
|
return binding;
|
|
80
81
|
}
|
|
82
|
+
/* -------------------------------------------------------------------------- */
|
|
83
|
+
/* Revenue: money representation */
|
|
84
|
+
/* -------------------------------------------------------------------------- */
|
|
85
|
+
/**
|
|
86
|
+
* Every amount below is an integer in the currency's minor units (cents for
|
|
87
|
+
* USD), never a float, and is quoted in the service's report currency
|
|
88
|
+
* (`REVENUE_REPORT_CURRENCY`, USD by default). Amounts the Partner API reported
|
|
89
|
+
* in another currency are stored raw but excluded from these aggregates and
|
|
90
|
+
* counted in the sync status, so a non-zero `skippedCurrencyRows` means the
|
|
91
|
+
* numbers below are understating the portfolio.
|
|
92
|
+
*/
|
|
93
|
+
export const MINOR_UNIT_SCALE = 2;
|
|
94
|
+
/**
|
|
95
|
+
* Render minor units as a plain decimal string (`123456` -> `"1234.56"`).
|
|
96
|
+
* String math throughout: passing these through a float would round-trip
|
|
97
|
+
* large amounts inexactly, and the point of minor units is exactness.
|
|
98
|
+
*/
|
|
99
|
+
export function minorUnitsToDecimal(minor, scale = MINOR_UNIT_SCALE) {
|
|
100
|
+
const negative = minor < 0;
|
|
101
|
+
const digits = Math.abs(Math.trunc(minor)).toString().padStart(scale + 1, '0');
|
|
102
|
+
const whole = digits.slice(0, digits.length - scale);
|
|
103
|
+
const fraction = scale > 0 ? `.${digits.slice(digits.length - scale)}` : '';
|
|
104
|
+
return `${negative ? '-' : ''}${whole}${fraction}`;
|
|
105
|
+
}
|
|
106
|
+
/* -------------------------------------------------------------------------- */
|
|
107
|
+
/* Revenue: enums + sentinels */
|
|
108
|
+
/* -------------------------------------------------------------------------- */
|
|
109
|
+
/** `app_gid` sentinel for the portfolio-wide rollup row. */
|
|
110
|
+
export const PORTFOLIO_APP_GID = '*';
|
|
111
|
+
export const MOVEMENT_TYPES = [
|
|
112
|
+
'new',
|
|
113
|
+
'expansion',
|
|
114
|
+
'contraction',
|
|
115
|
+
'churn',
|
|
116
|
+
'reactivation',
|
|
117
|
+
'frozen',
|
|
118
|
+
'unfrozen',
|
|
119
|
+
];
|
|
120
|
+
/** Empty summary for a store with no billing history (or no service). */
|
|
121
|
+
export function emptyMerchantRevenue(shopDomain, currencyCode = 'USD') {
|
|
122
|
+
return {
|
|
123
|
+
shopDomain,
|
|
124
|
+
shopKey: shopDomain,
|
|
125
|
+
currencyCode,
|
|
126
|
+
mrrMinor: 0,
|
|
127
|
+
grossMrrMinor: 0,
|
|
128
|
+
discountMinor: 0,
|
|
129
|
+
charges: [],
|
|
130
|
+
lifetimeGrossMinor: 0,
|
|
131
|
+
lifetimeNetMinor: 0,
|
|
132
|
+
firstPaidAt: null,
|
|
133
|
+
lastPaidAt: null,
|
|
134
|
+
activeTrials: 0,
|
|
135
|
+
computedAt: null,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* No-op client used when the service is unavailable (local dev) or explicitly
|
|
140
|
+
* disabled via `REVENUE_DISABLED`. Reads return empty rather than throwing so a
|
|
141
|
+
* dashboard renders zeroes instead of failing.
|
|
142
|
+
*/
|
|
143
|
+
export const NOOP_REVENUE = {
|
|
144
|
+
async getMerchantRevenue(shopDomain) {
|
|
145
|
+
return emptyMerchantRevenue(shopDomain);
|
|
146
|
+
},
|
|
147
|
+
async getMrrSeries() {
|
|
148
|
+
return [];
|
|
149
|
+
},
|
|
150
|
+
async getMovementBreakdown(query) {
|
|
151
|
+
return {
|
|
152
|
+
from: query.from,
|
|
153
|
+
to: query.to,
|
|
154
|
+
appGid: query.appGid ?? PORTFOLIO_APP_GID,
|
|
155
|
+
openingMrrMinor: 0,
|
|
156
|
+
closingMrrMinor: 0,
|
|
157
|
+
newMinor: 0,
|
|
158
|
+
expansionMinor: 0,
|
|
159
|
+
contractionMinor: 0,
|
|
160
|
+
churnMinor: 0,
|
|
161
|
+
reactivationMinor: 0,
|
|
162
|
+
netMinor: 0,
|
|
163
|
+
counts: {
|
|
164
|
+
new: 0,
|
|
165
|
+
expansion: 0,
|
|
166
|
+
contraction: 0,
|
|
167
|
+
churn: 0,
|
|
168
|
+
reactivation: 0,
|
|
169
|
+
frozen: 0,
|
|
170
|
+
unfrozen: 0,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
async getTrialFunnel() {
|
|
175
|
+
return [];
|
|
176
|
+
},
|
|
177
|
+
async getSyncStatus() {
|
|
178
|
+
return {
|
|
179
|
+
currencyCode: 'USD',
|
|
180
|
+
disabled: true,
|
|
181
|
+
feeds: [],
|
|
182
|
+
apps: [],
|
|
183
|
+
dirtyApps: 0,
|
|
184
|
+
reconciliation: {
|
|
185
|
+
checkedPairs: 0,
|
|
186
|
+
stalePairs: 0,
|
|
187
|
+
absentSubscriptions: 0,
|
|
188
|
+
unresolvedPairs: 0,
|
|
189
|
+
unpricedSubscriptions: 0,
|
|
190
|
+
oldestCheckedAt: null,
|
|
191
|
+
},
|
|
192
|
+
watermarkAt: null,
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
async requestSync() { },
|
|
196
|
+
async requestReplay() { },
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Single seam for the revenue binding, mirroring `identity()`: returns the real
|
|
200
|
+
* binding when present and enabled, otherwise `NOOP_REVENUE`, so an app renders
|
|
201
|
+
* without the service bound.
|
|
202
|
+
*/
|
|
203
|
+
export function revenue(binding, disabled) {
|
|
204
|
+
if (!binding || disabled === true || disabled === 'true') {
|
|
205
|
+
return NOOP_REVENUE;
|
|
206
|
+
}
|
|
207
|
+
return binding;
|
|
208
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optizio/merchant-identity",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Shared merchant/user identity types
|
|
3
|
+
"version": "0.5.1",
|
|
4
|
+
"description": "Shared merchant/user identity + revenue types and RPC client contracts for the merchant-hub portfolio.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/optizio/merchant-hub.git",
|