@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.
@@ -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
- /** Resolved flat allow-list of ISO 3166-1 alpha-2 country codes
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 endpoint serving the storefront-facing site config for a given
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
- * Returned shape is deliberately small + flat so the frontend can cache
36
- * it in module memory and re-fetch every 60s without much overhead.
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
- * Admin: list every channel with its current geo-block settings.
44
- * Used by the dedicated Vendure admin page so the admin can switch
45
- * between Elite / LicenseDock / any future channel from a single
46
- * screen.
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: save the geo-block settings for one channel. Body shape
51
- * mirrors what `listChannels` returns (minus the resolved preview).
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
- saveChannel(ctx: RequestContext, body: any, res: Response): Promise<Response<any, Record<string, any>> | undefined>;
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,EAAmB,cAAc,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAgB5C,UAAU,UAAU;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QACN,OAAO,EAAE,OAAO,CAAC;QACjB;;uDAE+C;QAC/C,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAClC;;;+DAGuD;QACvD,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B;+DACuD;QACvD,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B;;uCAE+B;QAC/B,cAAc,EAAE,MAAM,EAAE,CAAC;KAC5B,CAAC;IACF,WAAW,EAAE;QACT,iBAAiB,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,MAAM,CAAC;KACzB,CAAC;CACL;AAcD;;;;;;;;GAQG;AACH,qBACa,kBAAkB;IACf,OAAO,CAAC,UAAU;gBAAV,UAAU,EAAE,uBAAuB;IAGjD,SAAS,CAAQ,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAqEzD;;;;;OAKG;IAEG,YAAY,CAAQ,GAAG,EAAE,cAAc,EAAS,GAAG,EAAE,QAAQ;IA6CnE;;;OAGG;IAEG,WAAW,CAAQ,GAAG,EAAE,cAAc,EAAU,IAAI,EAAE,GAAG,EAAS,GAAG,EAAE,QAAQ;CA8BxF"}
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"}