@lynxflow/seo-engine 2.0.0 โ 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -40
- package/dist/built-in-locations.d.ts +5 -1
- package/dist/index.js +41 -13
- package/dist/index.mjs +41 -13
- package/dist/matrix-engine.d.ts +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# @lynxflow/seo-engine
|
|
2
2
|
|
|
3
|
-
High-Performance Programmatic SEO & Structured Data Engine for Modern Web Applications.
|
|
3
|
+
High-Performance Universal Programmatic SEO & Structured Data Engine for Modern Web Applications.
|
|
4
4
|
|
|
5
5
|
[](https://www.typescriptlang.org/)
|
|
6
6
|
[](LICENSE)
|
|
7
|
-
[](package
|
|
7
|
+
[](https://www.npmjs.com/package/@lynxflow/seo-engine)
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
`@lynxflow/seo-engine` is an enterprise developer SDK providing in-memory programmatic SEO matrix generation, Google-compliant Schema.org structured data, infinite geographic location synthesis, and real-time GeoIP Edge detection worldwide.
|
|
13
|
+
`@lynxflow/seo-engine` is an enterprise developer SDK providing in-memory programmatic SEO matrix generation, Google-compliant Schema.org structured data, infinite geographic location synthesis, strict market boundaries, and real-time GeoIP Edge detection worldwide.
|
|
14
14
|
|
|
15
15
|
* **10 Canonical Root Pillars & 50+ Specialized Sub-Matrices:** Scales across industries, regulatory frameworks, role KPIs, multi-format templates, integration ecosystems, and ROI tools.
|
|
16
|
+
* **Strict Geographic & Linguistic Scoping:** Easily lock your website to a single country (e.g. 100% US or 100% France) or expand globally across multiple languages and territories with `strictCountryBoundary`.
|
|
16
17
|
* **In-Memory Dynamic Execution:** Resolves millions of programmatic routes in RAM with zero database query overhead and zero MySQL/Postgres saturation.
|
|
17
18
|
* **Infinite Geographic Resolution (`createDynamicLocation`):** Dynamically synthesizes any municipality, county, state, or postal code worldwide (e.g. `austin`, `scottsdale`, `75015`, `90210`, `ec1a-1bb`, `shinjuku`) on the fly without 404 errors.
|
|
18
19
|
* **Edge GeoIP Location Detection (`resolveLocationFromHeaders`):** Reads Cloudflare (`cf-ipcity`, `cf-postal-code`), Vercel, AWS CloudFront, and Nginx edge headers to adapt pages to the visitor's real-time location.
|
|
@@ -34,33 +35,36 @@ bun add @lynxflow/seo-engine
|
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
37
|
-
##
|
|
38
|
+
## Market Scoping: Single Country vs. Global Multi-Country
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
### Option 1: 100% US-Only or Local Single-Country Website
|
|
41
|
+
Prevent crawl waste on out-of-scope foreign locations by enabling `strictCountryBoundary`:
|
|
40
42
|
|
|
43
|
+
```typescript
|
|
44
|
+
export const SEO_CONFIG = {
|
|
45
|
+
brandName: "LoneStar HVAC Pro",
|
|
46
|
+
languages: ["en"],
|
|
47
|
+
countries: ["united-states"],
|
|
48
|
+
strictCountryBoundary: true, // ๐ก๏ธ Rejects non-US locations
|
|
49
|
+
defaultCurrency: "USD",
|
|
50
|
+
defaultCurrencySymbol: "$",
|
|
51
|
+
};
|
|
41
52
|
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
โ ๐ฅ /vs/{competitor} โ Optional / Modular โ Architectural Comparison & Differences โ
|
|
52
|
-
โ ๐ /alternatives/{competitor} โ Optional / Modular โ Clean Canonical Migration Guides โ
|
|
53
|
-
โ ๐ฐ /pricing/{competitor} โ Optional / Modular โ Transparent Plan Breakdown & Verified Disclaimers โ
|
|
54
|
-
โ ๐ /solutions/{service}/{city} โ Local Geo Matrix โ Tiered Indexing (Crawl Budget) & Geodesic Mesh Links โ
|
|
55
|
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
53
|
+
|
|
54
|
+
### Option 2: Worldwide Multi-Country / Multi-Lingual SaaS
|
|
55
|
+
```typescript
|
|
56
|
+
export const SEO_CONFIG = {
|
|
57
|
+
brandName: "Apex Global Cloud",
|
|
58
|
+
languages: ["en", "de", "es", "fr", "ja", "pt-BR"],
|
|
59
|
+
countries: ["united-states", "united-kingdom", "germany", "france", "japan"],
|
|
60
|
+
strictCountryBoundary: false, // Allows worldwide expansion
|
|
61
|
+
};
|
|
56
62
|
```
|
|
57
63
|
|
|
58
64
|
---
|
|
59
65
|
|
|
60
66
|
## Quickstart & Contrasting Examples
|
|
61
67
|
|
|
62
|
-
> **Important Note:** All examples below are **non-limiting illustrations**. You can pass any arbitrary language code and any arbitrary city or postal code worldwide.
|
|
63
|
-
|
|
64
68
|
### 1. Initialize Engine & Dataset
|
|
65
69
|
|
|
66
70
|
```typescript
|
|
@@ -68,14 +72,6 @@ import { PseoMatrixEngine } from "@lynxflow/seo-engine";
|
|
|
68
72
|
|
|
69
73
|
export const matrixEngine = new PseoMatrixEngine();
|
|
70
74
|
|
|
71
|
-
// Non-limiting example configuration (Supports ANY country or locale)
|
|
72
|
-
export const SEO_CONFIG = {
|
|
73
|
-
brandName: "Apex Global",
|
|
74
|
-
languages: ["en", "de", "es", "fr", "ja", "pt-BR"], // Any ISO-639-1 / BCP-47 locale
|
|
75
|
-
countries: ["united-states", "united-kingdom", "germany", "japan"], // Or "international" / any country
|
|
76
|
-
cleanDirectRoutes: true,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
75
|
export const PSEO_DATASET = {
|
|
80
76
|
services: [
|
|
81
77
|
{
|
|
@@ -93,10 +89,6 @@ export const PSEO_DATASET = {
|
|
|
93
89
|
description: "Continuous enterprise backup and disaster recovery"
|
|
94
90
|
},
|
|
95
91
|
],
|
|
96
|
-
targets: [
|
|
97
|
-
{ slug: "enterprises", name: "Enterprise Organizations", type: "b2b", painPoints: ["Downtime Risk"], benefits: ["99.99% SLA"] },
|
|
98
|
-
{ slug: "healthcare", name: "Healthcare Providers", type: "industry", painPoints: ["HIPAA Compliance"], benefits: ["Audit-Ready Storage"] }
|
|
99
|
-
],
|
|
100
92
|
};
|
|
101
93
|
```
|
|
102
94
|
|
|
@@ -104,11 +96,10 @@ export const PSEO_DATASET = {
|
|
|
104
96
|
|
|
105
97
|
```typescript
|
|
106
98
|
// Case 1: Standard Pre-Indexed City in English
|
|
107
|
-
const pageStandard = matrixEngine.resolvePage(["commercial-hvac", "
|
|
99
|
+
const pageStandard = matrixEngine.resolvePage(["commercial-hvac", "new-york"], "https://example.com", PSEO_DATASET, SEO_CONFIG);
|
|
108
100
|
|
|
109
|
-
// Case 2: Contrasting Case โ Arbitrary Postal Code / Custom District
|
|
101
|
+
// Case 2: Contrasting Case โ Arbitrary Postal Code / Custom District
|
|
110
102
|
const pageCustom = matrixEngine.resolvePage(["commercial-hvac", "90210"], "https://example.com", PSEO_DATASET, SEO_CONFIG);
|
|
111
|
-
const pageJapanese = matrixEngine.resolvePage(["ja", "commercial-hvac", "shinjuku"], "https://example.com", PSEO_DATASET, SEO_CONFIG);
|
|
112
103
|
```
|
|
113
104
|
|
|
114
105
|
### 3. Edge GeoIP Resolution Example
|
|
@@ -118,7 +109,6 @@ import { resolveLocationFromHeaders, PseoMatrixEngine } from "@lynxflow/seo-engi
|
|
|
118
109
|
|
|
119
110
|
export function handleIncomingRequest(request: Request) {
|
|
120
111
|
const geo = resolveLocationFromHeaders(request.headers);
|
|
121
|
-
// Extracted dynamically from Cloudflare / Vercel / CloudFront headers
|
|
122
112
|
const userCity = geo.city || "new-york";
|
|
123
113
|
|
|
124
114
|
return matrixEngine.resolvePage(["commercial-hvac", userCity], "https://example.com", PSEO_DATASET, SEO_CONFIG);
|
|
@@ -129,11 +119,10 @@ export function handleIncomingRequest(request: Request) {
|
|
|
129
119
|
|
|
130
120
|
## TypeScript API Reference
|
|
131
121
|
|
|
132
|
-
* **`PseoMatrixEngine`**: Core programmatic matrix compiler
|
|
133
|
-
* **`createDynamicLocation(slugOrInput, fallbackCountry)`**: Dynamic synthesis of any city, postal code or district worldwide
|
|
122
|
+
* **`PseoMatrixEngine`**: Core programmatic matrix compiler with geographic boundaries and crawl budget protection.
|
|
123
|
+
* **`createDynamicLocation(slugOrInput, fallbackCountry, options)`**: Dynamic synthesis of any city, postal code or district worldwide.
|
|
134
124
|
* **`resolveLocationFromHeaders(headers)`**: Edge header GeoIP extractor for Cloudflare, Vercel, CloudFront, and Nginx.
|
|
135
125
|
* **`cleanSeoSlug(text, options)`**: Multilingual slug normalizer with stop-word removal for 10+ languages.
|
|
136
|
-
* **`validateSeoSlug(slug)`**: Strict slug validator.
|
|
137
126
|
* **`ExtendedSchemaGraphBuilder`**: 50+ Google Rich Result Schema.org JSON-LD generator.
|
|
138
127
|
* **`LegalDisclaimerEngine`**: Verified compliance notice manager with staleness guards (>90 days).
|
|
139
128
|
* **`getSeoAgentPrompt(context)`**: Built-in LLM operational prompt for AI coding agents.
|
|
@@ -15,7 +15,11 @@ export declare function resolveBuiltInLocations(territories?: string[] | string)
|
|
|
15
15
|
* Allows resolving ANY unlisted city, commune, district, or postal code dynamically on demand
|
|
16
16
|
* without returning 404 or requiring hardcoded databases.
|
|
17
17
|
*/
|
|
18
|
-
export declare function createDynamicLocation(slugOrInput: string, fallbackCountry?: string
|
|
18
|
+
export declare function createDynamicLocation(slugOrInput: string, fallbackCountry?: string, options?: {
|
|
19
|
+
currency?: string;
|
|
20
|
+
currencySymbol?: string;
|
|
21
|
+
region?: string;
|
|
22
|
+
}): PseoLocation;
|
|
19
23
|
/**
|
|
20
24
|
* ๐ GeoIP Edge Headers Resolver (Dynamic User Geolocation)
|
|
21
25
|
* Extracts the user's real-time city and country from Cloudflare / Vercel / Nginx Edge headers.
|
package/dist/index.js
CHANGED
|
@@ -3524,26 +3524,43 @@ function resolveBuiltInLocations(territories) {
|
|
|
3524
3524
|
}
|
|
3525
3525
|
}
|
|
3526
3526
|
}
|
|
3527
|
-
return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.
|
|
3527
|
+
return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.us];
|
|
3528
3528
|
}
|
|
3529
|
-
function createDynamicLocation(slugOrInput, fallbackCountry = "
|
|
3529
|
+
function createDynamicLocation(slugOrInput, fallbackCountry = "United States", options) {
|
|
3530
3530
|
const cleanInput = slugOrInput.trim().toLowerCase();
|
|
3531
3531
|
const slug = cleanInput.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3532
3532
|
const formattedName = slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3533
|
-
const
|
|
3534
|
-
const
|
|
3535
|
-
|
|
3536
|
-
|
|
3533
|
+
const isUsZip = /^\d{5}(-\d{4})?$/.test(cleanInput);
|
|
3534
|
+
const isFrenchPostal = /^\d{5}$/.test(cleanInput) && (fallbackCountry.toLowerCase().includes("fr") || fallbackCountry.toLowerCase().includes("france"));
|
|
3535
|
+
let displayName = formattedName;
|
|
3536
|
+
let regionName = options?.region || "Metropolitan Area";
|
|
3537
|
+
if (isUsZip) {
|
|
3538
|
+
displayName = `Area ${cleanInput}`;
|
|
3539
|
+
regionName = `ZIP Code ${cleanInput}`;
|
|
3540
|
+
} else if (isFrenchPostal) {
|
|
3541
|
+
displayName = `Secteur ${cleanInput}`;
|
|
3542
|
+
regionName = `Dรฉpartement ${cleanInput.slice(0, 2)}`;
|
|
3543
|
+
}
|
|
3544
|
+
const countryLower = fallbackCountry.toLowerCase();
|
|
3545
|
+
const isUS = countryLower.includes("us") || countryLower.includes("state") || countryLower.includes("america");
|
|
3546
|
+
const isUK = countryLower.includes("uk") || countryLower.includes("kingdom") || countryLower.includes("britain");
|
|
3547
|
+
const isJapan = countryLower.includes("japan") || countryLower.includes("jp") || countryLower.includes("tokyo");
|
|
3548
|
+
const isCanada = countryLower.includes("canada") || countryLower.includes("ca");
|
|
3549
|
+
const isAustralia = countryLower.includes("australia") || countryLower.includes("au");
|
|
3550
|
+
const isBrazil = countryLower.includes("brazil") || countryLower.includes("br") || countryLower.includes("brasil");
|
|
3551
|
+
const isSwitzerland = countryLower.includes("switzerland") || countryLower.includes("swiss") || countryLower.includes("ch");
|
|
3552
|
+
const currency = options?.currency || (isUS ? "USD" : isUK ? "GBP" : isJapan ? "JPY" : isCanada ? "CAD" : isAustralia ? "AUD" : isBrazil ? "BRL" : isSwitzerland ? "CHF" : "EUR");
|
|
3553
|
+
const currencySymbol = options?.currencySymbol || (isUS ? "$" : isUK ? "ยฃ" : isJapan ? "ยฅ" : isCanada ? "CAD $" : isAustralia ? "AUD $" : isBrazil ? "R$" : isSwitzerland ? "CHF" : "โฌ");
|
|
3537
3554
|
return {
|
|
3538
3555
|
slug,
|
|
3539
3556
|
name: displayName,
|
|
3540
|
-
region:
|
|
3557
|
+
region: regionName,
|
|
3541
3558
|
country: fallbackCountry,
|
|
3542
|
-
currency
|
|
3543
|
-
currencySymbol
|
|
3544
|
-
population:
|
|
3545
|
-
latitude:
|
|
3546
|
-
longitude:
|
|
3559
|
+
currency,
|
|
3560
|
+
currencySymbol,
|
|
3561
|
+
population: 50000,
|
|
3562
|
+
latitude: 40.7128,
|
|
3563
|
+
longitude: -74.006,
|
|
3547
3564
|
neighborSlugs: []
|
|
3548
3565
|
};
|
|
3549
3566
|
}
|
|
@@ -4205,7 +4222,18 @@ class PseoMatrixEngine {
|
|
|
4205
4222
|
const locationSlug = segments[segments.length - 1];
|
|
4206
4223
|
const matchedService = data.services.find((s) => cleanSeoSlug(s.slug, { language: options.language }) === serviceSlug || s.slug === serviceSlug);
|
|
4207
4224
|
if (matchedService) {
|
|
4208
|
-
const
|
|
4225
|
+
const countryList = options.allowedCountries || options.countries;
|
|
4226
|
+
const fallbackCountry = Array.isArray(countryList) ? countryList[0] : typeof countryList === "string" && countryList !== "international" ? countryList : "United States";
|
|
4227
|
+
const dynamicLoc = createDynamicLocation(locationSlug, fallbackCountry, {
|
|
4228
|
+
currency: options.defaultCurrency,
|
|
4229
|
+
currencySymbol: options.defaultCurrencySymbol
|
|
4230
|
+
});
|
|
4231
|
+
if (options.strictCountryBoundary && countryList) {
|
|
4232
|
+
const allowed = (Array.isArray(countryList) ? countryList : [countryList]).map((c) => c.toLowerCase());
|
|
4233
|
+
if (!allowed.includes("international") && !allowed.some((c) => dynamicLoc.country.toLowerCase().includes(c))) {
|
|
4234
|
+
return;
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4209
4237
|
const dynamicPages = this.generateLocalGeoMatrix(domain, [matchedService], [dynamicLoc], options);
|
|
4210
4238
|
return dynamicPages.find((p) => p.urlPath === path) || dynamicPages[0];
|
|
4211
4239
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -3524,26 +3524,43 @@ function resolveBuiltInLocations(territories) {
|
|
|
3524
3524
|
}
|
|
3525
3525
|
}
|
|
3526
3526
|
}
|
|
3527
|
-
return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.
|
|
3527
|
+
return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.us];
|
|
3528
3528
|
}
|
|
3529
|
-
function createDynamicLocation(slugOrInput, fallbackCountry = "
|
|
3529
|
+
function createDynamicLocation(slugOrInput, fallbackCountry = "United States", options) {
|
|
3530
3530
|
const cleanInput = slugOrInput.trim().toLowerCase();
|
|
3531
3531
|
const slug = cleanInput.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3532
3532
|
const formattedName = slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3533
|
-
const
|
|
3534
|
-
const
|
|
3535
|
-
|
|
3536
|
-
|
|
3533
|
+
const isUsZip = /^\d{5}(-\d{4})?$/.test(cleanInput);
|
|
3534
|
+
const isFrenchPostal = /^\d{5}$/.test(cleanInput) && (fallbackCountry.toLowerCase().includes("fr") || fallbackCountry.toLowerCase().includes("france"));
|
|
3535
|
+
let displayName = formattedName;
|
|
3536
|
+
let regionName = options?.region || "Metropolitan Area";
|
|
3537
|
+
if (isUsZip) {
|
|
3538
|
+
displayName = `Area ${cleanInput}`;
|
|
3539
|
+
regionName = `ZIP Code ${cleanInput}`;
|
|
3540
|
+
} else if (isFrenchPostal) {
|
|
3541
|
+
displayName = `Secteur ${cleanInput}`;
|
|
3542
|
+
regionName = `Dรฉpartement ${cleanInput.slice(0, 2)}`;
|
|
3543
|
+
}
|
|
3544
|
+
const countryLower = fallbackCountry.toLowerCase();
|
|
3545
|
+
const isUS = countryLower.includes("us") || countryLower.includes("state") || countryLower.includes("america");
|
|
3546
|
+
const isUK = countryLower.includes("uk") || countryLower.includes("kingdom") || countryLower.includes("britain");
|
|
3547
|
+
const isJapan = countryLower.includes("japan") || countryLower.includes("jp") || countryLower.includes("tokyo");
|
|
3548
|
+
const isCanada = countryLower.includes("canada") || countryLower.includes("ca");
|
|
3549
|
+
const isAustralia = countryLower.includes("australia") || countryLower.includes("au");
|
|
3550
|
+
const isBrazil = countryLower.includes("brazil") || countryLower.includes("br") || countryLower.includes("brasil");
|
|
3551
|
+
const isSwitzerland = countryLower.includes("switzerland") || countryLower.includes("swiss") || countryLower.includes("ch");
|
|
3552
|
+
const currency = options?.currency || (isUS ? "USD" : isUK ? "GBP" : isJapan ? "JPY" : isCanada ? "CAD" : isAustralia ? "AUD" : isBrazil ? "BRL" : isSwitzerland ? "CHF" : "EUR");
|
|
3553
|
+
const currencySymbol = options?.currencySymbol || (isUS ? "$" : isUK ? "ยฃ" : isJapan ? "ยฅ" : isCanada ? "CAD $" : isAustralia ? "AUD $" : isBrazil ? "R$" : isSwitzerland ? "CHF" : "โฌ");
|
|
3537
3554
|
return {
|
|
3538
3555
|
slug,
|
|
3539
3556
|
name: displayName,
|
|
3540
|
-
region:
|
|
3557
|
+
region: regionName,
|
|
3541
3558
|
country: fallbackCountry,
|
|
3542
|
-
currency
|
|
3543
|
-
currencySymbol
|
|
3544
|
-
population:
|
|
3545
|
-
latitude:
|
|
3546
|
-
longitude:
|
|
3559
|
+
currency,
|
|
3560
|
+
currencySymbol,
|
|
3561
|
+
population: 50000,
|
|
3562
|
+
latitude: 40.7128,
|
|
3563
|
+
longitude: -74.006,
|
|
3547
3564
|
neighborSlugs: []
|
|
3548
3565
|
};
|
|
3549
3566
|
}
|
|
@@ -4205,7 +4222,18 @@ class PseoMatrixEngine {
|
|
|
4205
4222
|
const locationSlug = segments[segments.length - 1];
|
|
4206
4223
|
const matchedService = data.services.find((s) => cleanSeoSlug(s.slug, { language: options.language }) === serviceSlug || s.slug === serviceSlug);
|
|
4207
4224
|
if (matchedService) {
|
|
4208
|
-
const
|
|
4225
|
+
const countryList = options.allowedCountries || options.countries;
|
|
4226
|
+
const fallbackCountry = Array.isArray(countryList) ? countryList[0] : typeof countryList === "string" && countryList !== "international" ? countryList : "United States";
|
|
4227
|
+
const dynamicLoc = createDynamicLocation(locationSlug, fallbackCountry, {
|
|
4228
|
+
currency: options.defaultCurrency,
|
|
4229
|
+
currencySymbol: options.defaultCurrencySymbol
|
|
4230
|
+
});
|
|
4231
|
+
if (options.strictCountryBoundary && countryList) {
|
|
4232
|
+
const allowed = (Array.isArray(countryList) ? countryList : [countryList]).map((c) => c.toLowerCase());
|
|
4233
|
+
if (!allowed.includes("international") && !allowed.some((c) => dynamicLoc.country.toLowerCase().includes(c))) {
|
|
4234
|
+
return;
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4209
4237
|
const dynamicPages = this.generateLocalGeoMatrix(domain, [matchedService], [dynamicLoc], options);
|
|
4210
4238
|
return dynamicPages.find((p) => p.urlPath === path) || dynamicPages[0];
|
|
4211
4239
|
}
|
package/dist/matrix-engine.d.ts
CHANGED
|
@@ -131,7 +131,10 @@ export interface MatrixOptions {
|
|
|
131
131
|
brandName: string;
|
|
132
132
|
language?: string;
|
|
133
133
|
languages?: string[];
|
|
134
|
+
allowedLanguages?: string[] | string;
|
|
134
135
|
countries?: string[] | string;
|
|
136
|
+
allowedCountries?: string[] | string;
|
|
137
|
+
strictCountryBoundary?: boolean;
|
|
135
138
|
territories?: string[] | string;
|
|
136
139
|
cleanDirectRoutes?: boolean;
|
|
137
140
|
enableFreeTools?: boolean;
|