create-nextblock 0.12.13 → 0.12.15
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/package.json +1 -1
- package/templates/nextblock-template/app/(auth-pages)/sign-in/page.tsx +0 -13
- package/templates/nextblock-template/app/(auth-pages)/sign-up/SignUpForm.tsx +0 -14
- package/templates/nextblock-template/app/[slug]/page.tsx +12 -4
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +209 -101
- package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +2 -3
- package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +1 -0
- package/templates/nextblock-template/app/cms/interactions/InteractionsModerationClient.tsx +1 -1
- package/templates/nextblock-template/app/cms/interactions/page.tsx +1 -1
- package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +38 -35
- package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +14 -11
- package/templates/nextblock-template/app/cms/products/ProductFormClientShell.tsx +62 -14
- package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +2 -2
- package/templates/nextblock-template/app/cms/revisions/RevisionHistoryButton.tsx +2 -2
- package/templates/nextblock-template/app/cms/revisions/actions.ts +5 -5
- package/templates/nextblock-template/app/cms/settings/languages/actions.ts +53 -1
- package/templates/nextblock-template/app/cms/settings/languages/components/LanguageDetectionPanel.tsx +188 -0
- package/templates/nextblock-template/app/cms/settings/languages/page.tsx +12 -1
- package/templates/nextblock-template/app/cms/users/actions.ts +0 -3
- package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +0 -2
- package/templates/nextblock-template/app/cms/users/page.tsx +0 -2
- package/templates/nextblock-template/app/layout.tsx +42 -1
- package/templates/nextblock-template/app/product/[slug]/page.tsx +12 -4
- package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +1 -1
- package/templates/nextblock-template/app/profile/account-data.ts +1 -1
- package/templates/nextblock-template/app/profile/account-types.ts +0 -1
- package/templates/nextblock-template/app/profile/page.tsx +0 -1
- package/templates/nextblock-template/app/providers.tsx +2 -0
- package/templates/nextblock-template/components/PostCommentsSection.tsx +2 -2
- package/templates/nextblock-template/components/ProductReviewsSection.tsx +2 -2
- package/templates/nextblock-template/components/header-auth.tsx +1 -1
- package/templates/nextblock-template/context/LanguageContext.tsx +22 -7
- package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +46 -43
- package/templates/nextblock-template/lib/custom-block-relation-registry.ts +3 -3
- package/templates/nextblock-template/lib/i18n/country-languages.ts +247 -0
- package/templates/nextblock-template/lib/i18n/detection.test.ts +197 -0
- package/templates/nextblock-template/lib/i18n/detection.ts +192 -0
- package/templates/nextblock-template/lib/setup/migrations-bundle.ts +72 -37
- package/templates/nextblock-template/package.json +1 -1
- package/templates/nextblock-template/proxy.ts +141 -8
- package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
- package/templates/nextblock-template/components/GitHubLoginButton.tsx +0 -36
|
@@ -95,7 +95,7 @@ NextBlock CMS integrates with a specific, opinionated set of external services w
|
|
|
95
95
|
The system delivers six top-level capability families, each surfaced through dedicated route groups in the Next.js App Router:
|
|
96
96
|
|
|
97
97
|
1. **Public Content Delivery** — Routes `app/[slug]`, `app/article/[slug]`, shared `app/layout.tsx`, `robots.txt`, and `sitemap.xml` serve marketing pages, articles, and product pages.
|
|
98
|
-
2. **Authentication & Account Management** — The `app/(auth-pages)/*` group and `app/auth/callback/route.ts` implement Supabase Auth session exchange
|
|
98
|
+
2. **Authentication & Account Management** — The `app/(auth-pages)/*` group and `app/auth/callback/route.ts` implement Supabase Auth email/password session exchange and profile completion flows.
|
|
99
99
|
3. **CMS Administration** — The `app/cms/*` route tree provides block editing, media management, product catalog management, order administration, shipping configuration, tax settings, and user administration, gated by role.
|
|
100
100
|
4. **Commerce Surface** — Routes `app/product/*`, `app/cart`, and `app/checkout` implement the customer-facing storefront; `app/api/checkout/route.ts` handles server-side checkout orchestration.
|
|
101
101
|
5. **Operational Endpoints** — Routes `app/api/webhooks/*` (Stripe/Freemius) and `app/api/cron/*` (sandbox reset, currency sync) provide the machine-to-machine surface; `app/api/upload` and `app/api/process-image` handle media ingestion and optimization.
|
|
@@ -269,7 +269,7 @@ The following architectural invariants are enforced at workspace level and must
|
|
|
269
269
|
|
|
270
270
|
**Editor Capabilities** — The `@nextblock-cms/editor` library (version `0.2.24`) exports `Editor`, `NotionEditor`, `EditorToolbar`, `EditorBubbleMenu`, `EditorFloatingMenu`, `EnhancedFloatingMenu`, `SlashCommandList`, `DragHandle`, `HtmlContent`, and `editorExtensions`. Feature set includes Tiptap StarterKit rich text, syntax-highlighted code blocks, tables, task lists, slash commands, drag handles, image handling, character counting, typography, mathematics, emoji, mentions, inline alert and call-to-action widgets, and custom HTML-preserving extensions for `div`, `style`, `script`, `svg`, `span`, and catch-all attribute preservation. A media-picker bridge is exposed via `setOpenImagePicker()`.
|
|
271
271
|
|
|
272
|
-
**Translation & Localization** — The
|
|
272
|
+
**Translation & Localization** — The set of served locales is the active rows of the `languages` table (managed at `/cms/settings/languages`; the proxy reads them with a 60-second in-memory cache and only falls back to the hardcoded `FALLBACK_LOCALES` `en`/`fr` when the DB is unreadable), backed by `languages` and `translations` tables from migration `00000000000001_setup_cms_core.sql`. First-visit language detection is admin-configurable (see F-007): browser `Accept-Language`, IP-country via host geo headers, combined, or always-default — implemented in `apps/nextblock/lib/i18n/detection.ts` and stored in `site_settings.language_detection_settings`. Content revision history is stored as snapshot + JSON Patch diff (enum `revision_type: snapshot, diff`) per migration `00000000000002_setup_content_tables.sql`.
|
|
273
273
|
|
|
274
274
|
**Page Lifecycle** — Pages move through `draft`, `published`, and `archived` statuses (enum `page_status`).
|
|
275
275
|
|
|
@@ -390,7 +390,7 @@ Based on claims and deferred items in the repository documentation, the followin
|
|
|
390
390
|
|
|
391
391
|
#### 1.3.3.5 Integration Points Not Covered
|
|
392
392
|
|
|
393
|
-
The system does not natively integrate with: alternative payment processors beyond Stripe and Freemius, alternative authentication providers beyond Supabase Auth
|
|
393
|
+
The system does not natively integrate with: alternative payment processors beyond Stripe and Freemius, alternative authentication providers beyond Supabase Auth, alternative object-storage providers beyond S3-compatible endpoints (specifically Cloudflare R2 in reference deployments), alternative monorepo orchestrators beyond Nx, or alternative hosting platforms requiring cron-configuration formats other than Vercel's `vercel.json` schema.
|
|
394
394
|
|
|
395
395
|
---
|
|
396
396
|
|
|
@@ -619,7 +619,11 @@ Media management combines a Cloudflare R2-backed object store with an image-proc
|
|
|
619
619
|
|
|
620
620
|
**Description**
|
|
621
621
|
|
|
622
|
-
|
|
622
|
+
Served locales are the active rows of the `languages` table, managed at `/cms/settings/languages` (the seed provides `en` and `fr`, with `en` as the single default; `apps/nextblock/proxy.ts` keeps `FALLBACK_LOCALES = ['en','fr']` only as a safety net when the DB is unreadable). The `languages` table enforces a single `is_default` row; the `translations` table stores translation keys with JSONB-per-locale values. Localized content entities (pages, posts, products) are clustered via `translation_group_id` UUIDs.
|
|
623
|
+
|
|
624
|
+
**First-visit language detection** is admin-configurable on `/cms/settings/languages` and stored as the non-sensitive `site_settings` key `language_detection_settings` (`{ mode, rememberVisitorChoice }`). Modes: `browser` (default — full `Accept-Language` q-value parsing), `country` (visitor's country from host geo headers `x-vercel-ip-country` / `cf-ipcountry` / `cloudfront-viewer-country` / `x-country-code`, mapped through `apps/nextblock/lib/i18n/country-languages.ts`), `browser_then_country`, and `default` (no detection). The pure resolution helpers live in `apps/nextblock/lib/i18n/detection.ts`; the proxy applies them for any request without a valid locale cookie, resolving against the active languages + default language read from the DB with a 60-second in-memory cache.
|
|
625
|
+
|
|
626
|
+
Locale propagation uses the `NEXT_USER_LOCALE` cookie and the `X-User-Locale` request header, both set by the request proxy. When `rememberVisitorChoice` is `true` (default) the cookie persists for one year (`maxAge: 31_536_000` seconds); when `false` it is a session cookie, so detection re-runs each new browser session (the client `LanguageProvider` mirrors the same expiry for manual switcher choices). A valid cookie always beats detection. The client-side provider chain `LanguageProvider → TranslationsProvider` in `apps/nextblock/app/providers.tsx` bridges server-resolved locale into React context.
|
|
623
627
|
|
|
624
628
|
**Business Value:** Unlocks multi-market deployments without requiring adopters to integrate a separate i18n library. **User Benefits:** Language switching persists across sessions; same content IDs preserve relationships across translations. **Technical Context:** Implemented at schema level (migration `00000000000001_setup_cms_core.sql`), proxy level, and provider level.
|
|
625
629
|
|
|
@@ -700,9 +704,9 @@ Three menu locations are supported: `HEADER`, `FOOTER`, and `SIDEBAR`, encoded b
|
|
|
700
704
|
|
|
701
705
|
**Description**
|
|
702
706
|
|
|
703
|
-
Authentication is layered over Supabase Auth using `@supabase/ssr` 0.7.0 and `@supabase/supabase-js` 2.77.0. Server actions in `apps/nextblock/app/actions.ts` implement sign-in, sign-up, and forgot-password flows
|
|
707
|
+
Authentication is layered over Supabase Auth using `@supabase/ssr` 0.7.0 and `@supabase/supabase-js` 2.77.0. Server actions in `apps/nextblock/app/actions.ts` implement sign-in, sign-up, and forgot-password flows. The `app/auth/callback/route.ts` route exchanges authorization codes for sessions (used by the email-confirmation and recovery flows) (`supabase.auth.exchangeCodeForSession()`), loads the profile role, and redirects using `resolvePostAuthRedirect()`. Email templates for confirmation, email change, invitation, magic-link, reauthentication, and password recovery reside in `libs/db/src/supabase/templates/`. A `handle_new_user()` trigger function paired with the `on_auth_user_created` trigger on `auth.users` automatically provisions a `profiles` row on registration.
|
|
704
708
|
|
|
705
|
-
**Business Value:** Eliminates the need for adopters to integrate a separate identity provider. **User Benefits:** Multiple sign-in methods (email/password,
|
|
709
|
+
**Business Value:** Eliminates the need for adopters to integrate a separate identity provider. **User Benefits:** Multiple sign-in methods (email/password, magic link) with localized email templates. **Technical Context:** Supabase Auth session cookies are synchronized by the request proxy to Server Components.
|
|
706
710
|
|
|
707
711
|
**Dependencies**
|
|
708
712
|
|
|
@@ -1290,7 +1294,8 @@ This subsection provides the detailed, testable requirements that operationalize
|
|
|
1290
1294
|
| F-005-RQ-002 | Editor MUST preserve custom HTML constructs (`div`, `style`, `script`, `svg`, `span`) and unrecognized attributes | Must-Have | High |
|
|
1291
1295
|
| F-006-RQ-001 | Media uploads MUST record metadata (`object_key`, `file_type`, `size_bytes`, `width`, `height`, `blur_data_url`, `variants`) in the `media` table | Must-Have | Medium |
|
|
1292
1296
|
| F-006-RQ-002 | `recordMediaUpload` MUST reject non-`ADMIN`/non-`WRITER` callers | Must-Have | Low |
|
|
1293
|
-
| F-007-RQ-001 | Locale MUST propagate via `NEXT_USER_LOCALE` cookie (1-year max age) and `X-User-Locale` header | Must-Have | Low |
|
|
1297
|
+
| F-007-RQ-001 | Locale MUST propagate via `NEXT_USER_LOCALE` cookie (1-year max age when `rememberVisitorChoice` is on; session cookie when off) and `X-User-Locale` header | Must-Have | Low |
|
|
1298
|
+
| F-007-RQ-002 | First-visit locale MUST honor the admin-configured detection mode (`browser`, `country`, `browser_then_country`, `default`) from `site_settings.language_detection_settings` | Must-Have | Medium |
|
|
1294
1299
|
| F-008-RQ-001 | Content revisions MUST use the hybrid snapshot/diff model keyed by `revision_type` enum | Must-Have | Medium |
|
|
1295
1300
|
| F-009-RQ-001 | Navigation items MUST support `HEADER`, `FOOTER`, `SIDEBAR` locations with hierarchy and ordering | Must-Have | Low |
|
|
1296
1301
|
|
|
@@ -1303,7 +1308,7 @@ This subsection provides the detailed, testable requirements that operationalize
|
|
|
1303
1308
|
| F-004-RQ-001 | Block type string, content object | Validated block content or ZodError | Schema validation synchronous |
|
|
1304
1309
|
| F-005-RQ-002 | HTML or Tiptap JSON | Rendered editor content preserving DOM | No HTML loss across round-trip |
|
|
1305
1310
|
| F-006-RQ-001 | Multipart file or presigned PUT | `media` row with metadata | Upload completes within browser timeout |
|
|
1306
|
-
| F-007-RQ-001 | `
|
|
1311
|
+
| F-007-RQ-001 | Locale cookie, `Accept-Language`, host geo-country header | Locale cookie + `X-User-Locale` header | Proxy overhead < 5 ms on cache hit; one Supabase round-trip per isolate per 60 s on miss (loaded concurrently with the auth lookup, shared across concurrent misses) |
|
|
1307
1312
|
|
|
1308
1313
|
#### 2.2.1.3 Validation Rules — Content Delivery
|
|
1309
1314
|
|
|
@@ -1312,7 +1317,7 @@ This subsection provides the detailed, testable requirements that operationalize
|
|
|
1312
1317
|
| F-001-RQ-002 | Image MIME must be in supported list | Only R2-served URLs accepted by next/image loader |
|
|
1313
1318
|
| F-004-RQ-001 | Block `type` MUST exist in registry; content MUST pass Zod schema | Schema prevents XSS via typed fields |
|
|
1314
1319
|
| F-006-RQ-001 | `size_bytes` must be non-negative; `object_key` unique | RLS: ADMIN/WRITER write; public read |
|
|
1315
|
-
| F-007-RQ-001 | Locale MUST be
|
|
1320
|
+
| F-007-RQ-001 | Locale MUST be an active `languages` row (hardcoded `FALLBACK_LOCALES` `en`/`fr` only when the DB is unreadable) | Cookie uses default security attributes |
|
|
1316
1321
|
| F-008-RQ-001 | Snapshot version MUST be unique per `page_id` | Writes RLS-restricted to ADMIN/WRITER |
|
|
1317
1322
|
| F-009-RQ-001 | `menu_location` MUST be one of the three enum values | Writes RLS-restricted to ADMIN/WRITER |
|
|
1318
1323
|
|
|
@@ -1323,7 +1328,7 @@ This subsection provides the detailed, testable requirements that operationalize
|
|
|
1323
1328
|
| Requirement ID | Description | Priority | Complexity |
|
|
1324
1329
|
|:--|:--|:--|:--|
|
|
1325
1330
|
| F-002-RQ-001 | Supabase Auth session exchange MUST succeed via `app/auth/callback/route.ts` | Must-Have | Medium |
|
|
1326
|
-
| F-002-RQ-002 |
|
|
1331
|
+
| F-002-RQ-002 | *(Removed)* Third-party OAuth sign-in is intentionally not provided — it cannot be configured as part of a one-click deployment | Won't-Have | — |
|
|
1327
1332
|
| F-002-RQ-003 | `handle_new_user()` trigger MUST provision a `profiles` row on every `auth.users` insert | Must-Have | Medium |
|
|
1328
1333
|
| F-003-RQ-001 | First registered user MUST become `ADMIN`; subsequent users MUST become `USER` | Must-Have | Medium |
|
|
1329
1334
|
| F-003-RQ-002 | `/cms` MUST require `WRITER` or `ADMIN`; `/cms/admin`, `/cms/users`, `/cms/settings` MUST require `ADMIN` only | Must-Have | Medium |
|
|
@@ -1612,7 +1617,7 @@ The following matrix links features to the sections of the technical specificati
|
|
|
1612
1617
|
| Build Status | `ecommerce:build` Nx standalone target currently not green (per §1.3.3.1) | F-013–F-022 |
|
|
1613
1618
|
| Freemius Reconciliation | Webhook events acknowledged only; DB reconciliation pending (per §1.3.3.1) | F-017, F-021 |
|
|
1614
1619
|
| Postal Code Shipping | Schema present; runtime resolver does not consume (per §1.3.3.1) | F-019 |
|
|
1615
|
-
| Locale Count |
|
|
1620
|
+
| Locale Count | Seed provides `en` and `fr`; additional locales are added as `languages` rows at `/cms/settings/languages` | F-007, F-009, F-013 |
|
|
1616
1621
|
| Module Boundaries | `libs/ui` MUST NOT depend on `apps/nextblock` | F-028 |
|
|
1617
1622
|
|
|
1618
1623
|
### 2.4.2 Performance Requirements
|
|
@@ -1674,7 +1679,7 @@ The following matrix links features to the sections of the technical specificati
|
|
|
1674
1679
|
| FX override | `FX_API_BASE_URL` toggle allows switching provider without code change | F-018 |
|
|
1675
1680
|
| Sandbox dataset | `SANDBOX_RESET_SQL` in `/api/cron/reset-sandbox/route.ts` must be regenerated as schema evolves | F-025, F-026 |
|
|
1676
1681
|
| Package alignment | `@nextblock-cms/ecom` package name vs. `@nextblock-cms/ecommerce` alias (per §1.3.3.1) requires coordination when republished | F-013–F-022 |
|
|
1677
|
-
| Locale expansion |
|
|
1682
|
+
| Locale expansion | Locales are DB-driven: add an active `languages` row (plus translations/content); `FALLBACK_LOCALES` in `proxy.ts` is only a DB-unreachable safety net | F-007 |
|
|
1678
1683
|
| Block registry updates | New block types must satisfy F-024 contract and register in `blockRegistry.ts` | F-004, F-024 |
|
|
1679
1684
|
| RLS policy review | Migration `00000000000006_setup_rls_and_grants.sql` should be audited on new table introduction | All DB-backed features |
|
|
1680
1685
|
|
|
@@ -2135,7 +2140,7 @@ graph TB
|
|
|
2135
2140
|
|
|
2136
2141
|
#### 3.4.1.1 Responsibilities
|
|
2137
2142
|
|
|
2138
|
-
Supabase provides PostgreSQL data storage, Row-Level Security, authentication (F-002), and session cookie management.
|
|
2143
|
+
Supabase provides PostgreSQL data storage, Row-Level Security, authentication (F-002), and session cookie management. Six email templates for the authentication flow (confirmation, email change, invitation, magic-link, reauthentication, password recovery) reside in `libs/db/src/supabase/templates/` and are synchronized with Supabase through `npm run configure:supabase-auth`.
|
|
2139
2144
|
|
|
2140
2145
|
#### 3.4.1.2 Environment Variables
|
|
2141
2146
|
|
|
@@ -2254,7 +2259,7 @@ The workspace implements a layered caching strategy aligned with the performance
|
|
|
2254
2259
|
| `unstable_cache` (package activation) | 60 s | Avoids DB hit on every F-022 license check | `libs/db/src/lib/package-validation.ts` |
|
|
2255
2260
|
| Next.js ISR (public layout) | 60 s (`PUBLIC_LAYOUT_REVALIDATE_SECONDS`) | Public content revalidation | `apps/nextblock/app/layout.tsx` |
|
|
2256
2261
|
| Image cache TTL | 31,536,000 s (1 year) | Immutable optimized-image responses | `next.config.js` |
|
|
2257
|
-
| Locale cookie | 31,536,000 s (1 year) | Persistent locale preference | `proxy.ts` |
|
|
2262
|
+
| Locale cookie | 31,536,000 s (1 year), or session cookie when "remember visitor's language" is off | Persistent locale preference | `proxy.ts` |
|
|
2258
2263
|
| On-demand revalidation | N/A | Per-path invalidation via `REVALIDATE_SECRET_TOKEN` | `/api/revalidate` (F-027) |
|
|
2259
2264
|
| bfcache-compatible HTML | `max-age=0, must-revalidate` | Preserves back-forward cache | `proxy.ts` |
|
|
2260
2265
|
|
|
@@ -2428,7 +2433,7 @@ The Default Technology Stack specified for this project included assumptions tha
|
|
|
2428
2433
|
| **Terraform** IaC | Declarative configs (`vercel.json`, Supabase migrations, `project.json`) | Application-layer declarative configuration suffices given the managed-service stack |
|
|
2429
2434
|
| **GitHub Actions** CI/CD | Vercel Git deploy + Node release scripts | Release cadence and library publishing managed via `tools/scripts/*` |
|
|
2430
2435
|
| **Python / Flask** backend | TypeScript + Next.js 16 route handlers | Monolithic Next.js model enables RSC co-located with API routes |
|
|
2431
|
-
| **Auth0** authentication | Supabase Auth
|
|
2436
|
+
| **Auth0** authentication | Supabase Auth (GoTrue) | Supabase Auth unifies database and identity for RLS-driven authorization (F-003) |
|
|
2432
2437
|
| **MongoDB** database | Supabase PostgreSQL | Relational schema with RLS is better suited to the commerce and content data model |
|
|
2433
2438
|
| **Langchain** AI framework | Not present (structural AI-readiness only) | Per §1.3.3.1, AI runtime features are "coming soon" |
|
|
2434
2439
|
| **React-Native** mobile | Not used — web-only Next.js | Out-of-scope per §1.3.3.5 |
|
|
@@ -2615,9 +2620,9 @@ flowchart TB
|
|
|
2615
2620
|
Supabase --> SyncSession[supabase.auth.getSession<br/>Sync Cookies]
|
|
2616
2621
|
SyncSession --> Locale{Read<br/>NEXT_USER_LOCALE<br/>Cookie}
|
|
2617
2622
|
|
|
2618
|
-
Locale -->|Valid:
|
|
2619
|
-
Locale -->|Invalid or Missing|
|
|
2620
|
-
|
|
2623
|
+
Locale -->|Valid: active language| SetLocaleHeader[Set X-User-Locale]
|
|
2624
|
+
Locale -->|Invalid or Missing| Detect[Detect per settings:<br/>browser / country /<br/>browser_then_country / default]
|
|
2625
|
+
Detect --> SetLocaleHeader
|
|
2621
2626
|
|
|
2622
2627
|
SetLocaleHeader --> GetUser[supabase.auth.getUser]
|
|
2623
2628
|
GetUser --> CmsGuard{Path starts<br/>with /cms?}
|
|
@@ -4156,7 +4161,7 @@ The Zustand-backed cart (with `persist` middleware) captures items in the browse
|
|
|
4156
4161
|
|
|
4157
4162
|
#### 5.1.3.3 Primary Authoring Flow
|
|
4158
4163
|
|
|
4159
|
-
Authors sign in via Supabase Auth
|
|
4164
|
+
Authors sign in via Supabase Auth (email/password), whose email-confirmation callback is handled at `app/auth/callback/route.ts`. After the role-based redirect from `lib/auth-redirects.ts`, authors enter `/cms/*` surfaces, which use Tiptap-based editors and the in-app `blockRegistry.ts` to compose pages. Published content triggers a Supabase webhook to `/api/revalidate`, which calls `revalidatePath` for `/slug` (pages) or `/article/slug` (posts).
|
|
4160
4165
|
|
|
4161
4166
|
#### 5.1.3.4 Integration, Transformation, and Storage
|
|
4162
4167
|
|
|
@@ -4703,7 +4708,7 @@ The primary error notification path is the Feedback System (F-029), which allows
|
|
|
4703
4708
|
|
|
4704
4709
|
#### 5.4.4.1 Authentication
|
|
4705
4710
|
|
|
4706
|
-
Supabase Auth provides email/password
|
|
4711
|
+
Supabase Auth provides email/password and magic-link sign-in. Sign-in server actions live in `app/actions.ts`; the email-confirmation callback resolves to `app/auth/callback/route.ts`, which exchanges the code for a session and then delegates to `lib/auth-redirects.ts` for the post-auth destination. The redirect resolver validates that any `next` parameter is a safe internal path, preserves `/reset-password`, routes `ADMIN`/`WRITER` to `safePath` or `/cms/dashboard`, sends `USER` without `full_name` to `/profile`, and otherwise falls back to `/`.
|
|
4707
4712
|
|
|
4708
4713
|
#### 5.4.4.2 Authorization Model
|
|
4709
4714
|
|
|
@@ -5656,7 +5661,7 @@ Declared in migration `00000000000001_setup_cms_core.sql`, these tables bootstra
|
|
|
5656
5661
|
| Table | Primary Key | Key Columns / Constraints |
|
|
5657
5662
|
|-------|-------------|----------------------------|
|
|
5658
5663
|
| `site_settings` | `key` (text) | `value jsonb` — flat key/value store for global configuration |
|
|
5659
|
-
| `profiles` | `id uuid` | FK → `auth.users(id) ON DELETE CASCADE`; `role user_role NOT NULL DEFAULT 'USER'`; `full_name`, `avatar_url`, `website`, `
|
|
5664
|
+
| `profiles` | `id uuid` | FK → `auth.users(id) ON DELETE CASCADE`; `role user_role NOT NULL DEFAULT 'USER'`; `full_name`, `avatar_url`, `website`, `phone` |
|
|
5660
5665
|
| `user_addresses` | `id` (identity) | FK → `profiles(id)`; `address_type CHECK IN ('billing','shipping')`; `is_default`, `recipient_name`, `line1/2`, `city`, `state`, `postal_code`, `country_code` |
|
|
5661
5666
|
| `languages` | `id bigint` | `code UNIQUE`, `name`, `is_default`, `is_active DEFAULT true` |
|
|
5662
5667
|
| `media` | `id uuid` | `uploader_id → profiles`; `object_key UNIQUE`; `variants jsonb`; `blur_data_url`; `width`, `height`, `size_bytes`, `file_path`, `folder` |
|
|
@@ -7561,16 +7566,17 @@ flowchart TB
|
|
|
7561
7566
|
|
|
7562
7567
|
#### 6.4.2.1 Identity Management
|
|
7563
7568
|
|
|
7564
|
-
The identity provider is **Supabase Auth (GoTrue)**, consumed through the `@supabase/ssr` adapter layer.
|
|
7569
|
+
The identity provider is **Supabase Auth (GoTrue)**, consumed through the `@supabase/ssr` adapter layer. Three distinct authentication surfaces are exposed to end users:
|
|
7565
7570
|
|
|
7566
7571
|
| Authentication Method | Entry Point | Implementation |
|
|
7567
7572
|
|-----------------------|-------------|----------------|
|
|
7568
7573
|
| Email/Password | `signInAction` in `app/actions.ts` | `supabase.auth.signInWithPassword` |
|
|
7569
7574
|
| Account Registration | `signUpAction` in `app/actions.ts` | `supabase.auth.signUp` with email confirmation |
|
|
7570
7575
|
| Password Recovery | `forgotPasswordAction` in `app/actions.ts` | `supabase.auth.resetPasswordForEmail` (OTP) |
|
|
7571
|
-
| GitHub OAuth | `components/GitHubLoginButton.tsx` | `supabase.auth.signInWithOAuth({ provider: 'github' })` |
|
|
7572
7576
|
|
|
7573
|
-
|
|
7577
|
+
> **No third-party OAuth providers.** GitHub OAuth sign-in and account-linking were removed: they cannot be provisioned as part of a one-click deployment (each install needs its own GitHub OAuth app, client secret, and Supabase's manual-linking toggle, none of which can ship in a migration). The unrelated self-update "Connect GitHub" flow (`lib/updates/*`) is not an end-user auth surface and remains.
|
|
7578
|
+
|
|
7579
|
+
The auth callback route handler at `apps/nextblock/app/auth/callback/route.ts` receives a short-lived authorization code on the query string (used by the email-confirmation and recovery flows), invokes `supabase.auth.exchangeCodeForSession(code)` to convert the code to a session, fetches the user profile via `getProfileWithRoleServerSide(user.id)`, and delegates redirection logic to `resolvePostAuthRedirect` in `apps/nextblock/lib/auth-redirects.ts`. On any exchange failure, the handler redirects to `initialRedirectTo || '/'`.
|
|
7574
7580
|
|
|
7575
7581
|
Six transactional email templates reside in `libs/db/src/supabase/templates/` — covering confirmation, email change, invitation, magic-link, reauthentication, and password recovery — and are synchronized with the Supabase project via `npm run configure:supabase-auth`.
|
|
7576
7582
|
|
|
@@ -7652,7 +7658,7 @@ The following sequence diagram depicts the full authentication flow from credent
|
|
|
7652
7658
|
sequenceDiagram
|
|
7653
7659
|
actor User
|
|
7654
7660
|
participant Browser
|
|
7655
|
-
participant AuthPage as /sign-in
|
|
7661
|
+
participant AuthPage as /sign-in
|
|
7656
7662
|
participant SbAuth as Supabase Auth (GoTrue)
|
|
7657
7663
|
participant Callback as /auth/callback/route.ts
|
|
7658
7664
|
participant Resolver as lib/auth-redirects.ts
|
|
@@ -7660,12 +7666,12 @@ sequenceDiagram
|
|
|
7660
7666
|
participant Profiles as profiles table
|
|
7661
7667
|
participant CMS as /cms/*
|
|
7662
7668
|
|
|
7663
|
-
User->>Browser: Submit credentials
|
|
7664
|
-
Browser->>AuthPage: POST (email+password)
|
|
7665
|
-
AuthPage->>SbAuth: signInWithPassword
|
|
7666
|
-
SbAuth-->>Browser:
|
|
7669
|
+
User->>Browser: Submit credentials
|
|
7670
|
+
Browser->>AuthPage: POST (email+password)
|
|
7671
|
+
AuthPage->>SbAuth: signInWithPassword
|
|
7672
|
+
SbAuth-->>Browser: Session cookies
|
|
7667
7673
|
|
|
7668
|
-
alt
|
|
7674
|
+
alt Email confirmation / recovery (code exchange)
|
|
7669
7675
|
Browser->>Callback: GET /auth/callback?code=...
|
|
7670
7676
|
Callback->>SbAuth: exchangeCodeForSession(code)
|
|
7671
7677
|
SbAuth-->>Callback: Set-Cookie (HttpOnly, Secure)
|
|
@@ -7720,7 +7726,7 @@ Authorization is driven by the `user_role` enum declared in migration `000000000
|
|
|
7720
7726
|
| `USER` | Default for new signups | Customer profile, addresses, own orders |
|
|
7721
7727
|
| `service_role` | Supabase service-role key | Webhooks, cron, admin server actions — bypasses RLS |
|
|
7722
7728
|
|
|
7723
|
-
Role assignment at bootstrap is governed by the `handle_new_user()` SECURITY DEFINER trigger function bound to `auth.users` via `on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW`. The trigger acquires a `FOR UPDATE` lock on the `site_settings` row where `setting_key = 'is_admin_created'`, assigns `role='ADMIN'` if the latch is false (and sets the latch), otherwise assigns `role='USER'`,
|
|
7729
|
+
Role assignment at bootstrap is governed by the `handle_new_user()` SECURITY DEFINER trigger function bound to `auth.users` via `on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW`. The trigger acquires a `FOR UPDATE` lock on the `site_settings` row where `setting_key = 'is_admin_created'`, assigns `role='ADMIN'` if the latch is false (and sets the latch), otherwise assigns `role='USER'`, and always creates a `profiles` row. The `FOR UPDATE` lock guarantees race-free first-admin election even under concurrent signup attempts.
|
|
7724
7730
|
|
|
7725
7731
|
#### 6.4.3.2 Permission Management and SECURITY DEFINER Helpers
|
|
7726
7732
|
|
|
@@ -7908,7 +7914,7 @@ The repository does not implement explicit PII masking transforms. The following
|
|
|
7908
7914
|
| Error message sanitization | All error responses | Never contains JWT, service role key, or DB connection strings |
|
|
7909
7915
|
| Admin user list | `/cms/users` | Email addresses displayed (no masking) — audience is ADMIN only |
|
|
7910
7916
|
|
|
7911
|
-
The CMS admin user-list page uses the service-role client via `supabaseAdmin.auth.admin.listUsers` to enumerate users; since the audience of that surface is already `ADMIN`-gated, no masking transform is applied. PII in `profiles` (`full_name`, `avatar_url`, `phone
|
|
7917
|
+
The CMS admin user-list page uses the service-role client via `supabaseAdmin.auth.admin.listUsers` to enumerate users; since the audience of that surface is already `ADMIN`-gated, no masking transform is applied. PII in `profiles` (`full_name`, `avatar_url`, `phone`) is protected by RLS self-scoping rather than cryptographic masking.
|
|
7912
7918
|
|
|
7913
7919
|
#### 6.4.4.4 Secure Communication
|
|
7914
7920
|
|
|
@@ -8202,7 +8208,6 @@ For details beyond the scope of this section, consult:
|
|
|
8202
8208
|
- `apps/nextblock/app/(auth-pages)/post-sign-in/page.tsx` — 27-line post-auth routing page
|
|
8203
8209
|
- `apps/nextblock/app/unauthorized/page.tsx` — 26-line unauthorized display
|
|
8204
8210
|
- `apps/nextblock/context/AuthContext.tsx` — Client auth state provider
|
|
8205
|
-
- `apps/nextblock/components/GitHubLoginButton.tsx` — 37-line OAuth initiation
|
|
8206
8211
|
|
|
8207
8212
|
#### CMS Guards and Admin Self-Protection
|
|
8208
8213
|
|
|
@@ -9691,7 +9696,7 @@ Four distinct persona classes consume the UI, with role-based affordances enforc
|
|
|
9691
9696
|
The UI surface supports six top-level capability families, each rooted in a dedicated route group:
|
|
9692
9697
|
|
|
9693
9698
|
1. **Public Content Delivery (F-001)** — locale-aware marketing, article, and product-detail rendering with SEO metadata, `robots.txt`, and `sitemap.xml`.
|
|
9694
|
-
2. **Authentication & Account (F-002)** — email/password,
|
|
9699
|
+
2. **Authentication & Account (F-002)** — email/password, magic-link, password reset, profile completion.
|
|
9695
9700
|
3. **CMS Authoring (F-004, F-005, F-006, F-007, F-008, F-009)** — block-based page building, Tiptap rich text, media library, translations, revision history, navigation management.
|
|
9696
9701
|
4. **Commerce (F-013 through F-021)** — catalog browsing, variant selection, cart, checkout, invoicing, customer order history.
|
|
9697
9702
|
5. **Administration (F-003, F-030)** — user management, package activation, site settings, shipping/tax configuration.
|
|
@@ -9852,8 +9857,8 @@ The auth forms consume a typed message union defined in `apps/nextblock/componen
|
|
|
9852
9857
|
|
|
9853
9858
|
| Path | File | Purpose |
|
|
9854
9859
|
|:--|:--|:--|
|
|
9855
|
-
| `/sign-in` | `app/(auth-pages)/sign-in/page.tsx` | Email/password
|
|
9856
|
-
| `/sign-up` | `app/(auth-pages)/sign-up/page.tsx` | Registration (email
|
|
9860
|
+
| `/sign-in` | `app/(auth-pages)/sign-in/page.tsx` | Email/password, forgot-password link, sandbox credentials alert |
|
|
9861
|
+
| `/sign-up` | `app/(auth-pages)/sign-up/page.tsx` | Registration (email) with success confirmation view |
|
|
9857
9862
|
| `/forgot-password` | `app/(auth-pages)/forgot-password/page.tsx` | Password reset request form |
|
|
9858
9863
|
| `/post-sign-in` | `app/(auth-pages)/post-sign-in/page.tsx` | Server routing endpoint (non-visual redirector) |
|
|
9859
9864
|
| `/auth/callback` | `app/auth/callback/route.ts` | OAuth authorization-code exchange handler |
|
|
@@ -10046,10 +10051,9 @@ The component consumes `useTheme` from `next-themes`, uses a mounted-state guard
|
|
|
10046
10051
|
|
|
10047
10052
|
| Interaction | Implementation |
|
|
10048
10053
|
|:--|:--|
|
|
10049
|
-
| Sign-In Form | Email/password + forgot-password link + `
|
|
10054
|
+
| Sign-In Form | Email/password + forgot-password link + `SandboxCredentialsAlert` when `NEXT_PUBLIC_IS_SANDBOX === 'true'`. Max-width `160` (mx-auto). Hidden `redirect` field preserved for post-sign-in routing |
|
|
10050
10055
|
| Sign-Up Form | Shared layout with sign-in. Success view rendered when URL contains success flag: confirmation badge (`rounded-full bg-primary/10 text-primary`), `CheckCircle2` icon, email-check instructions with `Mail` icon, "Back to sign in" / "Use different email" actions |
|
|
10051
10056
|
| Header Auth (`header-auth.tsx`) | Missing-env warning badge + disabled buttons when env vars absent; avatar dropdown (`h-8 w-8 rounded-full`) with profile/dashboard/logout when authenticated; sign-in/sign-up buttons for guests |
|
|
10052
|
-
| GitHub OAuth (`GitHubLoginButton.tsx`) | Outline variant, full-width button with embedded GitHub SVG; invokes `supabase.auth.signInWithOAuth({ provider: 'github' })` with callback URL |
|
|
10053
10057
|
|
|
10054
10058
|
### 7.7.6 Commerce UI Interactions
|
|
10055
10059
|
|
|
@@ -10275,7 +10279,7 @@ Server-resolved locale (from `X-User-Locale` header) is bridged to client via `T
|
|
|
10275
10279
|
|
|
10276
10280
|
#### Authentication Screens
|
|
10277
10281
|
|
|
10278
|
-
- `apps/nextblock/app/(auth-pages)/sign-in/page.tsx` —
|
|
10282
|
+
- `apps/nextblock/app/(auth-pages)/sign-in/page.tsx` — Email/password sign-in
|
|
10279
10283
|
- `apps/nextblock/app/(auth-pages)/sign-up/page.tsx` — Sign-up with success state
|
|
10280
10284
|
- `apps/nextblock/app/(auth-pages)/forgot-password/page.tsx` — Password reset
|
|
10281
10285
|
- `apps/nextblock/app/(auth-pages)/post-sign-in/page.tsx` — Server-routing endpoint
|
|
@@ -10298,7 +10302,6 @@ Server-resolved locale (from `X-User-Locale` header) is bridged to client via `T
|
|
|
10298
10302
|
- `apps/nextblock/components/ResponsiveNav.tsx` — Hierarchical navigation
|
|
10299
10303
|
- `apps/nextblock/components/theme-switcher.tsx` — Four-theme dropdown
|
|
10300
10304
|
- `apps/nextblock/components/header-auth.tsx` — Authenticated vs guest auth UI
|
|
10301
|
-
- `apps/nextblock/components/GitHubLoginButton.tsx` — OAuth trigger button
|
|
10302
10305
|
- `apps/nextblock/components/form-message.tsx` — Typed auth message renderer
|
|
10303
10306
|
|
|
10304
10307
|
#### Client Context Providers
|
|
@@ -10627,7 +10630,7 @@ Three distinct cloud providers compose the production footprint. The rationale f
|
|
|
10627
10630
|
| Provider | Role | Selection Rationale |
|
|
10628
10631
|
|:--|:--|:--|
|
|
10629
10632
|
| Vercel | Compute + Edge + Cron + RUM | Zero-configuration Next.js 16 hosting; built-in image optimization; native App Router support; no container orchestration overhead; cron scheduling integrated with function lifecycle |
|
|
10630
|
-
| Supabase | PostgreSQL + Auth + Storage metadata | Managed PostgreSQL 17 with built-in RLS; GoTrue auth service;
|
|
10633
|
+
| Supabase | PostgreSQL + Auth + Storage metadata | Managed PostgreSQL 17 with built-in RLS; GoTrue auth service; SQL migration CLI; PITR included; generous free tier for open-core distribution |
|
|
10631
10634
|
| Cloudflare R2 | S3-compatible object storage | Zero egress fees (superior to AWS S3 for media-heavy workloads); S3-compatible API usable via `@aws-sdk/client-s3 ^3.920.0`; global edge presence |
|
|
10632
10635
|
|
|
10633
10636
|
**Documented deviations from the Default Technology Stack** (per §3.7.1):
|
|
@@ -10639,7 +10642,7 @@ Three distinct cloud providers compose the production footprint. The rationale f
|
|
|
10639
10642
|
| Terraform | Declarative config across `vercel.json`, migrations, `config.toml`, `.env.exemple`, `nx.json` | No multi-service provisioning to orchestrate |
|
|
10640
10643
|
| GitHub Actions | Vercel Git integration + Node release scripts in `tools/scripts/` | No CI test suite to gate; publication handled imperatively |
|
|
10641
10644
|
| Python / Flask | TypeScript + Next.js route handlers | Unified stack across client + server |
|
|
10642
|
-
| Auth0 | Supabase Auth (GoTrue)
|
|
10645
|
+
| Auth0 | Supabase Auth (GoTrue) | Integrated with RLS at the database layer |
|
|
10643
10646
|
| MongoDB | Supabase PostgreSQL | Relational data model + RLS + SECURITY DEFINER helpers |
|
|
10644
10647
|
|
|
10645
10648
|
### 8.3.2 Core Services and Versions
|
|
@@ -10663,7 +10666,7 @@ Three distinct cloud providers compose the production footprint. The rationale f
|
|
|
10663
10666
|
| PostgreSQL | `postgres` | `^3.8` (inventory dual-path fallback) | Direct SQL when RPC unavailable |
|
|
10664
10667
|
| SSR client | `@supabase/ssr` | `^0.7.0` | Server-side cookie-based session |
|
|
10665
10668
|
| Browser client | `@supabase/supabase-js` | `^2.77.0` | Client components + editor |
|
|
10666
|
-
| Auth (GoTrue) | via `@supabase/ssr` | bundled | Email/password,
|
|
10669
|
+
| Auth (GoTrue) | via `@supabase/ssr` | bundled | Email/password, password reset |
|
|
10667
10670
|
| Realtime | bundled (enabled in `config.toml`) | bundled | WebSocket subscriptions |
|
|
10668
10671
|
| CLI | `supabase` | invoked via `npx supabase` | Migrations, link, db push, config push |
|
|
10669
10672
|
|
|
@@ -155,12 +155,12 @@ const RELATION_TARGETS: readonly CustomBlockRelationTarget[] = [
|
|
|
155
155
|
valueType: 'string',
|
|
156
156
|
},
|
|
157
157
|
{
|
|
158
|
-
descriptionColumns: ['
|
|
158
|
+
descriptionColumns: ['website'],
|
|
159
159
|
displayColumn: 'full_name',
|
|
160
160
|
label: 'Profiles',
|
|
161
161
|
orderBy: 'full_name',
|
|
162
|
-
searchableColumns: ['full_name', '
|
|
163
|
-
selectColumns: ['id', 'full_name', 'avatar_url', '
|
|
162
|
+
searchableColumns: ['full_name', 'website'],
|
|
163
|
+
selectColumns: ['id', 'full_name', 'avatar_url', 'website', 'role'],
|
|
164
164
|
table: 'profiles',
|
|
165
165
|
valueColumn: 'id',
|
|
166
166
|
valueType: 'string',
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
// Ordered ISO 3166-1 alpha-2 country -> primary language candidates (ISO 639-1).
|
|
2
|
+
// Used by the "visitor's country" language-detection mode: candidates are matched
|
|
3
|
+
// against the site's active language codes in order, so multilingual countries list
|
|
4
|
+
// their languages by prevalence (e.g. CH tries de, then fr, then it).
|
|
5
|
+
// This is a pragmatic "most likely language" map, not a census — sites that need a
|
|
6
|
+
// different mapping should simply not enable country-based detection.
|
|
7
|
+
export const COUNTRY_PRIMARY_LANGUAGES: Record<string, string[]> = {
|
|
8
|
+
AD: ['ca', 'es', 'fr'],
|
|
9
|
+
AE: ['ar', 'en'],
|
|
10
|
+
AF: ['fa', 'ps'],
|
|
11
|
+
AG: ['en'],
|
|
12
|
+
AI: ['en'],
|
|
13
|
+
AL: ['sq'],
|
|
14
|
+
AM: ['hy', 'ru'],
|
|
15
|
+
AO: ['pt'],
|
|
16
|
+
AR: ['es'],
|
|
17
|
+
AS: ['en'],
|
|
18
|
+
AT: ['de'],
|
|
19
|
+
AU: ['en'],
|
|
20
|
+
AW: ['nl', 'es'],
|
|
21
|
+
AX: ['sv'],
|
|
22
|
+
AZ: ['az', 'ru'],
|
|
23
|
+
BA: ['bs', 'hr', 'sr'],
|
|
24
|
+
BB: ['en'],
|
|
25
|
+
BD: ['bn'],
|
|
26
|
+
BE: ['nl', 'fr', 'de'],
|
|
27
|
+
BF: ['fr'],
|
|
28
|
+
BG: ['bg'],
|
|
29
|
+
BH: ['ar', 'en'],
|
|
30
|
+
BI: ['fr', 'rn'],
|
|
31
|
+
BJ: ['fr'],
|
|
32
|
+
BM: ['en'],
|
|
33
|
+
BN: ['ms', 'en'],
|
|
34
|
+
BO: ['es'],
|
|
35
|
+
BQ: ['nl'],
|
|
36
|
+
BR: ['pt'],
|
|
37
|
+
BS: ['en'],
|
|
38
|
+
BT: ['dz', 'en'],
|
|
39
|
+
BW: ['en', 'tn'],
|
|
40
|
+
BY: ['ru', 'be'],
|
|
41
|
+
BZ: ['en', 'es'],
|
|
42
|
+
CA: ['en', 'fr'],
|
|
43
|
+
CD: ['fr'],
|
|
44
|
+
CF: ['fr'],
|
|
45
|
+
CG: ['fr'],
|
|
46
|
+
CH: ['de', 'fr', 'it'],
|
|
47
|
+
CI: ['fr'],
|
|
48
|
+
CK: ['en'],
|
|
49
|
+
CL: ['es'],
|
|
50
|
+
CM: ['fr', 'en'],
|
|
51
|
+
CN: ['zh'],
|
|
52
|
+
CO: ['es'],
|
|
53
|
+
CR: ['es'],
|
|
54
|
+
CU: ['es'],
|
|
55
|
+
CV: ['pt'],
|
|
56
|
+
CW: ['nl', 'en', 'es'],
|
|
57
|
+
CY: ['el', 'tr', 'en'],
|
|
58
|
+
CZ: ['cs'],
|
|
59
|
+
DE: ['de'],
|
|
60
|
+
DJ: ['fr', 'ar'],
|
|
61
|
+
DK: ['da'],
|
|
62
|
+
DM: ['en'],
|
|
63
|
+
DO: ['es'],
|
|
64
|
+
DZ: ['ar', 'fr'],
|
|
65
|
+
EC: ['es'],
|
|
66
|
+
EE: ['et', 'ru'],
|
|
67
|
+
EG: ['ar', 'en'],
|
|
68
|
+
EH: ['ar'],
|
|
69
|
+
ER: ['ti', 'ar', 'en'],
|
|
70
|
+
ES: ['es', 'ca', 'gl'],
|
|
71
|
+
ET: ['am', 'en'],
|
|
72
|
+
FI: ['fi', 'sv'],
|
|
73
|
+
FJ: ['en', 'fj'],
|
|
74
|
+
FK: ['en'],
|
|
75
|
+
FM: ['en'],
|
|
76
|
+
FO: ['fo', 'da'],
|
|
77
|
+
FR: ['fr'],
|
|
78
|
+
GA: ['fr'],
|
|
79
|
+
GB: ['en'],
|
|
80
|
+
GD: ['en'],
|
|
81
|
+
GE: ['ka', 'ru'],
|
|
82
|
+
GF: ['fr'],
|
|
83
|
+
GG: ['en'],
|
|
84
|
+
GH: ['en'],
|
|
85
|
+
GI: ['en', 'es'],
|
|
86
|
+
GL: ['kl', 'da'],
|
|
87
|
+
GM: ['en'],
|
|
88
|
+
GN: ['fr'],
|
|
89
|
+
GP: ['fr'],
|
|
90
|
+
GQ: ['es', 'fr', 'pt'],
|
|
91
|
+
GR: ['el'],
|
|
92
|
+
GT: ['es'],
|
|
93
|
+
GU: ['en'],
|
|
94
|
+
GW: ['pt'],
|
|
95
|
+
GY: ['en'],
|
|
96
|
+
HK: ['zh', 'en'],
|
|
97
|
+
HN: ['es'],
|
|
98
|
+
HR: ['hr'],
|
|
99
|
+
HT: ['fr', 'ht'],
|
|
100
|
+
HU: ['hu'],
|
|
101
|
+
ID: ['id'],
|
|
102
|
+
IE: ['en', 'ga'],
|
|
103
|
+
IL: ['he', 'ar', 'en', 'ru'],
|
|
104
|
+
IM: ['en'],
|
|
105
|
+
IN: ['hi', 'en'],
|
|
106
|
+
IQ: ['ar', 'ku'],
|
|
107
|
+
IR: ['fa'],
|
|
108
|
+
IS: ['is'],
|
|
109
|
+
IT: ['it'],
|
|
110
|
+
JE: ['en'],
|
|
111
|
+
JM: ['en'],
|
|
112
|
+
JO: ['ar', 'en'],
|
|
113
|
+
JP: ['ja'],
|
|
114
|
+
KE: ['en', 'sw'],
|
|
115
|
+
KG: ['ky', 'ru'],
|
|
116
|
+
KH: ['km'],
|
|
117
|
+
KI: ['en'],
|
|
118
|
+
KM: ['fr', 'ar'],
|
|
119
|
+
KN: ['en'],
|
|
120
|
+
KP: ['ko'],
|
|
121
|
+
KR: ['ko'],
|
|
122
|
+
KW: ['ar', 'en'],
|
|
123
|
+
KY: ['en'],
|
|
124
|
+
KZ: ['kk', 'ru'],
|
|
125
|
+
LA: ['lo'],
|
|
126
|
+
LB: ['ar', 'fr', 'en'],
|
|
127
|
+
LC: ['en'],
|
|
128
|
+
LI: ['de'],
|
|
129
|
+
LK: ['si', 'ta', 'en'],
|
|
130
|
+
LR: ['en'],
|
|
131
|
+
LS: ['en', 'st'],
|
|
132
|
+
LT: ['lt', 'ru'],
|
|
133
|
+
LU: ['fr', 'de', 'lb'],
|
|
134
|
+
LV: ['lv', 'ru'],
|
|
135
|
+
LY: ['ar'],
|
|
136
|
+
MA: ['ar', 'fr'],
|
|
137
|
+
MC: ['fr'],
|
|
138
|
+
MD: ['ro', 'ru'],
|
|
139
|
+
ME: ['sr'],
|
|
140
|
+
MF: ['fr'],
|
|
141
|
+
MG: ['fr', 'mg'],
|
|
142
|
+
MH: ['en'],
|
|
143
|
+
MK: ['mk', 'sq'],
|
|
144
|
+
ML: ['fr'],
|
|
145
|
+
MM: ['my'],
|
|
146
|
+
MN: ['mn'],
|
|
147
|
+
MO: ['zh', 'pt'],
|
|
148
|
+
MP: ['en'],
|
|
149
|
+
MQ: ['fr'],
|
|
150
|
+
MR: ['ar', 'fr'],
|
|
151
|
+
MS: ['en'],
|
|
152
|
+
MT: ['mt', 'en'],
|
|
153
|
+
MU: ['en', 'fr'],
|
|
154
|
+
MV: ['dv', 'en'],
|
|
155
|
+
MW: ['en', 'ny'],
|
|
156
|
+
MX: ['es'],
|
|
157
|
+
MY: ['ms', 'en', 'zh'],
|
|
158
|
+
MZ: ['pt'],
|
|
159
|
+
NA: ['en', 'af', 'de'],
|
|
160
|
+
NC: ['fr'],
|
|
161
|
+
NE: ['fr'],
|
|
162
|
+
NF: ['en'],
|
|
163
|
+
NG: ['en'],
|
|
164
|
+
NI: ['es'],
|
|
165
|
+
NL: ['nl'],
|
|
166
|
+
NO: ['no', 'nb'],
|
|
167
|
+
NP: ['ne'],
|
|
168
|
+
NR: ['en'],
|
|
169
|
+
NU: ['en'],
|
|
170
|
+
NZ: ['en', 'mi'],
|
|
171
|
+
OM: ['ar', 'en'],
|
|
172
|
+
PA: ['es'],
|
|
173
|
+
PE: ['es'],
|
|
174
|
+
PF: ['fr'],
|
|
175
|
+
PG: ['en'],
|
|
176
|
+
PH: ['en', 'tl'],
|
|
177
|
+
PK: ['ur', 'en'],
|
|
178
|
+
PL: ['pl'],
|
|
179
|
+
PM: ['fr'],
|
|
180
|
+
PR: ['es', 'en'],
|
|
181
|
+
PS: ['ar'],
|
|
182
|
+
PT: ['pt'],
|
|
183
|
+
PW: ['en'],
|
|
184
|
+
PY: ['es', 'gn'],
|
|
185
|
+
QA: ['ar', 'en'],
|
|
186
|
+
RE: ['fr'],
|
|
187
|
+
RO: ['ro'],
|
|
188
|
+
RS: ['sr'],
|
|
189
|
+
RU: ['ru'],
|
|
190
|
+
RW: ['rw', 'en', 'fr'],
|
|
191
|
+
SA: ['ar', 'en'],
|
|
192
|
+
SB: ['en'],
|
|
193
|
+
SC: ['en', 'fr'],
|
|
194
|
+
SD: ['ar', 'en'],
|
|
195
|
+
SE: ['sv'],
|
|
196
|
+
SG: ['en', 'zh', 'ms', 'ta'],
|
|
197
|
+
SH: ['en'],
|
|
198
|
+
SI: ['sl'],
|
|
199
|
+
SJ: ['no', 'nb'],
|
|
200
|
+
SK: ['sk'],
|
|
201
|
+
SL: ['en'],
|
|
202
|
+
SM: ['it'],
|
|
203
|
+
SN: ['fr'],
|
|
204
|
+
SO: ['so', 'ar'],
|
|
205
|
+
SR: ['nl'],
|
|
206
|
+
SS: ['en', 'ar'],
|
|
207
|
+
ST: ['pt'],
|
|
208
|
+
SV: ['es'],
|
|
209
|
+
SX: ['nl', 'en'],
|
|
210
|
+
SY: ['ar'],
|
|
211
|
+
SZ: ['en', 'ss'],
|
|
212
|
+
TC: ['en'],
|
|
213
|
+
TD: ['fr', 'ar'],
|
|
214
|
+
TG: ['fr'],
|
|
215
|
+
TH: ['th'],
|
|
216
|
+
TJ: ['tg', 'ru'],
|
|
217
|
+
TK: ['en'],
|
|
218
|
+
TL: ['pt'],
|
|
219
|
+
TM: ['tk', 'ru'],
|
|
220
|
+
TN: ['ar', 'fr'],
|
|
221
|
+
TO: ['en', 'to'],
|
|
222
|
+
TR: ['tr'],
|
|
223
|
+
TT: ['en'],
|
|
224
|
+
TV: ['en'],
|
|
225
|
+
TW: ['zh'],
|
|
226
|
+
TZ: ['sw', 'en'],
|
|
227
|
+
UA: ['uk', 'ru'],
|
|
228
|
+
UG: ['en', 'sw'],
|
|
229
|
+
UM: ['en'],
|
|
230
|
+
US: ['en', 'es'],
|
|
231
|
+
UY: ['es'],
|
|
232
|
+
UZ: ['uz', 'ru'],
|
|
233
|
+
VA: ['it'],
|
|
234
|
+
VC: ['en'],
|
|
235
|
+
VE: ['es'],
|
|
236
|
+
VG: ['en'],
|
|
237
|
+
VI: ['en'],
|
|
238
|
+
VN: ['vi'],
|
|
239
|
+
VU: ['en', 'fr'],
|
|
240
|
+
WF: ['fr'],
|
|
241
|
+
WS: ['en', 'sm'],
|
|
242
|
+
YE: ['ar'],
|
|
243
|
+
YT: ['fr'],
|
|
244
|
+
ZA: ['en', 'af', 'zu'],
|
|
245
|
+
ZM: ['en'],
|
|
246
|
+
ZW: ['en', 'sn'],
|
|
247
|
+
};
|