@progus/connector 0.6.5 → 0.6.8
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/{crossSell-Bs_6xA6f.d.cts → crossSell-BZZ9FX7S.d.cts} +4 -1
- package/dist/{crossSell-Bs_6xA6f.d.ts → crossSell-BZZ9FX7S.d.ts} +4 -1
- package/dist/crossSell.d.cts +1 -1
- package/dist/crossSell.d.ts +1 -1
- package/dist/index.cjs +157 -136
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +157 -136
- package/package.json +1 -1
|
@@ -44,6 +44,9 @@ type AssignPartnerIdInput = {
|
|
|
44
44
|
shopDomain: string;
|
|
45
45
|
partnerId: string;
|
|
46
46
|
};
|
|
47
|
+
type AssignPartnerIdWithSubscriptionInput = AssignPartnerIdInput & {
|
|
48
|
+
admin: ShopifyAdminGraphQLClient;
|
|
49
|
+
};
|
|
47
50
|
type SubscriptionEventData = {
|
|
48
51
|
subscriptionStatus?: string;
|
|
49
52
|
subscriptionName?: string;
|
|
@@ -82,4 +85,4 @@ declare function getCrossSellOffers(options?: CrossSellOptions): AppsCatalogEntr
|
|
|
82
85
|
declare function fetchAppsCatalog(options?: CrossSellFetchOptions): Promise<AppsCatalogEntry[]>;
|
|
83
86
|
declare function getCrossSellOffersFromApi(options?: CrossSellFetchOptions): Promise<AppsCatalogEntry[]>;
|
|
84
87
|
|
|
85
|
-
export { type AssignPartnerIdInput as A, type ConnectorConfig as C, type Logger as L, type SubscriptionEventData as S, type TrackEventParams as T, type TrackResult as a, type
|
|
88
|
+
export { type AssignPartnerIdInput as A, type ConnectorConfig as C, type Logger as L, type SubscriptionEventData as S, type TrackEventParams as T, type TrackResult as a, type AssignPartnerIdWithSubscriptionInput as b, type CheckPartnerIdResult as c, type ShopifyAdminGraphQLClient as d, getCrossSellOffersFromApi as e, fetchAppsCatalog as f, getCrossSellOffers as g, type AppsCatalogEntry as h, type CrossSellFetchOptions as i, type CrossSellOptions as j, type TrackEventName as k };
|
|
@@ -44,6 +44,9 @@ type AssignPartnerIdInput = {
|
|
|
44
44
|
shopDomain: string;
|
|
45
45
|
partnerId: string;
|
|
46
46
|
};
|
|
47
|
+
type AssignPartnerIdWithSubscriptionInput = AssignPartnerIdInput & {
|
|
48
|
+
admin: ShopifyAdminGraphQLClient;
|
|
49
|
+
};
|
|
47
50
|
type SubscriptionEventData = {
|
|
48
51
|
subscriptionStatus?: string;
|
|
49
52
|
subscriptionName?: string;
|
|
@@ -82,4 +85,4 @@ declare function getCrossSellOffers(options?: CrossSellOptions): AppsCatalogEntr
|
|
|
82
85
|
declare function fetchAppsCatalog(options?: CrossSellFetchOptions): Promise<AppsCatalogEntry[]>;
|
|
83
86
|
declare function getCrossSellOffersFromApi(options?: CrossSellFetchOptions): Promise<AppsCatalogEntry[]>;
|
|
84
87
|
|
|
85
|
-
export { type AssignPartnerIdInput as A, type ConnectorConfig as C, type Logger as L, type SubscriptionEventData as S, type TrackEventParams as T, type TrackResult as a, type
|
|
88
|
+
export { type AssignPartnerIdInput as A, type ConnectorConfig as C, type Logger as L, type SubscriptionEventData as S, type TrackEventParams as T, type TrackResult as a, type AssignPartnerIdWithSubscriptionInput as b, type CheckPartnerIdResult as c, type ShopifyAdminGraphQLClient as d, getCrossSellOffersFromApi as e, fetchAppsCatalog as f, getCrossSellOffers as g, type AppsCatalogEntry as h, type CrossSellFetchOptions as i, type CrossSellOptions as j, type TrackEventName as k };
|
package/dist/crossSell.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { h as AppsCatalogEntry, i as CrossSellFetchOptions, j as CrossSellOptions, f as fetchAppsCatalog, g as getCrossSellOffers, e as getCrossSellOffersFromApi } from './crossSell-BZZ9FX7S.cjs';
|
package/dist/crossSell.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { h as AppsCatalogEntry, i as CrossSellFetchOptions, j as CrossSellOptions, f as fetchAppsCatalog, g as getCrossSellOffers, e as getCrossSellOffersFromApi } from './crossSell-BZZ9FX7S.js';
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,142 @@ __export(index_exports, {
|
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(index_exports);
|
|
32
32
|
|
|
33
|
+
// src/subscription.ts
|
|
34
|
+
var ACTIVE_SUBSCRIPTIONS_QUERY = `
|
|
35
|
+
query {
|
|
36
|
+
currentAppInstallation {
|
|
37
|
+
activeSubscriptions {
|
|
38
|
+
id
|
|
39
|
+
name
|
|
40
|
+
status
|
|
41
|
+
lineItems {
|
|
42
|
+
plan {
|
|
43
|
+
pricingDetails {
|
|
44
|
+
__typename
|
|
45
|
+
... on AppRecurringPricing {
|
|
46
|
+
interval
|
|
47
|
+
price {
|
|
48
|
+
amount
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
... on AppUsagePricing {
|
|
52
|
+
cappedAmount {
|
|
53
|
+
amount
|
|
54
|
+
}
|
|
55
|
+
terms
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
var SUBSCRIPTION_DETAILS_QUERY = `
|
|
65
|
+
query AppSubscriptionDetails($id: ID!) {
|
|
66
|
+
node(id: $id) {
|
|
67
|
+
... on AppSubscription {
|
|
68
|
+
id
|
|
69
|
+
name
|
|
70
|
+
status
|
|
71
|
+
lineItems {
|
|
72
|
+
plan {
|
|
73
|
+
pricingDetails {
|
|
74
|
+
__typename
|
|
75
|
+
... on AppRecurringPricing {
|
|
76
|
+
interval
|
|
77
|
+
price {
|
|
78
|
+
amount
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
... on AppUsagePricing {
|
|
82
|
+
cappedAmount {
|
|
83
|
+
amount
|
|
84
|
+
}
|
|
85
|
+
terms
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
`;
|
|
94
|
+
function normalizeInterval(intervalRaw, nameHint) {
|
|
95
|
+
const interval = intervalRaw ? String(intervalRaw).toUpperCase() : "";
|
|
96
|
+
if (interval === "ANNUAL" || interval === "EVERY_30_DAYS") return interval;
|
|
97
|
+
if (interval === "MONTHLY" || interval === "EVERY_30DAYS") return "EVERY_30_DAYS";
|
|
98
|
+
const name = (nameHint ?? "").toLowerCase();
|
|
99
|
+
if (name.includes("annual") || name.includes("year")) return "ANNUAL";
|
|
100
|
+
if (name) return "EVERY_30_DAYS";
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
function parseSubscriptionId(rawId) {
|
|
104
|
+
if (!rawId) return null;
|
|
105
|
+
return rawId.match(/\d+$/)?.[0] ?? rawId.split("/").pop() ?? rawId;
|
|
106
|
+
}
|
|
107
|
+
function parsePrice(rawPrice) {
|
|
108
|
+
if (typeof rawPrice === "number") return rawPrice;
|
|
109
|
+
if (typeof rawPrice === "string") {
|
|
110
|
+
const parsed = Number(rawPrice);
|
|
111
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function extractPricing(subscription) {
|
|
116
|
+
const pricingDetails = subscription?.lineItems?.[0]?.plan?.pricingDetails;
|
|
117
|
+
const rawPrice = pricingDetails?.price?.amount ?? pricingDetails?.cappedAmount?.amount;
|
|
118
|
+
const subscriptionPrice = parsePrice(rawPrice);
|
|
119
|
+
const subscriptionPeriod = normalizeInterval(pricingDetails?.interval, subscription?.name);
|
|
120
|
+
return { subscriptionPrice, subscriptionPeriod };
|
|
121
|
+
}
|
|
122
|
+
async function fetchActiveSubscriptionEventData(admin, logger = console) {
|
|
123
|
+
const response = await admin.graphql(ACTIVE_SUBSCRIPTIONS_QUERY);
|
|
124
|
+
const result = await response.json();
|
|
125
|
+
if (result.errors?.length) {
|
|
126
|
+
logger.error?.("Partner subscription query errors", { errors: result.errors });
|
|
127
|
+
}
|
|
128
|
+
const subscriptions = result.data?.currentAppInstallation?.activeSubscriptions ?? [];
|
|
129
|
+
const active = subscriptions.find((sub) => String(sub.status ?? "").toUpperCase() === "ACTIVE") ?? subscriptions[0];
|
|
130
|
+
const subscriptionId = parseSubscriptionId(active?.id);
|
|
131
|
+
if (!subscriptionId) return null;
|
|
132
|
+
let { subscriptionPrice, subscriptionPeriod } = extractPricing(active);
|
|
133
|
+
if (!subscriptionPeriod || subscriptionPrice === null) {
|
|
134
|
+
try {
|
|
135
|
+
const detailsResponse = await admin.graphql(SUBSCRIPTION_DETAILS_QUERY, {
|
|
136
|
+
variables: { id: active?.id }
|
|
137
|
+
});
|
|
138
|
+
const detailsJson = await detailsResponse.json();
|
|
139
|
+
if (detailsJson.errors?.length) {
|
|
140
|
+
logger.error?.("Partner subscription details query errors", { errors: detailsJson.errors });
|
|
141
|
+
}
|
|
142
|
+
const details = detailsJson.data?.node;
|
|
143
|
+
({ subscriptionPrice, subscriptionPeriod } = extractPricing(details));
|
|
144
|
+
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
145
|
+
return {
|
|
146
|
+
subscriptionStatus: details?.status ?? active?.status ?? "ACTIVE",
|
|
147
|
+
subscriptionName: details?.name ?? active?.name,
|
|
148
|
+
subscriptionId,
|
|
149
|
+
subscriptionPrice,
|
|
150
|
+
subscriptionPeriod
|
|
151
|
+
};
|
|
152
|
+
} catch (error) {
|
|
153
|
+
logger.error?.("Partner subscription details query failed", {
|
|
154
|
+
error: error instanceof Error ? error.message : String(error)
|
|
155
|
+
});
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
160
|
+
return {
|
|
161
|
+
subscriptionStatus: active?.status ?? "ACTIVE",
|
|
162
|
+
subscriptionName: active?.name,
|
|
163
|
+
subscriptionId,
|
|
164
|
+
subscriptionPrice,
|
|
165
|
+
subscriptionPeriod
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
33
169
|
// src/signing.ts
|
|
34
170
|
var import_crypto = require("crypto");
|
|
35
171
|
function signPayload(body, secret) {
|
|
@@ -76,6 +212,7 @@ function createProgusConnector(config) {
|
|
|
76
212
|
trackSubscriptionUpdated: fail,
|
|
77
213
|
trackSubscriptionCancelled: fail,
|
|
78
214
|
assignPartnerId: fail,
|
|
215
|
+
assignPartnerIdWithSubscription: fail,
|
|
79
216
|
checkPartnerId: async () => ({ success: false, message, status: 500 })
|
|
80
217
|
};
|
|
81
218
|
}
|
|
@@ -177,6 +314,25 @@ function createProgusConnector(config) {
|
|
|
177
314
|
const result = await trackInstall({ shopDomain: payload.shopDomain, partnerId: normalized });
|
|
178
315
|
return { ...result, partnerId: normalized };
|
|
179
316
|
}
|
|
317
|
+
async function assignPartnerIdWithSubscription(payload) {
|
|
318
|
+
const { admin, ...rest } = payload;
|
|
319
|
+
const result = await assignPartnerId(rest);
|
|
320
|
+
if (!result.success) return result;
|
|
321
|
+
try {
|
|
322
|
+
const subscriptionPayload = await fetchActiveSubscriptionEventData(admin, logger);
|
|
323
|
+
if (subscriptionPayload) {
|
|
324
|
+
await trackSubscription({
|
|
325
|
+
shopDomain: rest.shopDomain,
|
|
326
|
+
data: subscriptionPayload
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
logger?.error?.("Partner subscription sync failed", {
|
|
331
|
+
error: error instanceof Error ? error.message : String(error)
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
return result;
|
|
335
|
+
}
|
|
180
336
|
async function checkPartnerId(payload) {
|
|
181
337
|
if (!payload.shopDomain) {
|
|
182
338
|
return { success: false, message: "Missing shop domain" };
|
|
@@ -247,6 +403,7 @@ function createProgusConnector(config) {
|
|
|
247
403
|
trackSubscriptionUpdated: trackSubscription,
|
|
248
404
|
trackSubscriptionCancelled: trackSubscription,
|
|
249
405
|
assignPartnerId,
|
|
406
|
+
assignPartnerIdWithSubscription,
|
|
250
407
|
checkPartnerId
|
|
251
408
|
};
|
|
252
409
|
}
|
|
@@ -349,142 +506,6 @@ async function getCrossSellOffersFromApi(options = {}) {
|
|
|
349
506
|
const appsCatalog = options.appsCatalog ?? await fetchAppsCatalog(options);
|
|
350
507
|
return getCrossSellOffers({ ...options, appsCatalog });
|
|
351
508
|
}
|
|
352
|
-
|
|
353
|
-
// src/subscription.ts
|
|
354
|
-
var ACTIVE_SUBSCRIPTIONS_QUERY = `
|
|
355
|
-
query {
|
|
356
|
-
currentAppInstallation {
|
|
357
|
-
activeSubscriptions {
|
|
358
|
-
id
|
|
359
|
-
name
|
|
360
|
-
status
|
|
361
|
-
lineItems {
|
|
362
|
-
plan {
|
|
363
|
-
pricingDetails {
|
|
364
|
-
__typename
|
|
365
|
-
... on AppRecurringPricing {
|
|
366
|
-
interval
|
|
367
|
-
price {
|
|
368
|
-
amount
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
... on AppUsagePricing {
|
|
372
|
-
cappedAmount {
|
|
373
|
-
amount
|
|
374
|
-
}
|
|
375
|
-
terms
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
`;
|
|
384
|
-
var SUBSCRIPTION_DETAILS_QUERY = `
|
|
385
|
-
query AppSubscriptionDetails($id: ID!) {
|
|
386
|
-
node(id: $id) {
|
|
387
|
-
... on AppSubscription {
|
|
388
|
-
id
|
|
389
|
-
name
|
|
390
|
-
status
|
|
391
|
-
lineItems {
|
|
392
|
-
plan {
|
|
393
|
-
pricingDetails {
|
|
394
|
-
__typename
|
|
395
|
-
... on AppRecurringPricing {
|
|
396
|
-
interval
|
|
397
|
-
price {
|
|
398
|
-
amount
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
... on AppUsagePricing {
|
|
402
|
-
cappedAmount {
|
|
403
|
-
amount
|
|
404
|
-
}
|
|
405
|
-
terms
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
`;
|
|
414
|
-
function normalizeInterval(intervalRaw, nameHint) {
|
|
415
|
-
const interval = intervalRaw ? String(intervalRaw).toUpperCase() : "";
|
|
416
|
-
if (interval === "ANNUAL" || interval === "EVERY_30_DAYS") return interval;
|
|
417
|
-
if (interval === "MONTHLY" || interval === "EVERY_30DAYS") return "EVERY_30_DAYS";
|
|
418
|
-
const name = (nameHint ?? "").toLowerCase();
|
|
419
|
-
if (name.includes("annual") || name.includes("year")) return "ANNUAL";
|
|
420
|
-
if (name) return "EVERY_30_DAYS";
|
|
421
|
-
return "";
|
|
422
|
-
}
|
|
423
|
-
function parseSubscriptionId(rawId) {
|
|
424
|
-
if (!rawId) return null;
|
|
425
|
-
return rawId.match(/\d+$/)?.[0] ?? rawId.split("/").pop() ?? rawId;
|
|
426
|
-
}
|
|
427
|
-
function parsePrice(rawPrice) {
|
|
428
|
-
if (typeof rawPrice === "number") return rawPrice;
|
|
429
|
-
if (typeof rawPrice === "string") {
|
|
430
|
-
const parsed = Number(rawPrice);
|
|
431
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
432
|
-
}
|
|
433
|
-
return null;
|
|
434
|
-
}
|
|
435
|
-
function extractPricing(subscription) {
|
|
436
|
-
const pricingDetails = subscription?.lineItems?.[0]?.plan?.pricingDetails;
|
|
437
|
-
const rawPrice = pricingDetails?.price?.amount ?? pricingDetails?.cappedAmount?.amount;
|
|
438
|
-
const subscriptionPrice = parsePrice(rawPrice);
|
|
439
|
-
const subscriptionPeriod = normalizeInterval(pricingDetails?.interval, subscription?.name);
|
|
440
|
-
return { subscriptionPrice, subscriptionPeriod };
|
|
441
|
-
}
|
|
442
|
-
async function fetchActiveSubscriptionEventData(admin, logger = console) {
|
|
443
|
-
const response = await admin.graphql(ACTIVE_SUBSCRIPTIONS_QUERY);
|
|
444
|
-
const result = await response.json();
|
|
445
|
-
if (result.errors?.length) {
|
|
446
|
-
logger.error?.("Partner subscription query errors", { errors: result.errors });
|
|
447
|
-
}
|
|
448
|
-
const subscriptions = result.data?.currentAppInstallation?.activeSubscriptions ?? [];
|
|
449
|
-
const active = subscriptions.find((sub) => String(sub.status ?? "").toUpperCase() === "ACTIVE") ?? subscriptions[0];
|
|
450
|
-
const subscriptionId = parseSubscriptionId(active?.id);
|
|
451
|
-
if (!subscriptionId) return null;
|
|
452
|
-
let { subscriptionPrice, subscriptionPeriod } = extractPricing(active);
|
|
453
|
-
if (!subscriptionPeriod || subscriptionPrice === null) {
|
|
454
|
-
try {
|
|
455
|
-
const detailsResponse = await admin.graphql(SUBSCRIPTION_DETAILS_QUERY, {
|
|
456
|
-
variables: { id: active?.id }
|
|
457
|
-
});
|
|
458
|
-
const detailsJson = await detailsResponse.json();
|
|
459
|
-
if (detailsJson.errors?.length) {
|
|
460
|
-
logger.error?.("Partner subscription details query errors", { errors: detailsJson.errors });
|
|
461
|
-
}
|
|
462
|
-
const details = detailsJson.data?.node;
|
|
463
|
-
({ subscriptionPrice, subscriptionPeriod } = extractPricing(details));
|
|
464
|
-
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
465
|
-
return {
|
|
466
|
-
subscriptionStatus: details?.status ?? active?.status ?? "ACTIVE",
|
|
467
|
-
subscriptionName: details?.name ?? active?.name,
|
|
468
|
-
subscriptionId,
|
|
469
|
-
subscriptionPrice,
|
|
470
|
-
subscriptionPeriod
|
|
471
|
-
};
|
|
472
|
-
} catch (error) {
|
|
473
|
-
logger.error?.("Partner subscription details query failed", {
|
|
474
|
-
error: error instanceof Error ? error.message : String(error)
|
|
475
|
-
});
|
|
476
|
-
return null;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
480
|
-
return {
|
|
481
|
-
subscriptionStatus: active?.status ?? "ACTIVE",
|
|
482
|
-
subscriptionName: active?.name,
|
|
483
|
-
subscriptionId,
|
|
484
|
-
subscriptionPrice,
|
|
485
|
-
subscriptionPeriod
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
509
|
// Annotate the CommonJS export names for ESM import in node:
|
|
489
510
|
0 && (module.exports = {
|
|
490
511
|
createProgusConnector,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ConnectorConfig, T as TrackEventParams, a as TrackResult, S as SubscriptionEventData, A as AssignPartnerIdInput, b as
|
|
2
|
-
export {
|
|
1
|
+
import { C as ConnectorConfig, T as TrackEventParams, a as TrackResult, S as SubscriptionEventData, A as AssignPartnerIdInput, b as AssignPartnerIdWithSubscriptionInput, c as CheckPartnerIdResult, d as ShopifyAdminGraphQLClient } from './crossSell-BZZ9FX7S.cjs';
|
|
2
|
+
export { h as AppsCatalogEntry, i as CrossSellFetchOptions, j as CrossSellOptions, L as Logger, k as TrackEventName, f as fetchAppsCatalog, g as getCrossSellOffers, e as getCrossSellOffersFromApi } from './crossSell-BZZ9FX7S.cjs';
|
|
3
3
|
|
|
4
4
|
type Connector = {
|
|
5
5
|
track: (eventName: TrackEventParams["eventName"], payload: Omit<TrackEventParams, "eventName">) => Promise<TrackResult>;
|
|
@@ -25,6 +25,9 @@ type Connector = {
|
|
|
25
25
|
assignPartnerId: (payload: AssignPartnerIdInput) => Promise<TrackResult & {
|
|
26
26
|
partnerId?: string;
|
|
27
27
|
}>;
|
|
28
|
+
assignPartnerIdWithSubscription: (payload: AssignPartnerIdWithSubscriptionInput) => Promise<TrackResult & {
|
|
29
|
+
partnerId?: string;
|
|
30
|
+
}>;
|
|
28
31
|
checkPartnerId: (payload: {
|
|
29
32
|
shopDomain: string;
|
|
30
33
|
}) => Promise<CheckPartnerIdResult>;
|
|
@@ -39,4 +42,4 @@ declare function signPayload(body: string, secret: string): string;
|
|
|
39
42
|
|
|
40
43
|
declare function normalizePartnerId(value?: string | null): string | null;
|
|
41
44
|
|
|
42
|
-
export { AssignPartnerIdInput, CheckPartnerIdResult, ConnectorConfig, ShopifyAdminGraphQLClient, SubscriptionEventData, TrackEventParams, TrackResult, createProgusConnector, fetchActiveSubscriptionEventData, normalizePartnerId, signPayload };
|
|
45
|
+
export { AssignPartnerIdInput, AssignPartnerIdWithSubscriptionInput, CheckPartnerIdResult, ConnectorConfig, ShopifyAdminGraphQLClient, SubscriptionEventData, TrackEventParams, TrackResult, createProgusConnector, fetchActiveSubscriptionEventData, normalizePartnerId, signPayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ConnectorConfig, T as TrackEventParams, a as TrackResult, S as SubscriptionEventData, A as AssignPartnerIdInput, b as
|
|
2
|
-
export {
|
|
1
|
+
import { C as ConnectorConfig, T as TrackEventParams, a as TrackResult, S as SubscriptionEventData, A as AssignPartnerIdInput, b as AssignPartnerIdWithSubscriptionInput, c as CheckPartnerIdResult, d as ShopifyAdminGraphQLClient } from './crossSell-BZZ9FX7S.js';
|
|
2
|
+
export { h as AppsCatalogEntry, i as CrossSellFetchOptions, j as CrossSellOptions, L as Logger, k as TrackEventName, f as fetchAppsCatalog, g as getCrossSellOffers, e as getCrossSellOffersFromApi } from './crossSell-BZZ9FX7S.js';
|
|
3
3
|
|
|
4
4
|
type Connector = {
|
|
5
5
|
track: (eventName: TrackEventParams["eventName"], payload: Omit<TrackEventParams, "eventName">) => Promise<TrackResult>;
|
|
@@ -25,6 +25,9 @@ type Connector = {
|
|
|
25
25
|
assignPartnerId: (payload: AssignPartnerIdInput) => Promise<TrackResult & {
|
|
26
26
|
partnerId?: string;
|
|
27
27
|
}>;
|
|
28
|
+
assignPartnerIdWithSubscription: (payload: AssignPartnerIdWithSubscriptionInput) => Promise<TrackResult & {
|
|
29
|
+
partnerId?: string;
|
|
30
|
+
}>;
|
|
28
31
|
checkPartnerId: (payload: {
|
|
29
32
|
shopDomain: string;
|
|
30
33
|
}) => Promise<CheckPartnerIdResult>;
|
|
@@ -39,4 +42,4 @@ declare function signPayload(body: string, secret: string): string;
|
|
|
39
42
|
|
|
40
43
|
declare function normalizePartnerId(value?: string | null): string | null;
|
|
41
44
|
|
|
42
|
-
export { AssignPartnerIdInput, CheckPartnerIdResult, ConnectorConfig, ShopifyAdminGraphQLClient, SubscriptionEventData, TrackEventParams, TrackResult, createProgusConnector, fetchActiveSubscriptionEventData, normalizePartnerId, signPayload };
|
|
45
|
+
export { AssignPartnerIdInput, AssignPartnerIdWithSubscriptionInput, CheckPartnerIdResult, ConnectorConfig, ShopifyAdminGraphQLClient, SubscriptionEventData, TrackEventParams, TrackResult, createProgusConnector, fetchActiveSubscriptionEventData, normalizePartnerId, signPayload };
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,142 @@ import {
|
|
|
8
8
|
stripTrailingSlash
|
|
9
9
|
} from "./chunk-WZ5FAA44.js";
|
|
10
10
|
|
|
11
|
+
// src/subscription.ts
|
|
12
|
+
var ACTIVE_SUBSCRIPTIONS_QUERY = `
|
|
13
|
+
query {
|
|
14
|
+
currentAppInstallation {
|
|
15
|
+
activeSubscriptions {
|
|
16
|
+
id
|
|
17
|
+
name
|
|
18
|
+
status
|
|
19
|
+
lineItems {
|
|
20
|
+
plan {
|
|
21
|
+
pricingDetails {
|
|
22
|
+
__typename
|
|
23
|
+
... on AppRecurringPricing {
|
|
24
|
+
interval
|
|
25
|
+
price {
|
|
26
|
+
amount
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
... on AppUsagePricing {
|
|
30
|
+
cappedAmount {
|
|
31
|
+
amount
|
|
32
|
+
}
|
|
33
|
+
terms
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
var SUBSCRIPTION_DETAILS_QUERY = `
|
|
43
|
+
query AppSubscriptionDetails($id: ID!) {
|
|
44
|
+
node(id: $id) {
|
|
45
|
+
... on AppSubscription {
|
|
46
|
+
id
|
|
47
|
+
name
|
|
48
|
+
status
|
|
49
|
+
lineItems {
|
|
50
|
+
plan {
|
|
51
|
+
pricingDetails {
|
|
52
|
+
__typename
|
|
53
|
+
... on AppRecurringPricing {
|
|
54
|
+
interval
|
|
55
|
+
price {
|
|
56
|
+
amount
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
... on AppUsagePricing {
|
|
60
|
+
cappedAmount {
|
|
61
|
+
amount
|
|
62
|
+
}
|
|
63
|
+
terms
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
function normalizeInterval(intervalRaw, nameHint) {
|
|
73
|
+
const interval = intervalRaw ? String(intervalRaw).toUpperCase() : "";
|
|
74
|
+
if (interval === "ANNUAL" || interval === "EVERY_30_DAYS") return interval;
|
|
75
|
+
if (interval === "MONTHLY" || interval === "EVERY_30DAYS") return "EVERY_30_DAYS";
|
|
76
|
+
const name = (nameHint ?? "").toLowerCase();
|
|
77
|
+
if (name.includes("annual") || name.includes("year")) return "ANNUAL";
|
|
78
|
+
if (name) return "EVERY_30_DAYS";
|
|
79
|
+
return "";
|
|
80
|
+
}
|
|
81
|
+
function parseSubscriptionId(rawId) {
|
|
82
|
+
if (!rawId) return null;
|
|
83
|
+
return rawId.match(/\d+$/)?.[0] ?? rawId.split("/").pop() ?? rawId;
|
|
84
|
+
}
|
|
85
|
+
function parsePrice(rawPrice) {
|
|
86
|
+
if (typeof rawPrice === "number") return rawPrice;
|
|
87
|
+
if (typeof rawPrice === "string") {
|
|
88
|
+
const parsed = Number(rawPrice);
|
|
89
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
function extractPricing(subscription) {
|
|
94
|
+
const pricingDetails = subscription?.lineItems?.[0]?.plan?.pricingDetails;
|
|
95
|
+
const rawPrice = pricingDetails?.price?.amount ?? pricingDetails?.cappedAmount?.amount;
|
|
96
|
+
const subscriptionPrice = parsePrice(rawPrice);
|
|
97
|
+
const subscriptionPeriod = normalizeInterval(pricingDetails?.interval, subscription?.name);
|
|
98
|
+
return { subscriptionPrice, subscriptionPeriod };
|
|
99
|
+
}
|
|
100
|
+
async function fetchActiveSubscriptionEventData(admin, logger = console) {
|
|
101
|
+
const response = await admin.graphql(ACTIVE_SUBSCRIPTIONS_QUERY);
|
|
102
|
+
const result = await response.json();
|
|
103
|
+
if (result.errors?.length) {
|
|
104
|
+
logger.error?.("Partner subscription query errors", { errors: result.errors });
|
|
105
|
+
}
|
|
106
|
+
const subscriptions = result.data?.currentAppInstallation?.activeSubscriptions ?? [];
|
|
107
|
+
const active = subscriptions.find((sub) => String(sub.status ?? "").toUpperCase() === "ACTIVE") ?? subscriptions[0];
|
|
108
|
+
const subscriptionId = parseSubscriptionId(active?.id);
|
|
109
|
+
if (!subscriptionId) return null;
|
|
110
|
+
let { subscriptionPrice, subscriptionPeriod } = extractPricing(active);
|
|
111
|
+
if (!subscriptionPeriod || subscriptionPrice === null) {
|
|
112
|
+
try {
|
|
113
|
+
const detailsResponse = await admin.graphql(SUBSCRIPTION_DETAILS_QUERY, {
|
|
114
|
+
variables: { id: active?.id }
|
|
115
|
+
});
|
|
116
|
+
const detailsJson = await detailsResponse.json();
|
|
117
|
+
if (detailsJson.errors?.length) {
|
|
118
|
+
logger.error?.("Partner subscription details query errors", { errors: detailsJson.errors });
|
|
119
|
+
}
|
|
120
|
+
const details = detailsJson.data?.node;
|
|
121
|
+
({ subscriptionPrice, subscriptionPeriod } = extractPricing(details));
|
|
122
|
+
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
123
|
+
return {
|
|
124
|
+
subscriptionStatus: details?.status ?? active?.status ?? "ACTIVE",
|
|
125
|
+
subscriptionName: details?.name ?? active?.name,
|
|
126
|
+
subscriptionId,
|
|
127
|
+
subscriptionPrice,
|
|
128
|
+
subscriptionPeriod
|
|
129
|
+
};
|
|
130
|
+
} catch (error) {
|
|
131
|
+
logger.error?.("Partner subscription details query failed", {
|
|
132
|
+
error: error instanceof Error ? error.message : String(error)
|
|
133
|
+
});
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
138
|
+
return {
|
|
139
|
+
subscriptionStatus: active?.status ?? "ACTIVE",
|
|
140
|
+
subscriptionName: active?.name,
|
|
141
|
+
subscriptionId,
|
|
142
|
+
subscriptionPrice,
|
|
143
|
+
subscriptionPeriod
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
11
147
|
// src/signing.ts
|
|
12
148
|
import { createHmac } from "crypto";
|
|
13
149
|
function signPayload(body, secret) {
|
|
@@ -33,6 +169,7 @@ function createProgusConnector(config) {
|
|
|
33
169
|
trackSubscriptionUpdated: fail,
|
|
34
170
|
trackSubscriptionCancelled: fail,
|
|
35
171
|
assignPartnerId: fail,
|
|
172
|
+
assignPartnerIdWithSubscription: fail,
|
|
36
173
|
checkPartnerId: async () => ({ success: false, message, status: 500 })
|
|
37
174
|
};
|
|
38
175
|
}
|
|
@@ -134,6 +271,25 @@ function createProgusConnector(config) {
|
|
|
134
271
|
const result = await trackInstall({ shopDomain: payload.shopDomain, partnerId: normalized });
|
|
135
272
|
return { ...result, partnerId: normalized };
|
|
136
273
|
}
|
|
274
|
+
async function assignPartnerIdWithSubscription(payload) {
|
|
275
|
+
const { admin, ...rest } = payload;
|
|
276
|
+
const result = await assignPartnerId(rest);
|
|
277
|
+
if (!result.success) return result;
|
|
278
|
+
try {
|
|
279
|
+
const subscriptionPayload = await fetchActiveSubscriptionEventData(admin, logger);
|
|
280
|
+
if (subscriptionPayload) {
|
|
281
|
+
await trackSubscription({
|
|
282
|
+
shopDomain: rest.shopDomain,
|
|
283
|
+
data: subscriptionPayload
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
logger?.error?.("Partner subscription sync failed", {
|
|
288
|
+
error: error instanceof Error ? error.message : String(error)
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
137
293
|
async function checkPartnerId(payload) {
|
|
138
294
|
if (!payload.shopDomain) {
|
|
139
295
|
return { success: false, message: "Missing shop domain" };
|
|
@@ -204,145 +360,10 @@ function createProgusConnector(config) {
|
|
|
204
360
|
trackSubscriptionUpdated: trackSubscription,
|
|
205
361
|
trackSubscriptionCancelled: trackSubscription,
|
|
206
362
|
assignPartnerId,
|
|
363
|
+
assignPartnerIdWithSubscription,
|
|
207
364
|
checkPartnerId
|
|
208
365
|
};
|
|
209
366
|
}
|
|
210
|
-
|
|
211
|
-
// src/subscription.ts
|
|
212
|
-
var ACTIVE_SUBSCRIPTIONS_QUERY = `
|
|
213
|
-
query {
|
|
214
|
-
currentAppInstallation {
|
|
215
|
-
activeSubscriptions {
|
|
216
|
-
id
|
|
217
|
-
name
|
|
218
|
-
status
|
|
219
|
-
lineItems {
|
|
220
|
-
plan {
|
|
221
|
-
pricingDetails {
|
|
222
|
-
__typename
|
|
223
|
-
... on AppRecurringPricing {
|
|
224
|
-
interval
|
|
225
|
-
price {
|
|
226
|
-
amount
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
... on AppUsagePricing {
|
|
230
|
-
cappedAmount {
|
|
231
|
-
amount
|
|
232
|
-
}
|
|
233
|
-
terms
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
`;
|
|
242
|
-
var SUBSCRIPTION_DETAILS_QUERY = `
|
|
243
|
-
query AppSubscriptionDetails($id: ID!) {
|
|
244
|
-
node(id: $id) {
|
|
245
|
-
... on AppSubscription {
|
|
246
|
-
id
|
|
247
|
-
name
|
|
248
|
-
status
|
|
249
|
-
lineItems {
|
|
250
|
-
plan {
|
|
251
|
-
pricingDetails {
|
|
252
|
-
__typename
|
|
253
|
-
... on AppRecurringPricing {
|
|
254
|
-
interval
|
|
255
|
-
price {
|
|
256
|
-
amount
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
... on AppUsagePricing {
|
|
260
|
-
cappedAmount {
|
|
261
|
-
amount
|
|
262
|
-
}
|
|
263
|
-
terms
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
`;
|
|
272
|
-
function normalizeInterval(intervalRaw, nameHint) {
|
|
273
|
-
const interval = intervalRaw ? String(intervalRaw).toUpperCase() : "";
|
|
274
|
-
if (interval === "ANNUAL" || interval === "EVERY_30_DAYS") return interval;
|
|
275
|
-
if (interval === "MONTHLY" || interval === "EVERY_30DAYS") return "EVERY_30_DAYS";
|
|
276
|
-
const name = (nameHint ?? "").toLowerCase();
|
|
277
|
-
if (name.includes("annual") || name.includes("year")) return "ANNUAL";
|
|
278
|
-
if (name) return "EVERY_30_DAYS";
|
|
279
|
-
return "";
|
|
280
|
-
}
|
|
281
|
-
function parseSubscriptionId(rawId) {
|
|
282
|
-
if (!rawId) return null;
|
|
283
|
-
return rawId.match(/\d+$/)?.[0] ?? rawId.split("/").pop() ?? rawId;
|
|
284
|
-
}
|
|
285
|
-
function parsePrice(rawPrice) {
|
|
286
|
-
if (typeof rawPrice === "number") return rawPrice;
|
|
287
|
-
if (typeof rawPrice === "string") {
|
|
288
|
-
const parsed = Number(rawPrice);
|
|
289
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
290
|
-
}
|
|
291
|
-
return null;
|
|
292
|
-
}
|
|
293
|
-
function extractPricing(subscription) {
|
|
294
|
-
const pricingDetails = subscription?.lineItems?.[0]?.plan?.pricingDetails;
|
|
295
|
-
const rawPrice = pricingDetails?.price?.amount ?? pricingDetails?.cappedAmount?.amount;
|
|
296
|
-
const subscriptionPrice = parsePrice(rawPrice);
|
|
297
|
-
const subscriptionPeriod = normalizeInterval(pricingDetails?.interval, subscription?.name);
|
|
298
|
-
return { subscriptionPrice, subscriptionPeriod };
|
|
299
|
-
}
|
|
300
|
-
async function fetchActiveSubscriptionEventData(admin, logger = console) {
|
|
301
|
-
const response = await admin.graphql(ACTIVE_SUBSCRIPTIONS_QUERY);
|
|
302
|
-
const result = await response.json();
|
|
303
|
-
if (result.errors?.length) {
|
|
304
|
-
logger.error?.("Partner subscription query errors", { errors: result.errors });
|
|
305
|
-
}
|
|
306
|
-
const subscriptions = result.data?.currentAppInstallation?.activeSubscriptions ?? [];
|
|
307
|
-
const active = subscriptions.find((sub) => String(sub.status ?? "").toUpperCase() === "ACTIVE") ?? subscriptions[0];
|
|
308
|
-
const subscriptionId = parseSubscriptionId(active?.id);
|
|
309
|
-
if (!subscriptionId) return null;
|
|
310
|
-
let { subscriptionPrice, subscriptionPeriod } = extractPricing(active);
|
|
311
|
-
if (!subscriptionPeriod || subscriptionPrice === null) {
|
|
312
|
-
try {
|
|
313
|
-
const detailsResponse = await admin.graphql(SUBSCRIPTION_DETAILS_QUERY, {
|
|
314
|
-
variables: { id: active?.id }
|
|
315
|
-
});
|
|
316
|
-
const detailsJson = await detailsResponse.json();
|
|
317
|
-
if (detailsJson.errors?.length) {
|
|
318
|
-
logger.error?.("Partner subscription details query errors", { errors: detailsJson.errors });
|
|
319
|
-
}
|
|
320
|
-
const details = detailsJson.data?.node;
|
|
321
|
-
({ subscriptionPrice, subscriptionPeriod } = extractPricing(details));
|
|
322
|
-
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
323
|
-
return {
|
|
324
|
-
subscriptionStatus: details?.status ?? active?.status ?? "ACTIVE",
|
|
325
|
-
subscriptionName: details?.name ?? active?.name,
|
|
326
|
-
subscriptionId,
|
|
327
|
-
subscriptionPrice,
|
|
328
|
-
subscriptionPeriod
|
|
329
|
-
};
|
|
330
|
-
} catch (error) {
|
|
331
|
-
logger.error?.("Partner subscription details query failed", {
|
|
332
|
-
error: error instanceof Error ? error.message : String(error)
|
|
333
|
-
});
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (!subscriptionPeriod || subscriptionPrice === null) return null;
|
|
338
|
-
return {
|
|
339
|
-
subscriptionStatus: active?.status ?? "ACTIVE",
|
|
340
|
-
subscriptionName: active?.name,
|
|
341
|
-
subscriptionId,
|
|
342
|
-
subscriptionPrice,
|
|
343
|
-
subscriptionPeriod
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
367
|
export {
|
|
347
368
|
createProgusConnector,
|
|
348
369
|
fetchActiveSubscriptionEventData,
|