@huloglobal/vendure-plugin-geo-block 0.1.0 → 0.2.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/dist/geo-block-event.entity.d.ts +22 -0
- package/dist/geo-block-event.entity.d.ts.map +1 -0
- package/dist/geo-block-event.entity.js +68 -0
- package/dist/geo-block-event.entity.js.map +1 -0
- package/dist/geo-block.controller.d.ts +42 -25
- package/dist/geo-block.controller.d.ts.map +1 -1
- package/dist/geo-block.controller.js +368 -97
- package/dist/geo-block.controller.js.map +1 -1
- package/dist/geo-regions.d.ts +38 -13
- package/dist/geo-regions.d.ts.map +1 -1
- package/dist/geo-regions.js +212 -15
- package/dist/geo-regions.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +22 -23
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +56 -38
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
- package/ui/components/geo-block.component.ts +471 -255
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DeepPartial, VendureEntity } from '@vendure/core';
|
|
2
|
+
/**
|
|
3
|
+
* One row per block decision — written every time the
|
|
4
|
+
* `/geo-block/check` (or the storefront's call to `/site-config` followed
|
|
5
|
+
* by a server-side enforcement) decides to refuse a visitor.
|
|
6
|
+
*
|
|
7
|
+
* Cheap to keep around because the admin's stats endpoint aggregates on
|
|
8
|
+
* top of it; older rows can be pruned with `GeoBlockController.gc()`.
|
|
9
|
+
*/
|
|
10
|
+
export declare class GeoBlockEvent extends VendureEntity {
|
|
11
|
+
constructor(input?: DeepPartial<GeoBlockEvent>);
|
|
12
|
+
channelId: number;
|
|
13
|
+
country: string;
|
|
14
|
+
region: string;
|
|
15
|
+
ip: string;
|
|
16
|
+
userAgent: string;
|
|
17
|
+
url: string;
|
|
18
|
+
decision: 'block' | 'soft-block' | 'allow';
|
|
19
|
+
/** Which rule rejected (or allowed) the request. */
|
|
20
|
+
reason: 'denylist' | 'country-not-allowed' | 'uk-region-not-allowed' | 'ip-allowlist' | 'maintenance' | 'ok' | string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=geo-block-event.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo-block-event.entity.d.ts","sourceRoot":"","sources":["../src/geo-block-event.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG3D;;;;;;;GAOG;AACH,qBACa,aAAc,SAAQ,aAAa;gBAChC,KAAK,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC;IAM9C,SAAS,EAAG,MAAM,CAAC;IAInB,OAAO,EAAG,MAAM,CAAC;IAGjB,MAAM,EAAG,MAAM,CAAC;IAGhB,EAAE,EAAG,MAAM,CAAC;IAGZ,SAAS,EAAG,MAAM,CAAC;IAGnB,GAAG,EAAG,MAAM,CAAC;IAIb,QAAQ,EAAG,OAAO,GAAG,YAAY,GAAG,OAAO,CAAC;IAE5C,oDAAoD;IAEpD,MAAM,EAAG,UAAU,GAAG,qBAAqB,GAAG,uBAAuB,GAAG,cAAc,GAAG,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;CAC1H"}
|
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GeoBlockEvent = void 0;
|
|
13
|
+
const core_1 = require("@vendure/core");
|
|
14
|
+
const typeorm_1 = require("typeorm");
|
|
15
|
+
/**
|
|
16
|
+
* One row per block decision — written every time the
|
|
17
|
+
* `/geo-block/check` (or the storefront's call to `/site-config` followed
|
|
18
|
+
* by a server-side enforcement) decides to refuse a visitor.
|
|
19
|
+
*
|
|
20
|
+
* Cheap to keep around because the admin's stats endpoint aggregates on
|
|
21
|
+
* top of it; older rows can be pruned with `GeoBlockController.gc()`.
|
|
22
|
+
*/
|
|
23
|
+
let GeoBlockEvent = class GeoBlockEvent extends core_1.VendureEntity {
|
|
24
|
+
constructor(input) {
|
|
25
|
+
super(input);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.GeoBlockEvent = GeoBlockEvent;
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, typeorm_1.Index)(),
|
|
31
|
+
(0, typeorm_1.Column)({ type: 'int', default: 1 }),
|
|
32
|
+
__metadata("design:type", Number)
|
|
33
|
+
], GeoBlockEvent.prototype, "channelId", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, typeorm_1.Index)(),
|
|
36
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 8, nullable: true }),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], GeoBlockEvent.prototype, "country", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 8, nullable: true }),
|
|
41
|
+
__metadata("design:type", String)
|
|
42
|
+
], GeoBlockEvent.prototype, "region", void 0);
|
|
43
|
+
__decorate([
|
|
44
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 64, nullable: true }),
|
|
45
|
+
__metadata("design:type", String)
|
|
46
|
+
], GeoBlockEvent.prototype, "ip", void 0);
|
|
47
|
+
__decorate([
|
|
48
|
+
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
|
49
|
+
__metadata("design:type", String)
|
|
50
|
+
], GeoBlockEvent.prototype, "userAgent", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 2048, nullable: true }),
|
|
53
|
+
__metadata("design:type", String)
|
|
54
|
+
], GeoBlockEvent.prototype, "url", void 0);
|
|
55
|
+
__decorate([
|
|
56
|
+
(0, typeorm_1.Index)(),
|
|
57
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 32 }),
|
|
58
|
+
__metadata("design:type", String)
|
|
59
|
+
], GeoBlockEvent.prototype, "decision", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 64 }),
|
|
62
|
+
__metadata("design:type", String)
|
|
63
|
+
], GeoBlockEvent.prototype, "reason", void 0);
|
|
64
|
+
exports.GeoBlockEvent = GeoBlockEvent = __decorate([
|
|
65
|
+
(0, typeorm_1.Entity)(),
|
|
66
|
+
__metadata("design:paramtypes", [Object])
|
|
67
|
+
], GeoBlockEvent);
|
|
68
|
+
//# sourceMappingURL=geo-block-event.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo-block-event.entity.js","sourceRoot":"","sources":["../src/geo-block-event.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,wCAA2D;AAC3D,qCAAgD;AAEhD;;;;;;;GAOG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,oBAAa;IAC5C,YAAY,KAAkC;QAC1C,KAAK,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;CA6BJ,CAAA;AAhCY,sCAAa;AAOtB;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;gDACjB;AAInB;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACtC;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;6CACvC;AAGhB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;yCAC5C;AAGZ;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;gDACtB;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;0CAC7C;AAIb;IAFC,IAAA,eAAK,GAAE;IACP,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;+CACI;AAI5C;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;6CAC+E;wBA/B9G,aAAa;IADzB,IAAA,gBAAM,GAAE;;GACI,aAAa,CAgCzB"}
|
|
@@ -4,22 +4,14 @@ interface SiteConfig {
|
|
|
4
4
|
channelToken: string;
|
|
5
5
|
geoBlock: {
|
|
6
6
|
enabled: boolean;
|
|
7
|
-
|
|
8
|
-
* the storefront should let through, or `null` meaning "no
|
|
9
|
-
* country restriction" (WORLDWIDE preset). */
|
|
7
|
+
mode: 'block' | 'soft';
|
|
10
8
|
allowedCountries: string[] | null;
|
|
11
|
-
/** Countries the admin always blocks regardless of region. The
|
|
12
|
-
* resolved `allowedCountries` already has these subtracted —
|
|
13
|
-
* this field is exposed for diagnostics + so the storefront can
|
|
14
|
-
* enforce it even when allowedCountries is `null`. */
|
|
15
9
|
blockedCountries: string[];
|
|
16
|
-
/** UK subdivisions that must additionally match when the visitor
|
|
17
|
-
* resolves to GB. Empty = "any UK region allowed". */
|
|
18
10
|
allowedGbRegions: string[];
|
|
19
|
-
/** The raw region presets the admin selected — exposed for
|
|
20
|
-
* diagnostics (and so the frontend can display the admin's
|
|
21
|
-
* intent in any debug UI). */
|
|
22
11
|
allowedRegions: string[];
|
|
12
|
+
blockMessage: string;
|
|
13
|
+
blockRedirectUrl: string | null;
|
|
14
|
+
blockLogoUrl: string | null;
|
|
23
15
|
};
|
|
24
16
|
companyData: {
|
|
25
17
|
showCompanyNumber: boolean;
|
|
@@ -27,30 +19,55 @@ interface SiteConfig {
|
|
|
27
19
|
};
|
|
28
20
|
}
|
|
29
21
|
/**
|
|
30
|
-
* Public
|
|
31
|
-
* channel. The storefront calls GET /ees/site-config and identifies the
|
|
32
|
-
* channel via the standard `vendure-token` header (the same one shop-api
|
|
33
|
-
* uses), or via ?token=<channelToken> as a fallback for static fetchers.
|
|
22
|
+
* Public + admin endpoints for the storefront geo-block.
|
|
34
23
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
24
|
+
* Public:
|
|
25
|
+
* GET /geo-block/site-config — channel-aware rules the storefront caches
|
|
26
|
+
* GET /geo-block/check — per-request decision (with logging)
|
|
27
|
+
* GET /geo-block/presets — preset catalogue for the storefront banner
|
|
28
|
+
*
|
|
29
|
+
* Admin:
|
|
30
|
+
* GET /geo-block/admin/channels — all channels + their rules
|
|
31
|
+
* POST /geo-block/admin/save — save one channel's rules
|
|
32
|
+
* GET /geo-block/admin/stats — block totals + top blocked countries
|
|
33
|
+
* POST /geo-block/admin/simulate — "what would happen if a visitor from X visited?"
|
|
34
|
+
* POST /geo-block/admin/gc — prune old GeoBlockEvent rows
|
|
37
35
|
*/
|
|
38
36
|
export declare class GeoBlockController {
|
|
39
37
|
private connection;
|
|
40
38
|
constructor(connection: TransactionalConnection);
|
|
41
39
|
getConfig(req: Request): Promise<SiteConfig>;
|
|
42
40
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
41
|
+
* Per-request decision endpoint. The storefront calls this on entry
|
|
42
|
+
* (or middleware can call it) with optional `?country=` overrides.
|
|
43
|
+
* Logs the decision so the admin stats panel shows top blocked
|
|
44
|
+
* countries.
|
|
45
|
+
*
|
|
46
|
+
* Returns 200 with `{ allowed: boolean, reason, mode }` regardless —
|
|
47
|
+
* the storefront decides whether to redirect or render a banner.
|
|
47
48
|
*/
|
|
49
|
+
check(req: Request, res: Response): Promise<Response<any, Record<string, any>>>;
|
|
50
|
+
/** Catalogue of available region presets — fed to the admin picker
|
|
51
|
+
* and any storefront that wants to show "we serve <X>". */
|
|
52
|
+
presets(res: Response): Response<any, Record<string, any>>;
|
|
48
53
|
listChannels(ctx: RequestContext, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
54
|
+
saveChannel(ctx: RequestContext, body: any, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
49
55
|
/**
|
|
50
|
-
* Admin:
|
|
51
|
-
*
|
|
56
|
+
* Admin: top blocked countries + daily series + totals over the last
|
|
57
|
+
* N days (default 30). Fed straight into the admin Stats panel.
|
|
52
58
|
*/
|
|
53
|
-
|
|
59
|
+
stats(ctx: RequestContext, req: Request, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
60
|
+
/**
|
|
61
|
+
* Admin: dry-run check — "what would happen if a visitor from US
|
|
62
|
+
* with no UK region came in?". Lets the admin sanity-check their
|
|
63
|
+
* rules without standing up a proxy.
|
|
64
|
+
*/
|
|
65
|
+
simulate(ctx: RequestContext, body: any, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
66
|
+
gc(ctx: RequestContext, body: any, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
|
|
67
|
+
private loadChannelRow;
|
|
68
|
+
private buildConfig;
|
|
69
|
+
private logEvent;
|
|
70
|
+
private defaultMessage;
|
|
54
71
|
}
|
|
55
72
|
export {};
|
|
56
73
|
//# sourceMappingURL=geo-block.controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geo-block.controller.d.ts","sourceRoot":"","sources":["../src/geo-block.controller.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"geo-block.controller.d.ts","sourceRoot":"","sources":["../src/geo-block.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,cAAc,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA0B5C,UAAU,UAAU;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAClC,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,CAAC;IACF,WAAW,EAAE;QACT,iBAAiB,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,MAAM,CAAC;KACzB,CAAC;CACL;AA4BD;;;;;;;;;;;;;;GAcG;AACH,qBACa,kBAAkB;IACf,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,uBAAuB;IAGjD,SAAS,CAAQ,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAazD;;;;;;;;OAQG;IAEG,KAAK,CAAQ,GAAG,EAAE,OAAO,EAAS,GAAG,EAAE,QAAQ;IAyErD;+DAC2D;IAE3D,OAAO,CAAQ,GAAG,EAAE,QAAQ;IAKtB,YAAY,CAAQ,GAAG,EAAE,cAAc,EAAS,GAAG,EAAE,QAAQ;IA+C7D,WAAW,CAAQ,GAAG,EAAE,cAAc,EAAU,IAAI,EAAE,GAAG,EAAS,GAAG,EAAE,QAAQ;IA+CrF;;;OAGG;IAEG,KAAK,CAAQ,GAAG,EAAE,cAAc,EAAS,GAAG,EAAE,OAAO,EAAS,GAAG,EAAE,QAAQ;IA+CjF;;;;OAIG;IAEG,QAAQ,CAAQ,GAAG,EAAE,cAAc,EAAU,IAAI,EAAE,GAAG,EAAS,GAAG,EAAE,QAAQ;IAyB5E,EAAE,CAAQ,GAAG,EAAE,cAAc,EAAU,IAAI,EAAE,GAAG,EAAS,GAAG,EAAE,QAAQ;YAY9D,cAAc;IAqB5B,OAAO,CAAC,WAAW;YA6BL,QAAQ;IA4BtB,OAAO,CAAC,cAAc;CAczB"}
|