@huloglobal/vendure-plugin-visitor-analytics 0.7.0 → 0.8.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/CHANGELOG.md +83 -15
- package/dist/abandoned-cart.controller.d.ts +78 -0
- package/dist/abandoned-cart.controller.d.ts.map +1 -0
- package/dist/abandoned-cart.controller.js +251 -0
- package/dist/abandoned-cart.controller.js.map +1 -0
- package/dist/abandoned-cart.entity.d.ts +61 -0
- package/dist/abandoned-cart.entity.d.ts.map +1 -0
- package/dist/abandoned-cart.entity.js +143 -0
- package/dist/abandoned-cart.entity.js.map +1 -0
- package/dist/abandoned-cart.scanner.d.ts +34 -0
- package/dist/abandoned-cart.scanner.d.ts.map +1 -0
- package/dist/abandoned-cart.scanner.js +85 -0
- package/dist/abandoned-cart.scanner.js.map +1 -0
- package/dist/abandoned-cart.service.d.ts +92 -0
- package/dist/abandoned-cart.service.d.ts.map +1 -0
- package/dist/abandoned-cart.service.js +276 -0
- package/dist/abandoned-cart.service.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/journey-buffs.controller.d.ts +43 -0
- package/dist/journey-buffs.controller.d.ts.map +1 -0
- package/dist/journey-buffs.controller.js +79 -0
- package/dist/journey-buffs.controller.js.map +1 -0
- package/dist/journey-buffs.service.d.ts +53 -0
- package/dist/journey-buffs.service.d.ts.map +1 -0
- package/dist/journey-buffs.service.js +141 -0
- package/dist/journey-buffs.service.js.map +1 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +28 -3
- package/dist/plugin.js.map +1 -1
- package/dist/product-co-view.entity.d.ts +19 -0
- package/dist/product-co-view.entity.d.ts.map +1 -0
- package/dist/product-co-view.entity.js +52 -0
- package/dist/product-co-view.entity.js.map +1 -0
- package/dist/recommendations.controller.d.ts +72 -0
- package/dist/recommendations.controller.d.ts.map +1 -0
- package/dist/recommendations.controller.js +123 -0
- package/dist/recommendations.controller.js.map +1 -0
- package/dist/recommendations.service.d.ts +62 -0
- package/dist/recommendations.service.d.ts.map +1 -0
- package/dist/recommendations.service.js +167 -0
- package/dist/recommendations.service.js.map +1 -0
- package/dist/search-analytics.controller.d.ts +36 -0
- package/dist/search-analytics.controller.d.ts.map +1 -0
- package/dist/search-analytics.controller.js +86 -0
- package/dist/search-analytics.controller.js.map +1 -0
- package/dist/search-analytics.service.d.ts +36 -0
- package/dist/search-analytics.service.d.ts.map +1 -0
- package/dist/search-analytics.service.js +105 -0
- package/dist/search-analytics.service.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,46 +2,100 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@huloglobal/vendure-plugin-visitor-analytics` are
|
|
4
4
|
documented here. The format follows
|
|
5
|
-
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this
|
|
6
|
-
|
|
5
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project
|
|
6
|
+
adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.
|
|
8
|
+
## [0.7.0] — 2026-07-04
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Boot-time compatibility check via the new SDK helper
|
|
12
|
+
`warnIfIncompatibleVendure()`. Logs a non-fatal warning when the runtime
|
|
13
|
+
`@vendure/core` version is outside the tested range. Silent when inside;
|
|
14
|
+
fail-open on unparseable versions.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Peer dep on `@vendure/core` tightened to `>=3.5.0 <4.0.0` — Vendure 3.5,
|
|
18
|
+
3.6 and 3.7 are all covered. Anything under 3.5 has never been tested;
|
|
19
|
+
anything from 4.0 upwards is deferred until the changelog is reviewed.
|
|
20
|
+
- Uses `@huloglobal/vendure-licence-sdk@^0.6.0`.
|
|
21
|
+
|
|
22
|
+
## [0.6.0] — 2026-06-23
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- Vendure Admin API GraphQL extensions. Operator endpoints are now
|
|
26
|
+
first-class GraphQL queries alongside the existing REST admin
|
|
27
|
+
endpoints: `huloVisitorSummary`, `huloVisitorSources`,
|
|
28
|
+
`huloVisitorTopPages`, `huloVisitorFunnel`, `huloVisitorJourney`.
|
|
29
|
+
- Storefront path (`POST /ees/track`) stays REST — it's anonymous,
|
|
30
|
+
high-frequency, and can ingest millions of events a day; the
|
|
31
|
+
resolver stack would add pointless overhead per event.
|
|
32
|
+
|
|
33
|
+
## [0.5.0] — 2026-06-23
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- Tier-gating on every premium feature via the SDK's `isLicensed()`
|
|
37
|
+
helper. Unlicensed installs get:
|
|
38
|
+
- a hard 100 events / UTC day cap on `POST /ees/track` (returns
|
|
39
|
+
`{skipped: 'free-tier-cap'}` after that);
|
|
40
|
+
- live SSE feed 402;
|
|
41
|
+
- conversion-goal creation 402;
|
|
42
|
+
- CSV export 402.
|
|
43
|
+
- Anti-tamper heartbeat via the SDK.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- Relicensed the GitHub source to AGPL-3.0. Published npm builds remain
|
|
47
|
+
under the commercial licence documented at
|
|
48
|
+
<https://huloglobal.com/legal/terms/>.
|
|
49
|
+
- npm builds now include Sigstore provenance attestations.
|
|
50
|
+
|
|
51
|
+
## [0.4.3] — 2026-06-21
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- Dropped the conflicting `display: block` on mobile tables that broke
|
|
55
|
+
the row / cell alignment.
|
|
56
|
+
|
|
57
|
+
## [0.4.2] — 2026-06-21
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- 44px minimum tap targets on every interactive element in the admin UI.
|
|
61
|
+
|
|
62
|
+
## [0.4.1] — 2026-06-21
|
|
9
63
|
|
|
10
64
|
### Changed
|
|
11
65
|
- Comprehensive README refresh — documents the full v0.4 feature set
|
|
12
66
|
with the storefront snippet, every privacy + security option, and
|
|
13
67
|
the conversion-goals API.
|
|
14
68
|
|
|
15
|
-
## [0.4.0]
|
|
69
|
+
## [0.4.0] — 2026-06-20
|
|
16
70
|
|
|
17
71
|
### Added
|
|
18
72
|
- Signed visitor + session cookies via the licence-sdk `signValue` /
|
|
19
73
|
`verifySignedValue` helpers — tampered cookies are rejected.
|
|
20
74
|
- `Secure` cookie flag is set automatically when serving over HTTPS.
|
|
21
|
-
- Rate limiter (240/60s default) on `POST /ees/track`.
|
|
75
|
+
- Rate limiter (240 requests / 60s default) on `POST /ees/track`.
|
|
22
76
|
- `corsAllowedOrigins` option restricts CORS reflection to the
|
|
23
77
|
configured list (legacy wildcard preserved when empty).
|
|
24
78
|
- Security headers on every response.
|
|
25
79
|
- Opt-in retention sweeper via `options.retention`.
|
|
26
80
|
|
|
27
|
-
## [0.3.3]
|
|
81
|
+
## [0.3.3] — 2026-06-20
|
|
28
82
|
|
|
29
83
|
### Changed
|
|
30
|
-
- Mobile-friendly admin UI — summary cards reflow, tables scroll
|
|
31
|
-
|
|
84
|
+
- Mobile-friendly admin UI — summary cards reflow, tables scroll inside
|
|
85
|
+
their card, profile drawer goes full-width.
|
|
32
86
|
|
|
33
|
-
## [0.3.2]
|
|
87
|
+
## [0.3.2] — 2026-06-20
|
|
34
88
|
|
|
35
89
|
### Changed
|
|
36
90
|
- Republish targeting `@huloglobal/vendure-licence-sdk@^0.2.0`.
|
|
37
91
|
|
|
38
|
-
## [0.3.1]
|
|
92
|
+
## [0.3.1] — 2026-06-20
|
|
39
93
|
|
|
40
94
|
### Added
|
|
41
95
|
- `UpdateChecker` integration — `/ees/visitors/status` endpoint returns
|
|
42
96
|
version + update info; admin banner appears on new releases.
|
|
43
97
|
|
|
44
|
-
## [0.3.0]
|
|
98
|
+
## [0.3.0] — 2026-06-20
|
|
45
99
|
|
|
46
100
|
### Added
|
|
47
101
|
- **Conversion goals** — new `ConversionGoal` entity with a URL-glob
|
|
@@ -62,7 +116,7 @@ project adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
62
116
|
`consent:true` or cookie `ees_consent=1`
|
|
63
117
|
- **CSV export** — `GET /ees/visitors/export.csv?days=N` (max 90).
|
|
64
118
|
|
|
65
|
-
## [0.2.0]
|
|
119
|
+
## [0.2.0] — 2026-06-19
|
|
66
120
|
|
|
67
121
|
### Added
|
|
68
122
|
- **UTM attribution** — `utmSource` / `utmMedium` / `utmCampaign` /
|
|
@@ -78,7 +132,7 @@ project adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
78
132
|
- **Custom event recipes** — README section with copy-paste storefront
|
|
79
133
|
snippets for add-to-cart, search, quote-request, newsletter signup.
|
|
80
134
|
|
|
81
|
-
## [0.1.0] —
|
|
135
|
+
## [0.1.0] — 2026-06-19
|
|
82
136
|
|
|
83
137
|
### Added
|
|
84
138
|
- `VisitorAnalyticsPlugin` — ingest endpoint + admin dashboards.
|
|
@@ -92,5 +146,19 @@ project adheres to [semantic versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
92
146
|
profile + journey.
|
|
93
147
|
- Admin UI: summary tiles, funnel bars, top + exit page tables,
|
|
94
148
|
recent visitors table with clickable profile drawer.
|
|
95
|
-
- Licence verification via `@huloglobal/vendure-licence-sdk` with
|
|
96
|
-
polling.
|
|
149
|
+
- Licence verification via `@huloglobal/vendure-licence-sdk` with
|
|
150
|
+
revocation polling.
|
|
151
|
+
|
|
152
|
+
[0.7.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.7.0
|
|
153
|
+
[0.6.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.6.0
|
|
154
|
+
[0.5.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.5.0
|
|
155
|
+
[0.4.3]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.4.3
|
|
156
|
+
[0.4.2]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.4.2
|
|
157
|
+
[0.4.1]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.4.1
|
|
158
|
+
[0.4.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.4.0
|
|
159
|
+
[0.3.3]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.3.3
|
|
160
|
+
[0.3.2]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.3.2
|
|
161
|
+
[0.3.1]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.3.1
|
|
162
|
+
[0.3.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.3.0
|
|
163
|
+
[0.2.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.2.0
|
|
164
|
+
[0.1.0]: https://github.com/exceeded/vendure-plugin-visitor-analytics/releases/tag/v0.1.0
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { RequestContext } from '@vendure/core';
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import { AbandonedCartService } from './abandoned-cart.service';
|
|
4
|
+
/**
|
|
5
|
+
* Admin API for the Abandoned Cart feature.
|
|
6
|
+
*
|
|
7
|
+
* Endpoints:
|
|
8
|
+
* GET /ees/abandoned-carts — paginated list with filters
|
|
9
|
+
* GET /ees/abandoned-carts/summary — totals + top-value + recovery rate
|
|
10
|
+
* GET /ees/abandoned-carts/:id — detail incl. parsed items
|
|
11
|
+
* POST /ees/abandoned-carts/:id/recovery-link — mint/reissue signed URL
|
|
12
|
+
* POST /ees/abandoned-carts/:id/status — mark recovered/dismissed
|
|
13
|
+
* GET /ees/abandoned-carts/export.csv — CSV export
|
|
14
|
+
*
|
|
15
|
+
* Storefront-side (unauthenticated):
|
|
16
|
+
* GET /ees/recover-cart?t=... — resolve a token → items
|
|
17
|
+
*/
|
|
18
|
+
export declare class AbandonedCartController {
|
|
19
|
+
private readonly service;
|
|
20
|
+
constructor(service: AbandonedCartService);
|
|
21
|
+
list(ctx: RequestContext, takeRaw?: string, skipRaw?: string, status?: string, minValueRaw?: string, email?: string): Promise<{
|
|
22
|
+
items: any;
|
|
23
|
+
total: number;
|
|
24
|
+
take: number;
|
|
25
|
+
skip: number;
|
|
26
|
+
}>;
|
|
27
|
+
summary(ctx: RequestContext, daysRaw?: string): Promise<{
|
|
28
|
+
windowDays: number;
|
|
29
|
+
total: number;
|
|
30
|
+
openCount: number;
|
|
31
|
+
recoveredCount: number;
|
|
32
|
+
convertedCount: number;
|
|
33
|
+
expiredCount: number;
|
|
34
|
+
dismissedCount: number;
|
|
35
|
+
recoveryRatePct: number;
|
|
36
|
+
totalValueMinor: number;
|
|
37
|
+
recoveredValueMinor: number;
|
|
38
|
+
avgValueMinor: number;
|
|
39
|
+
}>;
|
|
40
|
+
exportCsv(ctx: RequestContext, res: Response, daysRaw?: string): Promise<void>;
|
|
41
|
+
detail(ctx: RequestContext, idRaw: string): Promise<any>;
|
|
42
|
+
issueRecoveryLink(ctx: RequestContext, idRaw: string): Promise<{
|
|
43
|
+
error: string;
|
|
44
|
+
hint: string;
|
|
45
|
+
ok?: undefined;
|
|
46
|
+
url?: undefined;
|
|
47
|
+
} | {
|
|
48
|
+
ok: boolean;
|
|
49
|
+
url: string;
|
|
50
|
+
error?: undefined;
|
|
51
|
+
hint?: undefined;
|
|
52
|
+
}>;
|
|
53
|
+
setStatus(ctx: RequestContext, idRaw: string, body: {
|
|
54
|
+
status?: string;
|
|
55
|
+
}): Promise<{
|
|
56
|
+
error: string;
|
|
57
|
+
ok?: undefined;
|
|
58
|
+
} | {
|
|
59
|
+
ok: boolean;
|
|
60
|
+
error?: undefined;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Public storefront endpoint — decodes a recovery token into a set
|
|
64
|
+
* of cart items the storefront can restore. Rate-limited by the
|
|
65
|
+
* plugin's usual ingest limiter (same origin as the tracker).
|
|
66
|
+
*/
|
|
67
|
+
recover(req: Request, token?: string): Promise<{
|
|
68
|
+
error: string;
|
|
69
|
+
} | {
|
|
70
|
+
id: number;
|
|
71
|
+
currency: string;
|
|
72
|
+
items: any[];
|
|
73
|
+
email: string | null;
|
|
74
|
+
ok: boolean;
|
|
75
|
+
error?: undefined;
|
|
76
|
+
}>;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=abandoned-cart.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandoned-cart.controller.d.ts","sourceRoot":"","sources":["../src/abandoned-cart.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAO,cAAc,EAAqB,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE;;;;;;;;;;;;;GAaG;AACH,qBACa,uBAAuB;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,oBAAoB;IAIpD,IAAI,CACC,GAAG,EAAE,cAAc,EACX,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACvB,KAAK,CAAC,EAAE,MAAM;;;;;;IAuC5B,OAAO,CAAQ,GAAG,EAAE,cAAc,EAAiB,OAAO,CAAC,EAAE,MAAM;;;;;;;;;;;;;IAuCnE,SAAS,CAAQ,GAAG,EAAE,cAAc,EAAS,GAAG,EAAE,QAAQ,EAAiB,OAAO,CAAC,EAAE,MAAM;IA+B3F,MAAM,CAAQ,GAAG,EAAE,cAAc,EAAe,KAAK,EAAE,MAAM;IAgB7D,iBAAiB,CAAQ,GAAG,EAAE,cAAc,EAAe,KAAK,EAAE,MAAM;;;;;;;;;;;IASxE,SAAS,CACJ,GAAG,EAAE,cAAc,EACb,KAAK,EAAE,MAAM,EAClB,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;;;;;;;IAWrC;;;;OAIG;IAEG,OAAO,CAAQ,GAAG,EAAE,OAAO,EAAc,KAAK,CAAC,EAAE,MAAM;;;;;;;;;;CAOhE"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.AbandonedCartController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const core_1 = require("@vendure/core");
|
|
18
|
+
const abandoned_cart_service_1 = require("./abandoned-cart.service");
|
|
19
|
+
/**
|
|
20
|
+
* Admin API for the Abandoned Cart feature.
|
|
21
|
+
*
|
|
22
|
+
* Endpoints:
|
|
23
|
+
* GET /ees/abandoned-carts — paginated list with filters
|
|
24
|
+
* GET /ees/abandoned-carts/summary — totals + top-value + recovery rate
|
|
25
|
+
* GET /ees/abandoned-carts/:id — detail incl. parsed items
|
|
26
|
+
* POST /ees/abandoned-carts/:id/recovery-link — mint/reissue signed URL
|
|
27
|
+
* POST /ees/abandoned-carts/:id/status — mark recovered/dismissed
|
|
28
|
+
* GET /ees/abandoned-carts/export.csv — CSV export
|
|
29
|
+
*
|
|
30
|
+
* Storefront-side (unauthenticated):
|
|
31
|
+
* GET /ees/recover-cart?t=... — resolve a token → items
|
|
32
|
+
*/
|
|
33
|
+
let AbandonedCartController = class AbandonedCartController {
|
|
34
|
+
constructor(service) {
|
|
35
|
+
this.service = service;
|
|
36
|
+
}
|
|
37
|
+
async list(ctx, takeRaw, skipRaw, status, minValueRaw, email) {
|
|
38
|
+
var _a;
|
|
39
|
+
const take = Math.min(Math.max(1, parseInt(takeRaw || '25', 10) || 25), 200);
|
|
40
|
+
const skip = Math.max(0, parseInt(skipRaw || '0', 10) || 0);
|
|
41
|
+
const where = [];
|
|
42
|
+
const params = [];
|
|
43
|
+
if (status) {
|
|
44
|
+
where.push('status = ?');
|
|
45
|
+
params.push(status);
|
|
46
|
+
}
|
|
47
|
+
if (minValueRaw) {
|
|
48
|
+
const v = parseInt(minValueRaw, 10);
|
|
49
|
+
if (Number.isFinite(v)) {
|
|
50
|
+
where.push('totalMinor >= ?');
|
|
51
|
+
params.push(v);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (email) {
|
|
55
|
+
where.push('LOWER(email) LIKE ?');
|
|
56
|
+
params.push(`%${email.toLowerCase()}%`);
|
|
57
|
+
}
|
|
58
|
+
const clause = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
|
59
|
+
const conn = this.service.connection.rawConnection;
|
|
60
|
+
const [rows, totalRow] = await Promise.all([
|
|
61
|
+
conn.query(`SELECT id, sessionId, visitorId, customerId, currency, totalMinor, itemCount,
|
|
62
|
+
email, status, abandonedAt, recoveredAt, notificationSent,
|
|
63
|
+
utmSource, utmMedium, countryCode
|
|
64
|
+
FROM abandoned_cart
|
|
65
|
+
${clause}
|
|
66
|
+
ORDER BY abandonedAt DESC
|
|
67
|
+
LIMIT ? OFFSET ?`, [...params, take, skip]),
|
|
68
|
+
conn.query(`SELECT COUNT(*) AS c FROM abandoned_cart ${clause}`, params),
|
|
69
|
+
]);
|
|
70
|
+
return {
|
|
71
|
+
items: rows,
|
|
72
|
+
total: Number(((_a = totalRow === null || totalRow === void 0 ? void 0 : totalRow[0]) === null || _a === void 0 ? void 0 : _a.c) || 0),
|
|
73
|
+
take, skip,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async summary(ctx, daysRaw) {
|
|
77
|
+
const days = Math.min(Math.max(1, parseInt(daysRaw || '30', 10) || 30), 365);
|
|
78
|
+
const since = new Date(Date.now() - days * 86400000);
|
|
79
|
+
const conn = this.service.connection.rawConnection;
|
|
80
|
+
const rows = await conn.query(`SELECT
|
|
81
|
+
COUNT(*) AS total,
|
|
82
|
+
SUM(status = 'abandoned') AS openCount,
|
|
83
|
+
SUM(status = 'recovered') AS recoveredCount,
|
|
84
|
+
SUM(status = 'converted') AS convertedCount,
|
|
85
|
+
SUM(status = 'expired') AS expiredCount,
|
|
86
|
+
SUM(status = 'dismissed') AS dismissedCount,
|
|
87
|
+
SUM(totalMinor) AS totalValueMinor,
|
|
88
|
+
SUM(CASE WHEN status IN ('recovered','converted') THEN totalMinor ELSE 0 END) AS recoveredValueMinor,
|
|
89
|
+
AVG(totalMinor) AS avgValueMinor
|
|
90
|
+
FROM abandoned_cart
|
|
91
|
+
WHERE abandonedAt >= ?`, [since]);
|
|
92
|
+
const s = (rows === null || rows === void 0 ? void 0 : rows[0]) || {};
|
|
93
|
+
const total = Number(s.total || 0);
|
|
94
|
+
const rec = Number(s.recoveredCount || 0) + Number(s.convertedCount || 0);
|
|
95
|
+
return {
|
|
96
|
+
windowDays: days,
|
|
97
|
+
total,
|
|
98
|
+
openCount: Number(s.openCount || 0),
|
|
99
|
+
recoveredCount: Number(s.recoveredCount || 0),
|
|
100
|
+
convertedCount: Number(s.convertedCount || 0),
|
|
101
|
+
expiredCount: Number(s.expiredCount || 0),
|
|
102
|
+
dismissedCount: Number(s.dismissedCount || 0),
|
|
103
|
+
recoveryRatePct: total ? Math.round((rec / total) * 1000) / 10 : 0,
|
|
104
|
+
totalValueMinor: Number(s.totalValueMinor || 0),
|
|
105
|
+
recoveredValueMinor: Number(s.recoveredValueMinor || 0),
|
|
106
|
+
avgValueMinor: Math.round(Number(s.avgValueMinor || 0)),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async exportCsv(ctx, res, daysRaw) {
|
|
110
|
+
const days = Math.min(Math.max(1, parseInt(daysRaw || '30', 10) || 30), 365);
|
|
111
|
+
const since = new Date(Date.now() - days * 86400000);
|
|
112
|
+
const conn = this.service.connection.rawConnection;
|
|
113
|
+
const rows = await conn.query(`SELECT id, sessionId, visitorId, customerId, currency, totalMinor, itemCount,
|
|
114
|
+
email, status, abandonedAt, recoveredAt, utmSource, utmMedium, utmCampaign, countryCode
|
|
115
|
+
FROM abandoned_cart
|
|
116
|
+
WHERE abandonedAt >= ?
|
|
117
|
+
ORDER BY abandonedAt DESC
|
|
118
|
+
LIMIT 50000`, [since]);
|
|
119
|
+
res.setHeader('content-type', 'text/csv; charset=utf-8');
|
|
120
|
+
res.setHeader('content-disposition', `attachment; filename="abandoned-carts-${new Date().toISOString().slice(0, 10)}.csv"`);
|
|
121
|
+
const esc = (v) => {
|
|
122
|
+
const s = v == null ? '' : String(v);
|
|
123
|
+
return /[,"\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
124
|
+
};
|
|
125
|
+
const cols = ['id', 'sessionId', 'visitorId', 'customerId', 'currency', 'totalMinor', 'itemCount',
|
|
126
|
+
'email', 'status', 'abandonedAt', 'recoveredAt', 'utmSource', 'utmMedium', 'utmCampaign', 'countryCode'];
|
|
127
|
+
res.write(cols.join(',') + '\n');
|
|
128
|
+
for (const r of rows) {
|
|
129
|
+
res.write(cols.map(c => esc(r[c])).join(',') + '\n');
|
|
130
|
+
}
|
|
131
|
+
res.end();
|
|
132
|
+
}
|
|
133
|
+
async detail(ctx, idRaw) {
|
|
134
|
+
const id = parseInt(idRaw, 10);
|
|
135
|
+
const conn = this.service.connection.rawConnection;
|
|
136
|
+
const rows = await conn.query(`SELECT * FROM abandoned_cart WHERE id = ? LIMIT 1`, [id]);
|
|
137
|
+
if (!(rows === null || rows === void 0 ? void 0 : rows.length))
|
|
138
|
+
return { error: 'not-found' };
|
|
139
|
+
const r = rows[0];
|
|
140
|
+
let items = [];
|
|
141
|
+
try {
|
|
142
|
+
items = JSON.parse(r.itemsJson || '[]');
|
|
143
|
+
}
|
|
144
|
+
catch { }
|
|
145
|
+
return { ...r, items };
|
|
146
|
+
}
|
|
147
|
+
async issueRecoveryLink(ctx, idRaw) {
|
|
148
|
+
const id = parseInt(idRaw, 10);
|
|
149
|
+
const url = await this.service.issueRecoveryLink(id);
|
|
150
|
+
if (!url)
|
|
151
|
+
return { error: 'recovery-disabled-or-not-found', hint: 'Set abandonment.recoveryLinkSecret in plugin options' };
|
|
152
|
+
return { ok: true, url };
|
|
153
|
+
}
|
|
154
|
+
async setStatus(ctx, idRaw, body) {
|
|
155
|
+
const id = parseInt(idRaw, 10);
|
|
156
|
+
const status = String((body === null || body === void 0 ? void 0 : body.status) || '');
|
|
157
|
+
if (!['recovered', 'dismissed', 'abandoned'].includes(status)) {
|
|
158
|
+
return { error: 'invalid-status' };
|
|
159
|
+
}
|
|
160
|
+
const ok = await this.service.markStatus(id, status);
|
|
161
|
+
return ok ? { ok: true } : { error: 'not-found' };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Public storefront endpoint — decodes a recovery token into a set
|
|
165
|
+
* of cart items the storefront can restore. Rate-limited by the
|
|
166
|
+
* plugin's usual ingest limiter (same origin as the tracker).
|
|
167
|
+
*/
|
|
168
|
+
async recover(req, token) {
|
|
169
|
+
const t = String(token || '').trim();
|
|
170
|
+
if (!t)
|
|
171
|
+
return { error: 'missing-token' };
|
|
172
|
+
const result = await this.service.findByRecoveryToken(t);
|
|
173
|
+
if (!result)
|
|
174
|
+
return { error: 'expired-or-invalid' };
|
|
175
|
+
return { ok: true, ...result };
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
exports.AbandonedCartController = AbandonedCartController;
|
|
179
|
+
__decorate([
|
|
180
|
+
(0, common_1.Get)('abandoned-carts'),
|
|
181
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
182
|
+
__param(0, (0, core_1.Ctx)()),
|
|
183
|
+
__param(1, (0, common_1.Query)('take')),
|
|
184
|
+
__param(2, (0, common_1.Query)('skip')),
|
|
185
|
+
__param(3, (0, common_1.Query)('status')),
|
|
186
|
+
__param(4, (0, common_1.Query)('minValue')),
|
|
187
|
+
__param(5, (0, common_1.Query)('email')),
|
|
188
|
+
__metadata("design:type", Function),
|
|
189
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String, String, String, String, String]),
|
|
190
|
+
__metadata("design:returntype", Promise)
|
|
191
|
+
], AbandonedCartController.prototype, "list", null);
|
|
192
|
+
__decorate([
|
|
193
|
+
(0, common_1.Get)('abandoned-carts/summary'),
|
|
194
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
195
|
+
__param(0, (0, core_1.Ctx)()),
|
|
196
|
+
__param(1, (0, common_1.Query)('days')),
|
|
197
|
+
__metadata("design:type", Function),
|
|
198
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String]),
|
|
199
|
+
__metadata("design:returntype", Promise)
|
|
200
|
+
], AbandonedCartController.prototype, "summary", null);
|
|
201
|
+
__decorate([
|
|
202
|
+
(0, common_1.Get)('abandoned-carts/export.csv'),
|
|
203
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
204
|
+
__param(0, (0, core_1.Ctx)()),
|
|
205
|
+
__param(1, (0, common_1.Res)()),
|
|
206
|
+
__param(2, (0, common_1.Query)('days')),
|
|
207
|
+
__metadata("design:type", Function),
|
|
208
|
+
__metadata("design:paramtypes", [core_1.RequestContext, Object, String]),
|
|
209
|
+
__metadata("design:returntype", Promise)
|
|
210
|
+
], AbandonedCartController.prototype, "exportCsv", null);
|
|
211
|
+
__decorate([
|
|
212
|
+
(0, common_1.Get)('abandoned-carts/:id'),
|
|
213
|
+
(0, core_1.Allow)(core_1.Permission.ReadCustomer),
|
|
214
|
+
__param(0, (0, core_1.Ctx)()),
|
|
215
|
+
__param(1, (0, common_1.Param)('id')),
|
|
216
|
+
__metadata("design:type", Function),
|
|
217
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String]),
|
|
218
|
+
__metadata("design:returntype", Promise)
|
|
219
|
+
], AbandonedCartController.prototype, "detail", null);
|
|
220
|
+
__decorate([
|
|
221
|
+
(0, common_1.Post)('abandoned-carts/:id/recovery-link'),
|
|
222
|
+
(0, core_1.Allow)(core_1.Permission.UpdateCustomer),
|
|
223
|
+
__param(0, (0, core_1.Ctx)()),
|
|
224
|
+
__param(1, (0, common_1.Param)('id')),
|
|
225
|
+
__metadata("design:type", Function),
|
|
226
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String]),
|
|
227
|
+
__metadata("design:returntype", Promise)
|
|
228
|
+
], AbandonedCartController.prototype, "issueRecoveryLink", null);
|
|
229
|
+
__decorate([
|
|
230
|
+
(0, common_1.Post)('abandoned-carts/:id/status'),
|
|
231
|
+
(0, core_1.Allow)(core_1.Permission.UpdateCustomer),
|
|
232
|
+
__param(0, (0, core_1.Ctx)()),
|
|
233
|
+
__param(1, (0, common_1.Param)('id')),
|
|
234
|
+
__param(2, (0, common_1.Body)()),
|
|
235
|
+
__metadata("design:type", Function),
|
|
236
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String, Object]),
|
|
237
|
+
__metadata("design:returntype", Promise)
|
|
238
|
+
], AbandonedCartController.prototype, "setStatus", null);
|
|
239
|
+
__decorate([
|
|
240
|
+
(0, common_1.Get)('recover-cart'),
|
|
241
|
+
__param(0, (0, common_1.Req)()),
|
|
242
|
+
__param(1, (0, common_1.Query)('t')),
|
|
243
|
+
__metadata("design:type", Function),
|
|
244
|
+
__metadata("design:paramtypes", [Object, String]),
|
|
245
|
+
__metadata("design:returntype", Promise)
|
|
246
|
+
], AbandonedCartController.prototype, "recover", null);
|
|
247
|
+
exports.AbandonedCartController = AbandonedCartController = __decorate([
|
|
248
|
+
(0, common_1.Controller)('ees'),
|
|
249
|
+
__metadata("design:paramtypes", [abandoned_cart_service_1.AbandonedCartService])
|
|
250
|
+
], AbandonedCartController);
|
|
251
|
+
//# sourceMappingURL=abandoned-cart.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandoned-cart.controller.js","sourceRoot":"","sources":["../src/abandoned-cart.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAqF;AACrF,wCAAuE;AAEvE,qEAAgE;AAEhE;;;;;;;;;;;;;GAaG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAuB;IAChC,YAA6B,OAA6B;QAA7B,YAAO,GAAP,OAAO,CAAsB;IAAG,CAAC;IAIxD,AAAN,KAAK,CAAC,IAAI,CACC,GAAmB,EACX,OAAgB,EAChB,OAAgB,EACd,MAAe,EACb,WAAoB,EACvB,KAAc;;QAE9B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,IAAI,MAAM,EAAE,CAAC;YAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAAC,CAAC;QAC9D,IAAI,WAAW,EAAE,CAAC;YACd,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAAC,CAAC;QAC9E,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACR,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,GAAI,IAAI,CAAC,OAAe,CAAC,UAAU,CAAC,aAAa,CAAC;QAC5D,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACvC,IAAI,CAAC,KAAK,CACN;;;;mBAIG,MAAM;;kCAES,EAClB,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAC1B;YACD,IAAI,CAAC,KAAK,CAAC,4CAA4C,MAAM,EAAE,EAAE,MAAM,CAAC;SAC3E,CAAC,CAAC;QACH,OAAO;YACH,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,MAAM,CAAC,CAAA,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAG,CAAC,CAAC,0CAAE,CAAC,KAAI,CAAC,CAAC;YACpC,IAAI,EAAE,IAAI;SACb,CAAC;IACN,CAAC;IAIK,AAAN,KAAK,CAAC,OAAO,CAAQ,GAAmB,EAAiB,OAAgB;QACrE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,QAAS,CAAC,CAAC;QACtD,MAAM,IAAI,GAAI,IAAI,CAAC,OAAe,CAAC,UAAU,CAAC,aAAa,CAAC;QAC5D,MAAM,IAAI,GAAU,MAAM,IAAI,CAAC,KAAK,CAChC;;;;;;;;;;;oCAWwB,EACxB,CAAC,KAAK,CAAC,CACV,CAAC;QACF,MAAM,CAAC,GAAG,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAG,CAAC,CAAC,KAAI,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC;QAC1E,OAAO;YACH,UAAU,EAAE,IAAI;YAChB,KAAK;YACL,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;YACnC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC;YAC7C,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC;YAC7C,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YACzC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC;YAC7C,eAAe,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YAClE,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC;YAC/C,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC,mBAAmB,IAAI,CAAC,CAAC;YACvD,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC;SAC1D,CAAC;IACN,CAAC;IAIK,AAAN,KAAK,CAAC,SAAS,CAAQ,GAAmB,EAAS,GAAa,EAAiB,OAAgB;QAC7F,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7E,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,QAAS,CAAC,CAAC;QACtD,MAAM,IAAI,GAAI,IAAI,CAAC,OAAe,CAAC,UAAU,CAAC,aAAa,CAAC;QAC5D,MAAM,IAAI,GAAU,MAAM,IAAI,CAAC,KAAK,CAChC;;;;;yBAKa,EACb,CAAC,KAAK,CAAC,CACV,CAAC;QACF,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;QACzD,GAAG,CAAC,SAAS,CAAC,qBAAqB,EAC/B,yCAAyC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAC1F,MAAM,GAAG,GAAG,CAAC,CAAM,EAAE,EAAE;YACnB,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,IAAI,EAAC,WAAW,EAAC,WAAW,EAAC,YAAY,EAAC,UAAU,EAAC,YAAY,EAAC,WAAW;YAC7E,OAAO,EAAC,QAAQ,EAAC,aAAa,EAAC,aAAa,EAAC,WAAW,EAAC,WAAW,EAAC,aAAa,EAAC,aAAa,CAAC,CAAC;QAChH,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACjC,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACnB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QACzD,CAAC;QACD,GAAG,CAAC,GAAG,EAAE,CAAC;IACd,CAAC;IAIK,AAAN,KAAK,CAAC,MAAM,CAAQ,GAAmB,EAAe,KAAa;QAC/D,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAI,IAAI,CAAC,OAAe,CAAC,UAAU,CAAC,aAAa,CAAC;QAC5D,MAAM,IAAI,GAAU,MAAM,IAAI,CAAC,KAAK,CAChC,mDAAmD,EACnD,CAAC,EAAE,CAAC,CACP,CAAC;QACF,IAAI,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,CAAA;YAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,KAAK,GAAU,EAAE,CAAC;QACtB,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACzD,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC;IAIK,AAAN,KAAK,CAAC,iBAAiB,CAAQ,GAAmB,EAAe,KAAa;QAC1E,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,KAAK,EAAE,gCAAgC,EAAE,IAAI,EAAE,sDAAsD,EAAE,CAAC;QAC3H,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC7B,CAAC;IAIK,AAAN,KAAK,CAAC,SAAS,CACJ,GAAmB,EACb,KAAa,EAClB,IAAyB;QAEjC,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,KAAI,EAAE,CAAQ,CAAC;QACjD,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;QACvC,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,MAAa,CAAC,CAAC;QAC5D,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;IACtD,CAAC;IAED;;;;OAIG;IAEG,AAAN,KAAK,CAAC,OAAO,CAAQ,GAAY,EAAc,KAAc;QACzD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;IACnC,CAAC;CACJ,CAAA;AA5KY,0DAAuB;AAK1B;IAFL,IAAA,YAAG,EAAC,iBAAiB,CAAC;IACtB,IAAA,YAAK,EAAC,iBAAU,CAAC,YAAY,CAAC;IAE1B,WAAA,IAAA,UAAG,GAAE,CAAA;IACL,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IACb,WAAA,IAAA,cAAK,EAAC,QAAQ,CAAC,CAAA;IACf,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;IACjB,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;qCALH,qBAAc;;mDAwC7B;AAIK;IAFL,IAAA,YAAG,EAAC,yBAAyB,CAAC;IAC9B,IAAA,YAAK,EAAC,iBAAU,CAAC,YAAY,CAAC;IAChB,WAAA,IAAA,UAAG,GAAE,CAAA;IAAuB,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;;qCAA9B,qBAAc;;sDAmCvC;AAIK;IAFL,IAAA,YAAG,EAAC,4BAA4B,CAAC;IACjC,IAAA,YAAK,EAAC,iBAAU,CAAC,YAAY,CAAC;IACd,WAAA,IAAA,UAAG,GAAE,CAAA;IAAuB,WAAA,IAAA,YAAG,GAAE,CAAA;IAAiB,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;;qCAApD,qBAAc;;wDA2BzC;AAIK;IAFL,IAAA,YAAG,EAAC,qBAAqB,CAAC;IAC1B,IAAA,YAAK,EAAC,iBAAU,CAAC,YAAY,CAAC;IACjB,WAAA,IAAA,UAAG,GAAE,CAAA;IAAuB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;qCAA5B,qBAAc;;qDAYtC;AAIK;IAFL,IAAA,aAAI,EAAC,mCAAmC,CAAC;IACzC,IAAA,YAAK,EAAC,iBAAU,CAAC,cAAc,CAAC;IACR,WAAA,IAAA,UAAG,GAAE,CAAA;IAAuB,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;;qCAA5B,qBAAc;;gEAKjD;AAIK;IAFL,IAAA,aAAI,EAAC,4BAA4B,CAAC;IAClC,IAAA,YAAK,EAAC,iBAAU,CAAC,cAAc,CAAC;IAE5B,WAAA,IAAA,UAAG,GAAE,CAAA;IACL,WAAA,IAAA,cAAK,EAAC,IAAI,CAAC,CAAA;IACX,WAAA,IAAA,aAAI,GAAE,CAAA;;qCAFK,qBAAc;;wDAW7B;AAQK;IADL,IAAA,YAAG,EAAC,cAAc,CAAC;IACL,WAAA,IAAA,YAAG,GAAE,CAAA;IAAgB,WAAA,IAAA,cAAK,EAAC,GAAG,CAAC,CAAA;;;;sDAM7C;kCA3KQ,uBAAuB;IADnC,IAAA,mBAAU,EAAC,KAAK,CAAC;qCAEwB,6CAAoB;GADjD,uBAAuB,CA4KnC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type AbandonedCartStatus = 'abandoned' | 'recovered' | 'converted' | 'expired' | 'dismissed';
|
|
2
|
+
/**
|
|
3
|
+
* One row per abandoned cart, keyed on the visitor session that produced
|
|
4
|
+
* it. Rebuilt fresh from `cart_snapshot` events by the periodic scanner,
|
|
5
|
+
* so a session can be updated in-place until it either converts (order
|
|
6
|
+
* placed) or expires (recovery window elapses without any action).
|
|
7
|
+
*/
|
|
8
|
+
export declare class AbandonedCart {
|
|
9
|
+
id: number;
|
|
10
|
+
visitorId: string;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
/** Set when the visitor is signed in. Guest carts stay NULL and are
|
|
13
|
+
* matched to a customer only if they later sign in (via the same
|
|
14
|
+
* visitorId) or check out with a linkable email. */
|
|
15
|
+
customerId: number | null;
|
|
16
|
+
channelId: number;
|
|
17
|
+
currency: string;
|
|
18
|
+
/** Total value in the smallest currency unit (pence/cents). Storing
|
|
19
|
+
* minor units avoids float drift and matches Vendure's convention. */
|
|
20
|
+
totalMinor: number;
|
|
21
|
+
itemCount: number;
|
|
22
|
+
/** JSON array of cart items:
|
|
23
|
+
* [{ variantId, name, qty, unitPriceMinor, productId?, sku? }, …]
|
|
24
|
+
* Held as text because the recovery link needs to reconstruct the
|
|
25
|
+
* cart exactly — we don't want to join back to a live catalog that
|
|
26
|
+
* may have changed price by the time recovery is attempted. */
|
|
27
|
+
itemsJson: string;
|
|
28
|
+
/** Plain email if the storefront passed one (checkout step 1 usually
|
|
29
|
+
* captures this). NULL for cold browsers. */
|
|
30
|
+
email: string | null;
|
|
31
|
+
/** SHA-256 of the lowercased email — safe to keep even under
|
|
32
|
+
* aggressive privacy defaults, and used to link recurring sessions
|
|
33
|
+
* from the same buyer without exposing the raw address. */
|
|
34
|
+
emailHash: string | null;
|
|
35
|
+
firstSnapshotAt: Date;
|
|
36
|
+
lastSnapshotAt: Date;
|
|
37
|
+
/** Moment the scanner promoted the session from "active" to
|
|
38
|
+
* "abandoned" — i.e. no checkout_completed and no fresh
|
|
39
|
+
* cart_snapshot within the abandonment window. */
|
|
40
|
+
abandonedAt: Date;
|
|
41
|
+
recoveredAt: Date | null;
|
|
42
|
+
/** Signed opaque token that recovers the cart on the storefront.
|
|
43
|
+
* Regenerated by the admin/recover endpoint; time-bounded. */
|
|
44
|
+
recoveryToken: string | null;
|
|
45
|
+
recoveryTokenExpiresAt: Date | null;
|
|
46
|
+
status: AbandonedCartStatus;
|
|
47
|
+
recoveryOrderId: number | null;
|
|
48
|
+
lastKnownUrl: string | null;
|
|
49
|
+
lastKnownReferrer: string | null;
|
|
50
|
+
utmSource: string | null;
|
|
51
|
+
utmMedium: string | null;
|
|
52
|
+
utmCampaign: string | null;
|
|
53
|
+
countryCode: string | null;
|
|
54
|
+
/** True once we've fired the Slack / email notification for this
|
|
55
|
+
* abandonment. Prevents duplicate notifications when the scanner
|
|
56
|
+
* re-runs. */
|
|
57
|
+
notificationSent: boolean;
|
|
58
|
+
createdAt: Date;
|
|
59
|
+
updatedAt: Date;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=abandoned-cart.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandoned-cart.entity.d.ts","sourceRoot":"","sources":["../src/abandoned-cart.entity.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,mBAAmB,GACzB,WAAW,GACX,WAAW,GACX,WAAW,GACX,SAAS,GACT,WAAW,CAAC;AAElB;;;;;GAKG;AACH,qBAMa,aAAa;IAEtB,EAAE,EAAG,MAAM,CAAC;IAGZ,SAAS,EAAG,MAAM,CAAC;IAGnB,SAAS,EAAG,MAAM,CAAC;IAEnB;;yDAEqD;IAErD,UAAU,EAAG,MAAM,GAAG,IAAI,CAAC;IAG3B,SAAS,EAAG,MAAM,CAAC;IAGnB,QAAQ,EAAG,MAAM,CAAC;IAElB;2EACuE;IAEvE,UAAU,EAAG,MAAM,CAAC;IAGpB,SAAS,EAAG,MAAM,CAAC;IAEnB;;;;oEAIgE;IAEhE,SAAS,EAAG,MAAM,CAAC;IAEnB;kDAC8C;IAE9C,KAAK,EAAG,MAAM,GAAG,IAAI,CAAC;IAEtB;;gEAE4D;IAE5D,SAAS,EAAG,MAAM,GAAG,IAAI,CAAC;IAG1B,eAAe,EAAG,IAAI,CAAC;IAGvB,cAAc,EAAG,IAAI,CAAC;IAEtB;;uDAEmD;IAEnD,WAAW,EAAG,IAAI,CAAC;IAGnB,WAAW,EAAG,IAAI,GAAG,IAAI,CAAC;IAE1B;mEAC+D;IAE/D,aAAa,EAAG,MAAM,GAAG,IAAI,CAAC;IAG9B,sBAAsB,EAAG,IAAI,GAAG,IAAI,CAAC;IAGrC,MAAM,EAAG,mBAAmB,CAAC;IAG7B,eAAe,EAAG,MAAM,GAAG,IAAI,CAAC;IAGhC,YAAY,EAAG,MAAM,GAAG,IAAI,CAAC;IAG7B,iBAAiB,EAAG,MAAM,GAAG,IAAI,CAAC;IAGlC,SAAS,EAAG,MAAM,GAAG,IAAI,CAAC;IAG1B,SAAS,EAAG,MAAM,GAAG,IAAI,CAAC;IAG1B,WAAW,EAAG,MAAM,GAAG,IAAI,CAAC;IAG5B,WAAW,EAAG,MAAM,GAAG,IAAI,CAAC;IAE5B;;mBAEe;IAEf,gBAAgB,EAAG,OAAO,CAAC;IAG3B,SAAS,EAAG,IAAI,CAAC;IAGjB,SAAS,EAAG,IAAI,CAAC;CACpB"}
|