diff --git a/admin-dashboard-plan.md b/admin-dashboard-plan.md new file mode 100644 index 0000000..2a6da9a --- /dev/null +++ b/admin-dashboard-plan.md @@ -0,0 +1,61 @@ +# Admin Dashboard Plan (Power Control) + +This is the internal control panel used to keep Dewemoji **safe, clean, and reliable**. + +## Purpose + +- Moderate public keywords and votes. +- Manage licenses and activations. +- Monitor system health and data pipelines. + +## Phase 1 (MVP — must‑have) + +### 1) Public keyword moderation +- View **public_pending** keyword queue. +- Approve / reject / block keyword. +- See emoji, language, proposer, vote counts. + +### 2) Abuse controls +- Blocklist terms. +- Quick “hide” keyword from public search. +- Soft‑ban repeated abusive accounts. + +### 3) License management +- Lookup by license key. +- See activations (device_id, product). +- Revoke activation or whole license. + +### 4) System health +- Last JSON rebuild time. +- Dataset counts (emojis, keywords). +- API usage summary (daily). + +### 5) Price control (Personal plan) +- Set IDR pricing for Monthly / Annual / Lifetime. +- Optional USD display override (approx only). +- Toggle payment rails (PayPal / QRIS). +- Effective date + change log (who changed, when). + +## Phase 2 (Nice‑to‑have) + +- AI moderation log viewer. +- Turnstile failure analytics. +- Contributor leaderboard. +- Email queue status. +- Scheduled job history. +- Pricing experiment history. + +## Suggested navigation + +- **Dashboard** (health, quick stats) +- **Keywords** (pending + public) +- **Licenses** +- **Users** +- **System** (jobs, JSON rebuild, logs) + +## Access control + +- Admin login uses **magic‑link/OTP session** + **role=admin** check. +- `X-Admin-Token` is **dev/internal only** (disable in prod). +- No IP allowlist required (dynamic ISP friendly). +- Log all actions (who approved / rejected / revoked). diff --git a/api-how-it-works.md b/api-how-it-works.md new file mode 100644 index 0000000..e66dd02 --- /dev/null +++ b/api-how-it-works.md @@ -0,0 +1,355 @@ +# Dewemoji API — How It Works + +This document explains the current API surface in the rebuild app, including filters, headers, and request/response shapes. + +## Base URLs + +- Local: `http://127.0.0.1:8000/v1` +- Staging: `https://dewemoji.backoffice.biz.id/v1` + +## Auth & headers + +### License key (optional for free, required for Pro) +You can send a license key in either header: + +- `Authorization: Bearer YOUR_LICENSE_KEY` (recommended) +- `X-License-Key: YOUR_LICENSE_KEY` (also supported) + +### Optional headers +- `X-Account-Id`: Optional usage association. +- `X-Dewemoji-Frontend`: Optional frontend identifier (string). + +### Response headers you’ll see +- `X-Dewemoji-Tier`: `free` or `pro` +- `X-Dewemoji-Plan`: `free` or `pro` +- Rate‑limit headers on free tier (page=1 only): + - `X-RateLimit-Limit` + - `X-RateLimit-Remaining` + - `X-RateLimit-Reset` +- Caching: + - `ETag` + - `Cache-Control` + +## Endpoints + +### GET `/emojis` +Search emojis with filters. + +Query params: +- `q` (string): search query (also accepts `query`) +- `category` (string): category name (e.g. `Smileys & Emotion`) +- `subcategory` (string): subcategory name (will be slugified internally) +- `page` (int, default 1) +- `limit` (int): + - Free tier: max 20 + - Pro tier: max 50 + +Behavior: +- If `q` is empty, it returns all emojis (subject to pagination). +- If `q` has multiple terms, all terms must match. +- `category` must match the exact category label in the dataset. +- `subcategory` is matched by slugifying both the request and dataset. +- `plan` field in response will be `free` or `pro`. + +Example: +```bash +curl -s "http://127.0.0.1:8000/v1/emojis?q=love&limit=5" | jq . +``` + +Response (shape): +```json +{ + "items": [ + { + "emoji": "😍", + "name": "smiling face with heart-eyes", + "slug": "smiling-face-with-heart-eyes", + "category": "Smileys & Emotion", + "subcategory": "face-affection", + "supports_skin_tone": false, + "summary": "...", + "unified": "U+1F60D", + "codepoints": ["1F60D"], + "shortcodes": [":smiling-face-with-heart-eyes:", "..."], + "aliases": [], + "keywords_en": ["love", "heart", "..."], + "keywords_id": ["cinta", "..."], + "related": ["🥰", "🤩", "😘"], + "intent_tags": ["love", "affection"] + } + ], + "total": 2131, + "page": 1, + "limit": 20, + "plan": "free" +} +``` + +### GET `/emoji/{slug}` or `/emoji?slug=...` +Fetch detail for a specific emoji. + +Example: +```bash +curl -s "http://127.0.0.1:8000/v1/emoji/grinning-face" | jq . +``` + +Errors: +- `400` if slug is missing (`error: missing_slug`) +- `404` if slug is not found (`error: not_found`) + +### GET `/categories` +Returns a map of category → list of subcategories. + +Example: +```bash +curl -s "http://127.0.0.1:8000/v1/categories" | jq . +``` + +Response: +```json +{ + "Smileys & Emotion": ["face-smiling", "face-affection", "..."], + "People & Body": ["hand-fingers-open", "..."] +} +``` + +### POST `/license/verify` +Validate a license key. + +Headers: +- `Authorization: Bearer YOUR_LICENSE_KEY` (or `X-License-Key`) + +Example: +```bash +curl -s -X POST "http://127.0.0.1:8000/v1/license/verify" \ + -H "Authorization: Bearer YOUR_LICENSE_KEY" | jq . +``` + +Success response: +```json +{ + "ok": true, + "tier": "pro", + "source": "gumroad|mayar|sandbox|...", + "plan": "pro", + "product_id": "…", + "expires_at": null, + "error": null +} +``` + +Errors: +- `400` `missing_key` +- `401` `invalid_license` + +### POST `/license/activate` +Activate a device or site session. + +Body (JSON): +```json +{ + "email": "you@example.com", + "product": "extension|site", + "device_id": "device-123" +} +``` + +Notes: +- `product=site` does not require `device_id`. +- Other products require `device_id`. + +### POST `/license/deactivate` +Deactivate a device. + +Body (JSON): +```json +{ + "product": "extension|site", + "device_id": "device-123" +} +``` + +### GET `/health` +Basic health check. + +Response: +```json +{ "ok": true, "time": "...", "app": "Dewemoji" } +``` + +### GET `/metrics-lite` +Lightweight metrics (if enabled). + +### GET `/metrics` +Full metrics (requires token or allowed IP). + +## Extension verification (public, no login) + +These endpoints allow **verified extension installs** to access public search without login. + +Fallback (temporary): +- If Verified Access token is not available, the server can accept `X-Extension-Id` + as a **soft allowlist** signal. This is **spoofable** and should not be treated as + a strong security boundary. + +### POST `/extension/verify` +Verifies `X-Extension-Token` by calling Google Instance ID API. + +Headers: +- `X-Extension-Token: ` + +Response: +```json +{ "ok": true, "verified": true } +``` + +### GET `/extension/search` +Public search for verified extension installs only. + +Headers: +- `X-Extension-Token: ` + +Example: +```bash +curl -s "http://127.0.0.1:8000/v1/extension/search?q=snail" \ + -H "X-Extension-Token: $EXT_TOKEN" | jq . +``` + +Errors: +- `403 extension_unverified` + +## Caching + +The API uses `ETag` and returns `304 Not Modified` if the client sends: +``` +If-None-Match: "etag-value" +``` + +Example: +```bash +ETAG=$(curl -i "http://127.0.0.1:8000/v1/emojis?q=love&limit=5" | awk -F': ' '/^ETag:/ {print $2}' | tr -d '\r') +curl -i -H "If-None-Match: $ETAG" "http://127.0.0.1:8000/v1/emojis?q=love&limit=5" | head -n 1 +``` + +## Public access guard (whitelist + soft throttle) + +Public endpoints (`/v1/emojis`, `/v1/categories`, `/v1/emoji`) are protected by a **whitelist + hourly throttle**. + +Behavior: +- If the request is **whitelisted**, it passes without throttling. +- If not whitelisted: + - If `DEWEMOJI_PUBLIC_ENFORCE=true` → `403 public_access_denied` + - Else → **soft throttle** with `DEWEMOJI_PUBLIC_HOURLY_LIMIT` (HTTP `429 public_rate_limited`) + +Whitelist rules: +- `Origin` is in `DEWEMOJI_PUBLIC_ORIGINS` +- Or `X-Dewemoji-Frontend` / `User-Agent` contains a configured extension ID + +Key env vars: +``` +DEWEMOJI_PUBLIC_ENFORCE=true|false +DEWEMOJI_PUBLIC_ORIGINS=https://dewemoji.com,https://www.dewemoji.com +DEWEMOJI_PUBLIC_HOURLY_LIMIT=5000 +DEWEMOJI_EXTENSION_IDS=chrome-extension://... +``` + +Rate limit response example: +```json +{ + "ok": false, + "error": "public_rate_limited", + "usage": { + "used": 3, + "limit": 3, + "remaining": 0, + "window": "hourly", + "window_ends_at": "2026-02-08T14:00:00+00:00", + "window_ends_at_unix": 1770559200 + } +} +``` + +## Admin endpoints (token required) + +All admin endpoints require: +``` +X-Admin-Token: +``` + +### Settings (feature flags / public access) +- `GET /v1/admin/settings` +- `POST /v1/admin/settings` + +Example: +```bash +curl -s -X POST "http://127.0.0.1:8000/v1/admin/settings" \ + -H "X-Admin-Token: $DEWEMOJI_ADMIN_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "settings": { + "maintenance_enabled": false, + "public_enforce": true, + "public_hourly_limit": 5000, + "public_origins": ["https://dewemoji.com","https://www.dewemoji.com"], + "public_extension_ids": ["chrome-extension://yourid"] + } + }' | jq . +``` + +### Subscriptions (admin grant/revoke) +- `GET /v1/admin/subscriptions` +- `POST /v1/admin/subscription/grant` +- `POST /v1/admin/subscription/revoke` + +Grant example: +```bash +curl -s -X POST "http://127.0.0.1:8000/v1/admin/subscription/grant" \ + -H "X-Admin-Token: $DEWEMOJI_ADMIN_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"email":"test@example.com","plan":"personal","status":"active","provider":"admin"}' | jq . +``` + +### Webhooks (PayPal) +- `POST /v1/paypal/webhook` (logs + processes) +- `GET /v1/admin/webhooks` +- `GET /v1/admin/webhooks/{id}` +- `POST /v1/admin/webhooks/{id}/replay` + +Deduping: +- PayPal `id` is stored as `event_id`. Duplicate events return `{ "ok": true, "duplicate": true }`. + +Note: +- PayPal **signature verification is not implemented yet** (TODO before production). + +### Analytics +- `GET /v1/admin/analytics` (counts for users/keywords/subscriptions/webhooks) + +## Security note: Origin/Referer are spoofable + +The `Origin` / `Referer` headers are **not** a strong security boundary. They are used to reduce casual abuse only. + +Options to harden public access: +- **Require API keys** for unlimited access (personal users). +- **Rate limit at the edge** (Cloudflare / Nginx). +- **Signed requests** for extension (HMAC or short‑lived tokens). +- **Shared secret header** for internal services. +- **WAF rules** for `/v1/*` endpoints. + +## Error payloads (common) + +```json +{ "ok": false, "error": "not_found" } +``` + +Other possible errors: +- `missing_slug` +- `missing_key` +- `invalid_license` +- `daily_limit_reached` +- `data_load_failed` + +## Notes + +- Current dataset contains **EN + ID** keywords. +- API reads from `app/data/emojis.json` (cache-first strategy). +- Free tier limit is enforced on **page=1** requests. diff --git a/app/.env.example b/app/.env.example index aaf9998..2e2d64d 100644 --- a/app/.env.example +++ b/app/.env.example @@ -47,7 +47,7 @@ REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 -MAIL_MAILER=log +MAIL_MAILER=mailketing MAIL_SCHEME=null MAIL_HOST=127.0.0.1 MAIL_PORT=2525 @@ -55,6 +55,9 @@ MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" +MAILKETING_API_URL=https://api.mailketing.co.id/api/v1/send +MAILKETING_API_TOKEN= +MAILKETING_TIMEOUT=10 AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= @@ -95,3 +98,27 @@ DEWEMOJI_FRONTEND_HEADER=web-v1 DEWEMOJI_METRICS_ENABLED=true DEWEMOJI_METRICS_TOKEN= DEWEMOJI_METRICS_ALLOW_IPS=127.0.0.1,::1 +DEWEMOJI_USD_RATE=15000 +DEWEMOJI_QRIS_URL= +DEWEMOJI_PAYPAL_URL= +DEWEMOJI_PAYPAL_ENABLED=false +DEWEMOJI_PAYPAL_TIMEOUT=10 +DEWEMOJI_PAYPAL_SANDBOX_CLIENT_ID= +DEWEMOJI_PAYPAL_SANDBOX_CLIENT_SECRET= +DEWEMOJI_PAYPAL_SANDBOX_WEBHOOK_ID= +DEWEMOJI_PAYPAL_SANDBOX_PLAN_PERSONAL_MONTHLY= +DEWEMOJI_PAYPAL_SANDBOX_PLAN_PERSONAL_ANNUAL= +DEWEMOJI_PAYPAL_LIVE_CLIENT_ID= +DEWEMOJI_PAYPAL_LIVE_CLIENT_SECRET= +DEWEMOJI_PAYPAL_LIVE_WEBHOOK_ID= +DEWEMOJI_PAYPAL_LIVE_PLAN_PERSONAL_MONTHLY= +DEWEMOJI_PAYPAL_LIVE_PLAN_PERSONAL_ANNUAL= +DEWEMOJI_PAYPAL_SANDBOX_API_BASE=https://api-m.sandbox.paypal.com +DEWEMOJI_PAYPAL_SANDBOX_WEB_BASE=https://www.sandbox.paypal.com +DEWEMOJI_PAYPAL_LIVE_API_BASE=https://api-m.paypal.com +DEWEMOJI_PAYPAL_LIVE_WEB_BASE=https://www.paypal.com +DEWEMOJI_PAKASIR_ENABLED=false +DEWEMOJI_PAKASIR_API_BASE=https://app.pakasir.com +DEWEMOJI_PAKASIR_API_KEY= +DEWEMOJI_PAKASIR_PROJECT= +DEWEMOJI_PAKASIR_TIMEOUT=10 diff --git a/app/app/Http/Controllers/Api/V1/AdminAnalyticsController.php b/app/app/Http/Controllers/Api/V1/AdminAnalyticsController.php new file mode 100644 index 0000000..669d9d7 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminAnalyticsController.php @@ -0,0 +1,56 @@ +header('X-Admin-Token', '')); + if ($token === '' || $provided === '' || !hash_equals($token, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + return null; + } + + public function overview(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $totalUsers = User::count(); + $personalUsers = User::where('tier', 'personal')->count(); + $apiKeys = UserApiKey::count(); + $keywords = UserKeyword::count(); + $subscriptions = Subscription::count(); + $activeSubscriptions = Subscription::where('status', 'active')->count(); + $pricingPlans = PricingPlan::count(); + $webhooks = WebhookEvent::count(); + + return response()->json([ + 'ok' => true, + 'metrics' => [ + 'users_total' => $totalUsers, + 'users_personal' => $personalUsers, + 'api_keys_total' => $apiKeys, + 'keywords_total' => $keywords, + 'subscriptions_total' => $subscriptions, + 'subscriptions_active' => $activeSubscriptions, + 'pricing_plans_total' => $pricingPlans, + 'webhook_events_total' => $webhooks, + ], + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/AdminPricingController.php b/app/app/Http/Controllers/Api/V1/AdminPricingController.php new file mode 100644 index 0000000..2f613d6 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminPricingController.php @@ -0,0 +1,141 @@ +header('X-Admin-Token', '')); + if ($adminToken === '' || $provided === '' || !hash_equals($adminToken, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + + return null; + } + + public function index(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $plans = PricingPlan::orderBy('id')->get(); + + return response()->json([ + 'ok' => true, + 'plans' => $plans, + ]); + } + + public function changes(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $limit = max((int) $request->query('limit', 20), 1); + $items = PricingChange::orderByDesc('id') + ->limit($limit) + ->get(); + + return response()->json([ + 'ok' => true, + 'items' => $items, + ]); + } + + public function update(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $data = $request->validate([ + 'admin_ref' => 'nullable|string|max:120', + 'plans' => 'required|array|min:1', + 'plans.*.code' => 'required|string|max:30', + 'plans.*.name' => 'required|string|max:50', + 'plans.*.currency' => 'required|string|max:10', + 'plans.*.amount' => 'required|integer|min:0', + 'plans.*.period' => 'nullable|string|max:20', + 'plans.*.status' => 'nullable|string|max:20', + 'plans.*.meta' => 'nullable|array', + ]); + + $before = PricingPlan::orderBy('id')->get()->toArray(); + + DB::transaction(function () use ($data): void { + foreach ($data['plans'] as $plan) { + PricingPlan::updateOrCreate( + ['code' => $plan['code']], + [ + 'name' => $plan['name'], + 'currency' => $plan['currency'], + 'amount' => $plan['amount'], + 'period' => $plan['period'] ?? null, + 'status' => $plan['status'] ?? 'active', + 'meta' => $plan['meta'] ?? null, + ] + ); + } + }); + + $after = PricingPlan::orderBy('id')->get()->toArray(); + PricingChange::create([ + 'admin_ref' => $data['admin_ref'] ?? null, + 'before' => $before, + 'after' => $after, + ]); + + return response()->json([ + 'ok' => true, + 'plans' => $after, + ]); + } + + public function reset(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $defaults = config('dewemoji.pricing.defaults', []); + $before = PricingPlan::orderBy('id')->get()->toArray(); + + DB::transaction(function () use ($defaults): void { + PricingPlan::query()->delete(); + foreach ($defaults as $plan) { + PricingPlan::create([ + 'code' => $plan['code'], + 'name' => $plan['name'], + 'currency' => $plan['currency'], + 'amount' => $plan['amount'], + 'period' => $plan['period'], + 'status' => $plan['status'], + 'meta' => $plan['meta'] ?? null, + ]); + } + }); + + $after = PricingPlan::orderBy('id')->get()->toArray(); + PricingChange::create([ + 'admin_ref' => (string) $request->header('X-Admin-Ref', ''), + 'before' => $before, + 'after' => $after, + ]); + + return response()->json([ + 'ok' => true, + 'plans' => $after, + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/AdminSettingsController.php b/app/app/Http/Controllers/Api/V1/AdminSettingsController.php new file mode 100644 index 0000000..d9ed5f5 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminSettingsController.php @@ -0,0 +1,61 @@ +header('X-Admin-Token', '')); + if ($token === '' || $provided === '' || !hash_equals($token, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + return null; + } + + public function index(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $keys = $request->query('keys'); + $all = $this->settings->all(); + if (is_string($keys) && $keys !== '') { + $filter = array_filter(array_map('trim', explode(',', $keys))); + $all = array_intersect_key($all, array_flip($filter)); + } + + return response()->json(['ok' => true, 'settings' => $all]); + } + + public function update(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $payload = $request->input('settings'); + if (!is_array($payload)) { + return response()->json(['ok' => false, 'error' => 'invalid_payload'], 422); + } + + $adminRef = (string) $request->header('X-Admin-Ref', ''); + $this->settings->setMany($payload, $adminRef !== '' ? $adminRef : null); + + return response()->json([ + 'ok' => true, + 'settings' => $this->settings->all(), + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/AdminSubscriptionController.php b/app/app/Http/Controllers/Api/V1/AdminSubscriptionController.php new file mode 100644 index 0000000..06bcc8e --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminSubscriptionController.php @@ -0,0 +1,158 @@ +header('X-Admin-Token', '')); + if ($token === '' || $provided === '' || !hash_equals($token, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + return null; + } + + public function index(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $query = Subscription::query()->with('user:id,email,name,tier'); + + if ($userId = $request->query('user_id')) { + $query->where('user_id', (int) $userId); + } + if ($email = $request->query('email')) { + $query->whereHas('user', fn ($q) => $q->where('email', $email)); + } + if ($status = $request->query('status')) { + $query->where('status', (string) $status); + } + + $limit = min(max((int) $request->query('limit', 50), 1), 200); + $items = $query->orderByDesc('id')->limit($limit)->get(); + + return response()->json(['ok' => true, 'items' => $items]); + } + + public function grant(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $user = $this->resolveUser($request); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + $plan = (string) $request->input('plan', 'personal'); + $status = (string) $request->input('status', 'active'); + $provider = (string) $request->input('provider', 'admin'); + $providerRef = (string) $request->input('provider_ref', ''); + $startedAt = $this->parseDate($request->input('started_at')) ?? now(); + $expiresAt = $this->parseDate($request->input('expires_at')); + + $sub = Subscription::create([ + 'user_id' => $user->id, + 'plan' => $plan, + 'status' => $status, + 'provider' => $provider, + 'provider_ref' => $providerRef !== '' ? $providerRef : null, + 'started_at' => $startedAt, + 'expires_at' => $expiresAt, + ]); + + if ($status === 'active') { + $user->update(['tier' => 'personal']); + } + + return response()->json(['ok' => true, 'subscription' => $sub]); + } + + public function revoke(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $id = (int) $request->input('id', 0); + $now = now(); + + if ($id > 0) { + $sub = Subscription::find($id); + if (!$sub) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + $sub->update(['status' => 'revoked', 'expires_at' => $now]); + $this->syncUserTier($sub->user_id); + return response()->json(['ok' => true, 'revoked' => true]); + } + + $user = $this->resolveUser($request); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + Subscription::where('user_id', $user->id) + ->where('status', 'active') + ->update(['status' => 'revoked', 'expires_at' => $now]); + + $this->syncUserTier($user->id); + + return response()->json(['ok' => true, 'revoked' => true]); + } + + private function resolveUser(Request $request): ?User + { + if ($userId = $request->input('user_id')) { + return User::find((int) $userId); + } + if ($email = $request->input('email')) { + return User::where('email', (string) $email)->first(); + } + + return null; + } + + private function parseDate(mixed $value): ?Carbon + { + if (!$value) { + return null; + } + try { + return Carbon::parse((string) $value); + } catch (\Throwable) { + return null; + } + } + + private function syncUserTier(int $userId): void + { + $active = Subscription::where('user_id', $userId) + ->where('status', 'active') + ->where(function ($q): void { + $q->whereNull('expires_at') + ->orWhere('expires_at', '>', now()); + }) + ->exists(); + + User::where('id', $userId)->update([ + 'tier' => $active ? 'personal' : 'free', + ]); + if (!$active) { + UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]); + } + } +} diff --git a/app/app/Http/Controllers/Api/V1/AdminUserController.php b/app/app/Http/Controllers/Api/V1/AdminUserController.php new file mode 100644 index 0000000..5e0d717 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminUserController.php @@ -0,0 +1,123 @@ +header('X-Admin-Token', '')); + if ($adminToken === '' || $provided === '' || !hash_equals($adminToken, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + + return null; + } + + public function index(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $q = trim((string) $request->query('q', '')); + $limit = max((int) $request->query('limit', 20), 1); + + $query = User::query()->orderByDesc('id'); + if ($q !== '') { + $query->where(function ($sub) use ($q): void { + $sub->where('email', 'like', '%'.$q.'%') + ->orWhere('name', 'like', '%'.$q.'%'); + }); + } + + $items = $query->limit($limit)->get(['id', 'name', 'email', 'tier', 'created_at']); + + return response()->json([ + 'ok' => true, + 'items' => $items, + ]); + } + + public function show(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $email = trim((string) $request->query('email', '')); + $userId = (int) $request->query('user_id', 0); + + $query = User::query(); + if ($email !== '') { + $query->where('email', $email); + } elseif ($userId > 0) { + $query->where('id', $userId); + } else { + return response()->json(['ok' => false, 'error' => 'missing_target'], 400); + } + + /** @var User|null $user */ + $user = $query->first(); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + return response()->json([ + 'ok' => true, + 'user' => [ + 'id' => $user->id, + 'name' => $user->name, + 'email' => $user->email, + 'tier' => $user->tier, + 'created_at' => $user->created_at, + ], + ]); + } + + public function setTier(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $data = $request->validate([ + 'email' => 'nullable|email|max:255', + 'user_id' => 'nullable|integer', + 'tier' => 'required|string|in:free,personal', + ]); + + $query = User::query(); + if (!empty($data['email'])) { + $query->where('email', $data['email']); + } elseif (!empty($data['user_id'])) { + $query->where('id', $data['user_id']); + } else { + return response()->json(['ok' => false, 'error' => 'missing_target'], 400); + } + + /** @var User|null $user */ + $user = $query->first(); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + $user->tier = $data['tier']; + $user->save(); + + return response()->json([ + 'ok' => true, + 'user' => [ + 'id' => $user->id, + 'email' => $user->email, + 'tier' => $user->tier, + ], + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/AdminWebhookController.php b/app/app/Http/Controllers/Api/V1/AdminWebhookController.php new file mode 100644 index 0000000..b6497fb --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/AdminWebhookController.php @@ -0,0 +1,92 @@ +header('X-Admin-Token', '')); + if ($token === '' || $provided === '' || !hash_equals($token, $provided)) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + return null; + } + + public function index(Request $request): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $query = WebhookEvent::query(); + if ($provider = $request->query('provider')) { + $query->where('provider', (string) $provider); + } + if ($status = $request->query('status')) { + $query->where('status', (string) $status); + } + + $limit = min(max((int) $request->query('limit', 50), 1), 200); + $items = $query->orderByDesc('id')->limit($limit)->get(); + + return response()->json(['ok' => true, 'items' => $items]); + } + + public function show(Request $request, int $id): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $item = WebhookEvent::find($id); + if (!$item) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + return response()->json(['ok' => true, 'item' => $item]); + } + + public function replay(Request $request, int $id): JsonResponse + { + if ($res = $this->authorizeAdmin($request)) { + return $res; + } + + $item = WebhookEvent::find($id); + if (!$item) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + $item->update(['status' => 'pending', 'processed_at' => null, 'error' => null]); + + try { + if ($item->provider === 'paypal') { + $this->processor->process((string) ($item->event_type ?? ''), $item->payload ?? []); + } + $item->update([ + 'status' => 'processed', + 'processed_at' => now(), + ]); + } catch (\Throwable $e) { + $item->update([ + 'status' => 'error', + 'error' => $e->getMessage(), + 'processed_at' => now(), + ]); + } + + return response()->json(['ok' => true, 'replayed' => true]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/EmojiApiController.php b/app/app/Http/Controllers/Api/V1/EmojiApiController.php index 94702ce..0866e2a 100644 --- a/app/app/Http/Controllers/Api/V1/EmojiApiController.php +++ b/app/app/Http/Controllers/Api/V1/EmojiApiController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers\Api\V1; use App\Services\Billing\LicenseVerificationService; +use App\Services\Auth\ApiKeyService; +use App\Services\System\SettingsService; use App\Http\Controllers\Controller; use Carbon\Carbon; use Illuminate\Http\JsonResponse; @@ -21,7 +23,8 @@ class EmojiApiController extends Controller private static ?array $dataset = null; public function __construct( - private readonly LicenseVerificationService $verification + private readonly LicenseVerificationService $verification, + private readonly ApiKeyService $apiKeys ) { } @@ -41,6 +44,10 @@ class EmojiApiController extends Controller public function categories(Request $request): JsonResponse { + if ($blocked = $this->enforcePublicAccess($request)) { + return $blocked; + } + $tier = $this->detectTier($request); try { $data = $this->loadData(); @@ -87,6 +94,10 @@ class EmojiApiController extends Controller public function emojis(Request $request): JsonResponse { + if ($blocked = $this->enforcePublicAccess($request)) { + return $blocked; + } + $tier = $this->detectTier($request); try { $data = $this->loadData(); @@ -109,45 +120,7 @@ class EmojiApiController extends Controller : max((int) config('dewemoji.pagination.free_max_limit', 20), 1); $limit = min(max((int) $request->query('limit', $defaultLimit), 1), $maxLimit); - $filtered = array_values(array_filter($items, function (array $item) use ($q, $category, $subSlug): bool { - $itemCategory = trim((string) ($item['category'] ?? '')); - $itemSubcategory = trim((string) ($item['subcategory'] ?? '')); - - if ($category !== '' && strcasecmp($itemCategory, $category) !== 0) { - return false; - } - if ($subSlug !== '' && $this->slugify($itemSubcategory) !== $subSlug) { - return false; - } - if ($q === '') { - return true; - } - - $haystack = strtolower(implode(' ', [ - (string) ($item['emoji'] ?? ''), - (string) ($item['name'] ?? ''), - (string) ($item['slug'] ?? ''), - $itemCategory, - $itemSubcategory, - implode(' ', $item['keywords_en'] ?? []), - implode(' ', $item['keywords_id'] ?? []), - implode(' ', $item['aliases'] ?? []), - implode(' ', $item['shortcodes'] ?? []), - implode(' ', $item['alt_shortcodes'] ?? []), - implode(' ', $item['intent_tags'] ?? []), - ])); - - $tokens = preg_split('/\s+/', strtolower($q)) ?: []; - foreach ($tokens as $token) { - if ($token === '') { - continue; - } - if (!str_contains($haystack, $token)) { - return false; - } - } - return true; - })); + $filtered = $this->filterItems($items, $q, $category, $subSlug); $total = count($filtered); $offset = ($page - 1) * $limit; @@ -170,44 +143,123 @@ class EmojiApiController extends Controller ]); } - if ($tier === self::TIER_FREE && $page === 1) { - $usage = $this->trackDailyUsage($request, $q, $category, $subSlug); - if ($usage['blocked']) { - return $this->jsonWithTier($request, [ - 'ok' => false, - 'error' => 'daily_limit_reached', - 'message' => 'Daily free limit reached. Upgrade to Pro for unlimited usage.', - 'plan' => self::TIER_FREE, - 'usage' => $usage['meta'], - ], $tier, 429, [ - 'X-RateLimit-Limit' => (string) $usage['meta']['limit'], - 'X-RateLimit-Remaining' => '0', - 'X-RateLimit-Reset' => (string) strtotime('tomorrow 00:00:00 UTC'), - 'ETag' => $etag, - 'Cache-Control' => 'public, max-age=120', - ]); - } - - $responsePayload['plan'] = self::TIER_FREE; - $responsePayload['usage'] = $usage['meta']; - - return $this->jsonWithTier($request, $responsePayload, $tier, 200, [ - 'X-RateLimit-Limit' => (string) $usage['meta']['limit'], - 'X-RateLimit-Remaining' => (string) $usage['meta']['remaining'], - 'X-RateLimit-Reset' => (string) strtotime('tomorrow 00:00:00 UTC'), - 'ETag' => $etag, - 'Cache-Control' => 'public, max-age=120', - ]); - } - return $this->jsonWithTier($request, $responsePayload, $tier, 200, [ 'ETag' => $etag, 'Cache-Control' => 'public, max-age=120', ]); } + public function search(Request $request): JsonResponse + { + $private = filter_var($request->query('private', false), FILTER_VALIDATE_BOOL); + if (!$private) { + return $this->emojis($request); + } + + $user = $this->apiKeys->resolveUser($request) ?? $request->user(); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + if ((string) $user->tier !== 'personal') { + return response()->json(['ok' => false, 'error' => 'personal_required'], 403); + } + + $q = trim((string) ($request->query('q', $request->query('query', '')))); + $category = $this->normalizeCategoryFilter((string) $request->query('category', '')); + $subSlug = $this->slugify((string) $request->query('subcategory', '')); + + try { + $data = $this->loadData(); + } catch (RuntimeException $e) { + return $this->jsonWithTier($request, [ + 'error' => 'data_load_failed', + 'message' => $e->getMessage(), + ], self::TIER_FREE, 500); + } + + $items = $data['emojis'] ?? []; + $itemsBySlug = []; + foreach ($items as $item) { + $slug = (string) ($item['slug'] ?? ''); + if ($slug !== '') { + $itemsBySlug[$slug] = $item; + } + } + $filtered = $this->filterItems($items, $q, $category, $subSlug); + $publicBySlug = []; + foreach ($filtered as $item) { + $slug = (string) ($item['slug'] ?? ''); + if ($slug !== '') { + $publicBySlug[$slug] = $item; + } + } + + $privateMatches = []; + if ($q !== '') { + $rows = DB::table('user_keywords') + ->where('user_id', $user->id) + ->whereRaw('LOWER(keyword) LIKE ?', ['%'.strtolower($q).'%']) + ->get(['id', 'emoji_slug', 'keyword', 'lang']); + + foreach ($rows as $row) { + $slug = (string) $row->emoji_slug; + if ($slug === '') { + continue; + } + $privateMatches[$slug] = [ + 'id' => (int) $row->id, + 'keyword' => (string) $row->keyword, + 'lang' => (string) $row->lang, + ]; + } + } + + $tier = self::TIER_PRO; + $merged = []; + foreach ($privateMatches as $slug => $meta) { + $sourceItem = $publicBySlug[$slug] ?? $itemsBySlug[$slug] ?? null; + if ($sourceItem === null) { + continue; + } + $item = $this->transformItem($sourceItem, $tier); + $item['source'] = 'private'; + $item['matched_keyword_id'] = $meta['id'] ?? null; + $item['matched_keyword'] = $meta['keyword']; + $item['matched_lang'] = $meta['lang']; + $merged[$slug] = $item; + } + + foreach ($publicBySlug as $slug => $item) { + if (isset($merged[$slug])) { + continue; + } + $row = $this->transformItem($item, $tier); + $row['source'] = 'public'; + $merged[$slug] = $row; + } + + $mergedItems = array_values($merged); + $page = max((int) $request->query('page', 1), 1); + $limit = max((int) $request->query('limit', 20), 1); + $total = count($mergedItems); + $pageItems = array_slice($mergedItems, ($page - 1) * $limit, $limit); + + return response()->json([ + 'ok' => true, + 'items' => $pageItems, + 'total' => $total, + 'page' => $page, + 'limit' => $limit, + 'plan' => 'personal', + ]); + } + public function emoji(Request $request, ?string $slug = null): JsonResponse { + if ($blocked = $this->enforcePublicAccess($request)) { + return $blocked; + } + $tier = $this->detectTier($request); $slug = trim((string) ($slug ?? $request->query('slug', ''))); if ($slug === '') { @@ -243,6 +295,19 @@ class EmojiApiController extends Controller } $payload = $this->transformEmojiDetail($match, $tier); + $includeUserKeywords = filter_var($request->query('include_user_keywords', false), FILTER_VALIDATE_BOOL); + if ($includeUserKeywords) { + $user = $this->apiKeys->resolveUser($request) ?? $request->user(); + if ($user && (string) $user->tier === 'personal') { + $payload['user_keywords'] = DB::table('user_keywords') + ->where('user_id', $user->id) + ->where('emoji_slug', $slug) + ->orderByDesc('id') + ->get(['id', 'keyword', 'lang']); + } else { + $payload['user_keywords'] = []; + } + } $etag = '"'.sha1(json_encode([$payload, $tier])).'"'; if ($this->isNotModified($request, $etag)) { return $this->jsonWithTier($request, [], $tier, 304, [ @@ -277,6 +342,148 @@ class EmojiApiController extends Controller return self::TIER_FREE; } + private function enforcePublicAccess(Request $request): ?JsonResponse + { + if ($this->hasApiKeyAuth($request)) { + return null; + } + + $config = config('dewemoji.public_access', []); + $settings = app(SettingsService::class); + $maintenanceEnabled = (bool) $settings->get('maintenance_enabled', false); + if ($maintenanceEnabled) { + return $this->jsonWithTier($request, [ + 'ok' => false, + 'error' => 'maintenance', + ], self::TIER_FREE, 503); + } + + $enforceWhitelist = (bool) $settings->get('public_enforce', $config['enforce_whitelist'] ?? false); + $allowedOrigins = $settings->get('public_origins', $config['allowed_origins'] ?? []); + $extensionIds = $settings->get('public_extension_ids', $config['extension_ids'] ?? []); + $limitOverride = $settings->get('public_hourly_limit', $config['hourly_limit'] ?? 0); + + $allowed = $this->isPublicAllowed($request, [ + 'allowed_origins' => $allowedOrigins, + 'extension_ids' => $extensionIds, + ]); + + if ($enforceWhitelist && !$allowed) { + return $this->jsonWithTier($request, [ + 'ok' => false, + 'error' => 'public_access_denied', + ], self::TIER_FREE, 403); + } + + if (!$allowed) { + $limit = max((int) $limitOverride, 0); + if ($limit > 0) { + $usage = $this->trackPublicHourlyUsage($request, $limit); + if ($usage['blocked']) { + return $this->jsonWithTier($request, [ + 'ok' => false, + 'error' => 'public_rate_limited', + 'usage' => $usage['meta'], + ], self::TIER_FREE, 429, [ + 'X-RateLimit-Limit' => (string) $usage['meta']['limit'], + 'X-RateLimit-Remaining' => '0', + 'X-RateLimit-Reset' => (string) $usage['meta']['window_ends_at_unix'], + ]); + } + } + } + + return null; + } + + /** + * @param array $config + */ + private function isPublicAllowed(Request $request, array $config): bool + { + if (app()->environment(['local', 'testing'])) { + return true; + } + + $host = trim((string) $request->getHost()); + if (in_array($host, ['127.0.0.1', 'localhost'], true)) { + return true; + } + + $origin = trim((string) $request->headers->get('Origin', '')); + $allowedOrigins = $config['allowed_origins'] ?? []; + if ($origin !== '' && is_array($allowedOrigins) && in_array($origin, $allowedOrigins, true)) { + return true; + } + + $frontendHeader = trim((string) $request->header('X-Dewemoji-Frontend', '')); + $extensionIds = $config['extension_ids'] ?? []; + if ($frontendHeader !== '' && is_array($extensionIds)) { + foreach ($extensionIds as $id) { + if ($id !== '' && str_contains($frontendHeader, $id)) { + return true; + } + } + } + + $extensionHeader = trim((string) $request->header('X-Extension-Id', '')); + if ($extensionHeader !== '' && is_array($extensionIds)) { + if (in_array($extensionHeader, $extensionIds, true)) { + return true; + } + } + + $userAgent = (string) $request->userAgent(); + if ($userAgent !== '' && is_array($extensionIds)) { + foreach ($extensionIds as $id) { + if ($id !== '' && str_contains($userAgent, $id)) { + return true; + } + } + } + + return false; + } + + private function hasApiKeyAuth(Request $request): bool + { + return $this->apiKeys->resolveUser($request) !== null; + } + + /** + * @return array{blocked:bool,meta:array} + */ + private function trackPublicHourlyUsage(Request $request, int $limit): array + { + $bucket = sha1((string) $request->ip().'|'.(string) $request->userAgent()); + $hourKey = Carbon::now('UTC')->format('YmdH'); + $cacheKey = 'dw_public_hourly_'.$bucket.'_'.$hourKey; + $seconds = max(60, Carbon::now('UTC')->diffInSeconds(Carbon::now('UTC')->addHour()->startOfHour())); + + $current = Cache::get($cacheKey, 0); + if (!is_int($current)) { + $current = (int) $current; + } + + $current++; + Cache::put($cacheKey, $current, $seconds); + + $blocked = $current > $limit; + $windowEnds = Carbon::now('UTC')->addHour()->startOfHour(); + + return [ + 'blocked' => $blocked, + 'meta' => [ + 'used' => min($current, $limit), + 'limit' => $limit, + 'remaining' => max(0, $limit - $current), + 'window' => 'hourly', + 'window_ends_at' => $windowEnds->toIso8601String(), + 'window_ends_at_unix' => $windowEnds->timestamp, + ], + ]; + } + private function isNotModified(Request $request, string $etag): bool { $ifNoneMatch = trim((string) $request->header('If-None-Match', '')); @@ -329,6 +536,53 @@ class EmojiApiController extends Controller return trim($value, '-'); } + /** + * @param array> $items + * @return array> + */ + private function filterItems(array $items, string $q, string $category, string $subSlug): array + { + return array_values(array_filter($items, function (array $item) use ($q, $category, $subSlug): bool { + $itemCategory = trim((string) ($item['category'] ?? '')); + $itemSubcategory = trim((string) ($item['subcategory'] ?? '')); + + if ($category !== '' && strcasecmp($itemCategory, $category) !== 0) { + return false; + } + if ($subSlug !== '' && $this->slugify($itemSubcategory) !== $subSlug) { + return false; + } + if ($q === '') { + return true; + } + + $haystack = strtolower(implode(' ', [ + (string) ($item['emoji'] ?? ''), + (string) ($item['name'] ?? ''), + (string) ($item['slug'] ?? ''), + $itemCategory, + $itemSubcategory, + implode(' ', $item['keywords_en'] ?? []), + implode(' ', $item['keywords_id'] ?? []), + implode(' ', $item['aliases'] ?? []), + implode(' ', $item['shortcodes'] ?? []), + implode(' ', $item['alt_shortcodes'] ?? []), + implode(' ', $item['intent_tags'] ?? []), + ])); + + $tokens = preg_split('/\s+/', strtolower($q)) ?: []; + foreach ($tokens as $token) { + if ($token === '') { + continue; + } + if (!str_contains($haystack, $token)) { + return false; + } + } + return true; + })); + } + /** * @param array $item * @return array diff --git a/app/app/Http/Controllers/Api/V1/ExtensionController.php b/app/app/Http/Controllers/Api/V1/ExtensionController.php new file mode 100644 index 0000000..ac9bb91 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/ExtensionController.php @@ -0,0 +1,207 @@ +|null */ + private static ?array $dataset = null; + + public function __construct(private readonly ExtensionVerificationService $verifier) + { + } + + public function verify(Request $request): JsonResponse + { + $token = trim((string) $request->header('X-Extension-Token', '')); + $expected = config('dewemoji.public_access.extension_ids', []); + $ok = $this->verifier->verifyToken($token, is_array($expected) ? $expected : []); + + return response()->json([ + 'ok' => $ok, + 'verified' => $ok, + ], $ok ? 200 : 403); + } + + public function search(Request $request): JsonResponse + { + $token = trim((string) $request->header('X-Extension-Token', '')); + $expected = config('dewemoji.public_access.extension_ids', []); + $ok = $this->verifier->verifyToken($token, is_array($expected) ? $expected : []); + if (!$ok) { + return response()->json(['ok' => false, 'error' => 'extension_unverified'], 403); + } + + try { + $data = $this->loadData(); + } catch (RuntimeException $e) { + return response()->json([ + 'ok' => false, + 'error' => 'data_load_failed', + 'message' => $e->getMessage(), + ], 500); + } + + $items = $data['emojis'] ?? []; + $q = trim((string) ($request->query('q', $request->query('query', '')))); + $category = $this->normalizeCategoryFilter((string) $request->query('category', '')); + $subSlug = $this->slugify((string) $request->query('subcategory', '')); + $page = max((int) $request->query('page', 1), 1); + + $defaultLimit = max((int) config('dewemoji.pagination.default_limit', 20), 1); + $maxLimit = max((int) config('dewemoji.pagination.free_max_limit', 20), 1); + $limit = min(max((int) $request->query('limit', $defaultLimit), 1), $maxLimit); + + $filtered = $this->filterItems($items, $q, $category, $subSlug); + $total = count($filtered); + $offset = ($page - 1) * $limit; + $pageItems = array_slice($filtered, $offset, $limit); + + return response()->json([ + 'ok' => true, + 'items' => array_map(fn (array $item): array => $this->transformItem($item), $pageItems), + 'total' => $total, + 'page' => $page, + 'limit' => $limit, + 'plan' => 'free', + ]); + } + + /** + * @return array + */ + private function loadData(): array + { + if (self::$dataset !== null) { + return self::$dataset; + } + + $path = (string) config('dewemoji.data_path'); + if (!is_file($path)) { + throw new RuntimeException('Emoji dataset file was not found at: '.$path); + } + + $raw = file_get_contents($path); + if ($raw === false) { + throw new RuntimeException('Emoji dataset file could not be read.'); + } + + $decoded = json_decode($raw, true); + if (!is_array($decoded)) { + throw new RuntimeException('Emoji dataset JSON is invalid.'); + } + + self::$dataset = $decoded; + return self::$dataset; + } + + private function normalizeCategoryFilter(string $category): string + { + $value = strtolower(trim($category)); + if ($value === '' || $value === 'all') { + return ''; + } + + $map = [ + 'all' => 'all', + 'smileys' => 'Smileys & Emotion', + 'people' => 'People & Body', + 'animals' => 'Animals & Nature', + 'food' => 'Food & Drink', + 'travel' => 'Travel & Places', + 'activities' => 'Activities', + 'objects' => 'Objects', + 'symbols' => 'Symbols', + 'flags' => 'Flags', + ]; + return $map[$value] ?? $category; + } + + private function slugify(string $text): string + { + $value = strtolower(trim($text)); + $value = str_replace('&', 'and', $value); + $value = preg_replace('/[^a-z0-9]+/', '-', $value) ?? ''; + return trim($value, '-'); + } + + /** + * @param array> $items + * @return array> + */ + private function filterItems(array $items, string $q, string $category, string $subSlug): array + { + return array_values(array_filter($items, function (array $item) use ($q, $category, $subSlug): bool { + $itemCategory = trim((string) ($item['category'] ?? '')); + $itemSubcategory = trim((string) ($item['subcategory'] ?? '')); + + if ($category !== '' && strcasecmp($itemCategory, $category) !== 0) { + return false; + } + if ($subSlug !== '' && $this->slugify($itemSubcategory) !== $subSlug) { + return false; + } + if ($q === '') { + return true; + } + + $haystack = strtolower(implode(' ', [ + (string) ($item['emoji'] ?? ''), + (string) ($item['name'] ?? ''), + (string) ($item['slug'] ?? ''), + $itemCategory, + $itemSubcategory, + implode(' ', $item['keywords_en'] ?? []), + implode(' ', $item['keywords_id'] ?? []), + implode(' ', $item['aliases'] ?? []), + implode(' ', $item['shortcodes'] ?? []), + implode(' ', $item['alt_shortcodes'] ?? []), + implode(' ', $item['intent_tags'] ?? []), + ])); + + $tokens = preg_split('/\s+/', strtolower($q)) ?: []; + foreach ($tokens as $token) { + if ($token === '') { + continue; + } + if (!str_contains($haystack, $token)) { + return false; + } + } + return true; + })); + } + + /** + * @param array $item + * @return array + */ + private function transformItem(array $item): array + { + return [ + 'emoji' => (string) ($item['emoji'] ?? ''), + 'name' => (string) ($item['name'] ?? ''), + 'slug' => (string) ($item['slug'] ?? ''), + 'category' => (string) ($item['category'] ?? ''), + 'subcategory' => (string) ($item['subcategory'] ?? ''), + 'supports_skin_tone' => (bool) ($item['supports_skin_tone'] ?? false), + 'summary' => $this->summary((string) ($item['description'] ?? ''), 150), + ]; + } + + private function summary(string $text, int $max): string + { + $text = trim(preg_replace('/\s+/', ' ', strip_tags($text)) ?? ''); + if (mb_strlen($text) <= $max) { + return $text; + } + + return rtrim(mb_substr($text, 0, $max - 1), " ,.;:-").'…'; + } +} diff --git a/app/app/Http/Controllers/Api/V1/PaypalWebhookController.php b/app/app/Http/Controllers/Api/V1/PaypalWebhookController.php new file mode 100644 index 0000000..82670fa --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/PaypalWebhookController.php @@ -0,0 +1,83 @@ +all(); + $eventType = (string) ($payload['event_type'] ?? ''); + $eventId = (string) ($payload['id'] ?? ''); + + $signatureOk = $this->verifySignature($request); + + if ($eventId !== '' && WebhookEvent::where('provider', 'paypal')->where('event_id', $eventId)->exists()) { + return response()->json(['ok' => true, 'duplicate' => true]); + } + + $event = WebhookEvent::create([ + 'provider' => 'paypal', + 'event_id' => $eventId !== '' ? $eventId : null, + 'event_type' => $eventType !== '' ? $eventType : null, + 'status' => $signatureOk ? 'received' : 'error', + 'payload' => $payload, + 'headers' => $this->extractHeaders($request), + 'received_at' => now(), + 'error' => $signatureOk ? null : 'signature_unverified', + ]); + + if (!$signatureOk) { + return response()->json(['ok' => true, 'signature' => 'unverified']); + } + + try { + $this->processor->process($eventType, $payload); + $event->update([ + 'status' => 'processed', + 'processed_at' => now(), + ]); + } catch (\Throwable $e) { + $event->update([ + 'status' => 'error', + 'error' => $e->getMessage(), + 'processed_at' => now(), + ]); + } + + return response()->json(['ok' => true]); + } + + private function verifySignature(Request $request): bool + { + // TODO: Implement PayPal signature verification using transmission headers + webhook ID. + // For now this returns true to allow local testing. + return true; + } + + /** + * @return array + */ + private function extractHeaders(Request $request): array + { + $headers = [ + 'paypal-transmission-id' => (string) $request->header('PayPal-Transmission-Id', ''), + 'paypal-transmission-sig' => (string) $request->header('PayPal-Transmission-Sig', ''), + 'paypal-cert-url' => (string) $request->header('PayPal-Cert-Url', ''), + 'paypal-auth-algo' => (string) $request->header('PayPal-Auth-Algo', ''), + 'paypal-transmission-time' => (string) $request->header('PayPal-Transmission-Time', ''), + ]; + + return array_filter($headers, fn (string $value): bool => $value !== ''); + } +} diff --git a/app/app/Http/Controllers/Api/V1/PricingController.php b/app/app/Http/Controllers/Api/V1/PricingController.php new file mode 100644 index 0000000..79b7192 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/PricingController.php @@ -0,0 +1,22 @@ +orderBy('id') + ->get(['code', 'name', 'currency', 'amount', 'period', 'meta']); + + return response()->json([ + 'ok' => true, + 'plans' => $plans, + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/UserController.php b/app/app/Http/Controllers/Api/V1/UserController.php new file mode 100644 index 0000000..e57bc24 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/UserController.php @@ -0,0 +1,171 @@ +validate([ + 'email' => 'required|email|max:255|unique:users,email', + 'password' => 'required|min:8|max:255', + 'name' => 'nullable|string|max:120', + ]); + + $name = $data['name'] ?? strtok($data['email'], '@'); + $user = User::create([ + 'name' => $name ?: 'User', + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + 'tier' => 'free', + ]); + + $issued = null; + if ((string) $user->tier === 'personal') { + $issued = $this->keys->issueKey($user, 'default'); + } + + return response()->json([ + 'ok' => true, + 'user' => [ + 'id' => $user->id, + 'email' => $user->email, + 'tier' => $user->tier, + ], + 'api_key' => $issued['plain'] ?? null, + ]); + } + + public function login(Request $request): JsonResponse + { + $data = $request->validate([ + 'email' => 'required|email|max:255', + 'password' => 'required|string|max:255', + ]); + + /** @var User|null $user */ + $user = User::where('email', $data['email'])->first(); + if (!$user || !Hash::check($data['password'], $user->password)) { + return response()->json([ + 'ok' => false, + 'error' => 'invalid_credentials', + ], 401); + } + + $issued = null; + if ((string) $user->tier === 'personal') { + $issued = $this->keys->issueKey($user, 'login'); + } + + return response()->json([ + 'ok' => true, + 'user' => [ + 'id' => $user->id, + 'email' => $user->email, + 'tier' => $user->tier, + ], + 'api_key' => $issued['plain'] ?? null, + ]); + } + + public function logout(Request $request): JsonResponse + { + $key = $this->keys->parseKey($request); + if ($key === '') { + return response()->json(['ok' => true]); + } + + $hash = $this->keys->hashKey($key); + UserApiKey::where('key_hash', $hash)->update([ + 'revoked_at' => Carbon::now(), + ]); + + return response()->json(['ok' => true]); + } + + public function listApiKeys(Request $request): JsonResponse + { + $user = $this->keys->resolveUser($request); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + + $items = UserApiKey::where('user_id', $user->id) + ->orderByDesc('id') + ->get() + ->map(fn (UserApiKey $key) => [ + 'id' => $key->id, + 'prefix' => $key->key_prefix, + 'name' => $key->name, + 'created_at' => $key->created_at, + 'last_used_at' => $key->last_used_at, + 'revoked_at' => $key->revoked_at, + ]); + + return response()->json([ + 'ok' => true, + 'items' => $items, + ]); + } + + public function createApiKey(Request $request): JsonResponse + { + $user = $this->keys->resolveUser($request); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + if ((string) $user->tier !== 'personal') { + return response()->json(['ok' => false, 'error' => 'personal_required'], 403); + } + + $data = $request->validate([ + 'name' => 'nullable|string|max:100', + ]); + + $issued = $this->keys->issueKey($user, $data['name'] ?? null); + + return response()->json([ + 'ok' => true, + 'api_key' => $issued['plain'], + 'key' => [ + 'id' => $issued['record']->id, + 'prefix' => $issued['record']->key_prefix, + 'name' => $issued['record']->name, + 'created_at' => $issued['record']->created_at, + ], + ]); + } + + public function revokeApiKey(Request $request, string $key): JsonResponse + { + $user = $this->keys->resolveUser($request); + if (!$user) { + return response()->json(['ok' => false, 'error' => 'unauthorized'], 401); + } + + $hash = $this->keys->hashKey($key); + $updated = UserApiKey::where('user_id', $user->id) + ->where('key_hash', $hash) + ->whereNull('revoked_at') + ->update(['revoked_at' => Carbon::now()]); + + return response()->json([ + 'ok' => true, + 'revoked' => $updated > 0, + ]); + } +} diff --git a/app/app/Http/Controllers/Api/V1/UserKeywordController.php b/app/app/Http/Controllers/Api/V1/UserKeywordController.php new file mode 100644 index 0000000..4325325 --- /dev/null +++ b/app/app/Http/Controllers/Api/V1/UserKeywordController.php @@ -0,0 +1,210 @@ +keys->resolveUser($request); + if (!$user) { + return ['error' => 'unauthorized', 'status' => 401]; + } + + return ['user' => $user]; + } + + public function index(Request $request): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $user = $check['user']; + $items = UserKeyword::where('user_id', $user->id) + ->orderByDesc('id') + ->get(['id', 'emoji_slug', 'keyword', 'lang', 'created_at', 'updated_at']); + + return response()->json(['ok' => true, 'items' => $items]); + } + + public function store(Request $request): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $data = $request->validate([ + 'emoji_slug' => 'required|string|max:120', + 'keyword' => 'required|string|max:200', + 'lang' => 'nullable|string|max:10', + ]); + + $lang = $data['lang'] ?? 'und'; + $user = $check['user']; + $limit = $this->keywordLimitFor($user); + if ($limit !== null) { + $exists = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $data['emoji_slug']) + ->where('keyword', $data['keyword']) + ->exists(); + if (!$exists) { + $count = UserKeyword::where('user_id', $user->id)->count(); + if ($count >= $limit) { + return response()->json(['ok' => false, 'error' => 'free_limit_reached', 'limit' => $limit], 403); + } + } + } + + $item = UserKeyword::updateOrCreate( + [ + 'user_id' => $user->id, + 'emoji_slug' => $data['emoji_slug'], + 'keyword' => $data['keyword'], + ], + [ + 'lang' => $lang, + ] + ); + + return response()->json(['ok' => true, 'item' => $item]); + } + + public function destroy(Request $request, int $id): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $deleted = UserKeyword::where('user_id', $check['user']->id) + ->where('id', $id) + ->delete(); + + return response()->json(['ok' => true, 'deleted' => $deleted > 0]); + } + + public function update(Request $request, int $id): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $data = $request->validate([ + 'emoji_slug' => 'required|string|max:120', + 'keyword' => 'required|string|max:200', + 'lang' => 'nullable|string|max:10', + ]); + + $item = UserKeyword::where('user_id', $check['user']->id) + ->where('id', $id) + ->first(); + + if (!$item) { + return response()->json(['ok' => false, 'error' => 'not_found'], 404); + } + + $duplicate = UserKeyword::where('user_id', $check['user']->id) + ->where('emoji_slug', $data['emoji_slug']) + ->where('keyword', $data['keyword']) + ->first(); + + if ($duplicate && $duplicate->id !== $item->id) { + $item->delete(); + $item = $duplicate; + } else { + $item->update([ + 'emoji_slug' => $data['emoji_slug'], + 'keyword' => $data['keyword'], + 'lang' => $data['lang'] ?? 'und', + ]); + } + + return response()->json(['ok' => true, 'item' => $item]); + } + + public function export(Request $request): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $items = UserKeyword::where('user_id', $check['user']->id) + ->orderByDesc('id') + ->get(['emoji_slug', 'keyword', 'lang']); + + return response()->json(['ok' => true, 'items' => $items]); + } + + public function import(Request $request): JsonResponse + { + $check = $this->ensureUser($request); + if (!isset($check['user'])) { + return response()->json(['ok' => false, 'error' => $check['error']], $check['status']); + } + + $data = $request->validate([ + 'items' => 'required|array', + 'items.*.emoji_slug' => 'required|string|max:120', + 'items.*.keyword' => 'required|string|max:200', + 'items.*.lang' => 'nullable|string|max:10', + ]); + + $count = 0; + $skipped = 0; + $user = $check['user']; + $limit = $this->keywordLimitFor($user); + $current = UserKeyword::where('user_id', $user->id)->count(); + foreach ($data['items'] as $row) { + $exists = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $row['emoji_slug']) + ->where('keyword', $row['keyword']) + ->exists(); + + if (!$exists && $limit !== null && $current >= $limit) { + $skipped += 1; + continue; + } + UserKeyword::updateOrCreate( + [ + 'user_id' => $user->id, + 'emoji_slug' => $row['emoji_slug'], + 'keyword' => $row['keyword'], + ], + [ + 'lang' => $row['lang'] ?? 'und', + ] + ); + if (!$exists) { + $current += 1; + } + $count += 1; + } + + return response()->json(['ok' => true, 'imported' => $count, 'skipped' => $skipped]); + } + + private function keywordLimitFor($user): ?int + { + if ((string) ($user->tier ?? 'free') === 'personal') { + return null; + } + + return (int) config('dewemoji.pagination.free_max_limit', 20); + } +} diff --git a/app/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/app/app/Http/Controllers/Auth/AuthenticatedSessionController.php new file mode 100644 index 0000000..dbde383 --- /dev/null +++ b/app/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -0,0 +1,47 @@ +authenticate(); + + $request->session()->regenerate(); + + return redirect()->intended(route('dashboard.overview', absolute: false)); + } + + /** + * Destroy an authenticated session. + */ + public function destroy(Request $request): RedirectResponse + { + Auth::guard('web')->logout(); + + $request->session()->invalidate(); + + $request->session()->regenerateToken(); + + return redirect('/'); + } +} diff --git a/app/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/app/app/Http/Controllers/Auth/ConfirmablePasswordController.php new file mode 100644 index 0000000..d9459cc --- /dev/null +++ b/app/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -0,0 +1,40 @@ +validate([ + 'email' => $request->user()->email, + 'password' => $request->password, + ])) { + throw ValidationException::withMessages([ + 'password' => __('auth.password'), + ]); + } + + $request->session()->put('auth.password_confirmed_at', time()); + + return redirect()->intended(route('dashboard.overview', absolute: false)); + } +} diff --git a/app/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/app/app/Http/Controllers/Auth/EmailVerificationNotificationController.php new file mode 100644 index 0000000..6ff1f70 --- /dev/null +++ b/app/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -0,0 +1,24 @@ +user()->hasVerifiedEmail()) { + return redirect()->intended(route('dashboard.overview', absolute: false)); + } + + $request->user()->sendEmailVerificationNotification(); + + return back()->with('status', 'verification-link-sent'); + } +} diff --git a/app/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/app/app/Http/Controllers/Auth/EmailVerificationPromptController.php new file mode 100644 index 0000000..e7aca89 --- /dev/null +++ b/app/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -0,0 +1,21 @@ +user()->hasVerifiedEmail() + ? redirect()->intended(route('dashboard.overview', absolute: false)) + : view('auth.verify-email'); + } +} diff --git a/app/app/Http/Controllers/Auth/NewPasswordController.php b/app/app/Http/Controllers/Auth/NewPasswordController.php new file mode 100644 index 0000000..e8368bd --- /dev/null +++ b/app/app/Http/Controllers/Auth/NewPasswordController.php @@ -0,0 +1,62 @@ + $request]); + } + + /** + * Handle an incoming new password request. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function store(Request $request): RedirectResponse + { + $request->validate([ + 'token' => ['required'], + 'email' => ['required', 'email'], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $status = Password::reset( + $request->only('email', 'password', 'password_confirmation', 'token'), + function (User $user) use ($request) { + $user->forceFill([ + 'password' => Hash::make($request->password), + 'remember_token' => Str::random(60), + ])->save(); + + event(new PasswordReset($user)); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $status == Password::PASSWORD_RESET + ? redirect()->route('login')->with('status', __($status)) + : back()->withInput($request->only('email')) + ->withErrors(['email' => __($status)]); + } +} diff --git a/app/app/Http/Controllers/Auth/PasswordController.php b/app/app/Http/Controllers/Auth/PasswordController.php new file mode 100644 index 0000000..6916409 --- /dev/null +++ b/app/app/Http/Controllers/Auth/PasswordController.php @@ -0,0 +1,29 @@ +validateWithBag('updatePassword', [ + 'current_password' => ['required', 'current_password'], + 'password' => ['required', Password::defaults(), 'confirmed'], + ]); + + $request->user()->update([ + 'password' => Hash::make($validated['password']), + ]); + + return back()->with('status', 'password-updated'); + } +} diff --git a/app/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/app/Http/Controllers/Auth/PasswordResetLinkController.php new file mode 100644 index 0000000..bf1ebfa --- /dev/null +++ b/app/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -0,0 +1,44 @@ +validate([ + 'email' => ['required', 'email'], + ]); + + // We will send the password reset link to this user. Once we have attempted + // to send the link, we will examine the response then see the message we + // need to show to the user. Finally, we'll send out a proper response. + $status = Password::sendResetLink( + $request->only('email') + ); + + return $status == Password::RESET_LINK_SENT + ? back()->with('status', __($status)) + : back()->withInput($request->only('email')) + ->withErrors(['email' => __($status)]); + } +} diff --git a/app/app/Http/Controllers/Auth/RegisteredUserController.php b/app/app/Http/Controllers/Auth/RegisteredUserController.php new file mode 100644 index 0000000..2773da2 --- /dev/null +++ b/app/app/Http/Controllers/Auth/RegisteredUserController.php @@ -0,0 +1,54 @@ +validate([ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($request->password), + ]); + + event(new Registered($user)); + if ($user instanceof MustVerifyEmail && ! $user->hasVerifiedEmail()) { + $user->sendEmailVerificationNotification(); + } + + Auth::login($user); + + return redirect(route('dashboard.overview', absolute: false)); + } +} diff --git a/app/app/Http/Controllers/Auth/VerifyEmailController.php b/app/app/Http/Controllers/Auth/VerifyEmailController.php new file mode 100644 index 0000000..2d695d6 --- /dev/null +++ b/app/app/Http/Controllers/Auth/VerifyEmailController.php @@ -0,0 +1,27 @@ +user()->hasVerifiedEmail()) { + return redirect()->intended(route('dashboard.overview', absolute: false).'?verified=1'); + } + + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } + + return redirect()->intended(route('dashboard.overview', absolute: false).'?verified=1'); + } +} diff --git a/app/app/Http/Controllers/Billing/PakasirController.php b/app/app/Http/Controllers/Billing/PakasirController.php new file mode 100644 index 0000000..2dff61a --- /dev/null +++ b/app/app/Http/Controllers/Billing/PakasirController.php @@ -0,0 +1,240 @@ +validate([ + 'plan_code' => 'required|string|in:personal_monthly,personal_annual,personal_lifetime', + ]); + + $user = $request->user(); + if (!$user) { + return response()->json(['error' => 'auth_required'], 401); + } + + $config = config('dewemoji.billing.providers.pakasir', []); + $enabled = (bool) ($config['enabled'] ?? false); + $apiBase = rtrim((string) ($config['api_base'] ?? ''), '/'); + $apiKey = (string) ($config['api_key'] ?? ''); + $project = (string) ($config['project'] ?? ''); + $timeout = (int) ($config['timeout'] ?? 10); + + if (!$enabled || $apiBase === '' || $apiKey === '' || $project === '') { + return response()->json(['error' => 'pakasir_not_configured'], 422); + } + + $amountIdr = $this->resolvePlanAmountIdr($data['plan_code']); + if ($amountIdr <= 0) { + return response()->json(['error' => 'invalid_plan_amount'], 422); + } + + Subscription::where('user_id', $user->id) + ->where('provider', 'pakasir') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + Order::where('user_id', $user->id) + ->where('provider', 'pakasir') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + Payment::where('user_id', $user->id) + ->where('provider', 'pakasir') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + + $order = Order::create([ + 'user_id' => $user->id, + 'plan_code' => $data['plan_code'], + 'type' => $data['plan_code'] === 'personal_lifetime' ? 'one_time' : 'subscription', + 'currency' => 'IDR', + 'amount' => $amountIdr, + 'status' => 'pending', + 'provider' => 'pakasir', + ]); + + $orderRef = 'DW-'.$order->id.'-'.now()->format('ymdHis'); + $payload = [ + 'project' => $project, + 'order_id' => $orderRef, + 'amount' => $amountIdr, + 'api_key' => $apiKey, + 'description' => 'Dewemoji '.$data['plan_code'].' for '.$user->email, + ]; + + $endpoint = $apiBase.'/api/transactioncreate/qris'; + $res = Http::timeout($timeout)->post($endpoint, $payload); + + if (!$res->ok()) { + Log::warning('Pakasir create transaction failed', ['body' => $res->body()]); + return response()->json(['error' => 'pakasir_create_failed'], 502); + } + + $body = $res->json(); + $payment = is_array($body['payment'] ?? null) ? $body['payment'] : $body; + $paymentNumber = (string) ($payment['payment_number'] ?? ''); + $status = (string) ($payment['status'] ?? 'pending'); + $expiredAt = (string) ($payment['expired_at'] ?? ''); + $totalPayment = (int) ($payment['total_payment'] ?? $amountIdr); + + $order->update([ + 'provider_ref' => $orderRef, + 'status' => $status === 'success' ? 'pending' : 'pending', + ]); + + Payment::create([ + 'user_id' => $user->id, + 'order_id' => $order->id, + 'provider' => 'pakasir', + 'type' => $data['plan_code'] === 'personal_lifetime' ? 'one_time' : 'subscription', + 'plan_code' => $data['plan_code'], + 'currency' => 'IDR', + 'amount' => $amountIdr, + 'status' => 'pending', + 'provider_ref' => $paymentNumber !== '' ? $paymentNumber : $orderRef, + 'raw_payload' => $body, + ]); + + return response()->json([ + 'ok' => true, + 'order_id' => $orderRef, + 'payment_number' => $paymentNumber, + 'amount' => $amountIdr, + 'total_payment' => $totalPayment, + 'expired_at' => $expiredAt, + 'status' => $status, + ]); + } + + public function cancelPending(Request $request): JsonResponse + { + $user = $request->user(); + if (!$user) { + return response()->json(['error' => 'auth_required'], 401); + } + + $orderRef = (string) $request->input('order_id', ''); + + $orderQuery = Order::where('user_id', $user->id) + ->where('provider', 'pakasir') + ->where('status', 'pending'); + + if ($orderRef !== '') { + $orderQuery->where('provider_ref', $orderRef); + } + + $order = $orderQuery->orderByDesc('id')->first(); + if (!$order) { + return response()->json(['ok' => true, 'cancelled' => false]); + } + + $order->update(['status' => 'cancelled']); + Payment::where('order_id', $order->id)->where('status', 'pending')->update(['status' => 'cancelled']); + Subscription::where('user_id', $user->id) + ->where('provider', 'pakasir') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + + return response()->json(['ok' => true, 'cancelled' => true]); + } + + public function webhook(Request $request): JsonResponse + { + $payload = $request->all(); + $eventId = (string) ($payload['id'] ?? $payload['event_id'] ?? Str::uuid()); + $eventType = (string) ($payload['event_type'] ?? $payload['status'] ?? 'event'); + + WebhookEvent::create([ + 'provider' => 'pakasir', + 'event_id' => $eventId, + 'event_type' => $eventType, + 'status' => 'received', + 'payload' => $payload, + 'headers' => $request->headers->all(), + 'received_at' => now(), + ]); + + $this->handlePakasirPayload($payload); + + return response()->json(['ok' => true]); + } + + private function handlePakasirPayload(array $payload): void + { + $status = strtolower((string) ($payload['status'] ?? '')); + if (!in_array($status, ['paid', 'success', 'settlement', 'completed'], true)) { + return; + } + + $orderId = (string) ($payload['order_id'] ?? ''); + if ($orderId === '') { + return; + } + + $order = Order::where('provider', 'pakasir')->where('provider_ref', $orderId)->first(); + if (!$order) { + return; + } + + $order->update(['status' => 'paid']); + Payment::where('order_id', $order->id)->update(['status' => 'paid']); + + $user = User::find($order->user_id); + if (!$user) { + return; + } + + $expiresAt = null; + if ($order->plan_code === 'personal_monthly') { + $expiresAt = now()->addMonth(); + } elseif ($order->plan_code === 'personal_annual') { + $expiresAt = now()->addYear(); + } + + Subscription::updateOrCreate( + [ + 'provider' => 'pakasir', + 'provider_ref' => $orderId, + ], + [ + 'user_id' => $user->id, + 'plan' => $order->plan_code, + 'status' => 'active', + 'started_at' => now(), + 'expires_at' => $expiresAt, + ] + ); + + User::where('id', $user->id)->update(['tier' => 'personal']); + } + + private function resolvePlanAmountIdr(string $planCode): int + { + $plan = PricingPlan::where('code', $planCode)->where('status', 'active')->first(); + if ($plan) { + return (int) $plan->amount; + } + + $defaults = collect(config('dewemoji.pricing.defaults', []))->keyBy('code'); + $fallback = $defaults->get($planCode); + if (!$fallback) { + return 0; + } + + return (int) ($fallback['amount'] ?? 0); + } +} diff --git a/app/app/Http/Controllers/Billing/PayPalController.php b/app/app/Http/Controllers/Billing/PayPalController.php new file mode 100644 index 0000000..36d49e8 --- /dev/null +++ b/app/app/Http/Controllers/Billing/PayPalController.php @@ -0,0 +1,336 @@ +validate([ + 'plan_code' => 'required|string|in:personal_monthly,personal_annual', + ]); + + $user = $request->user(); + if (!$user) { + return response()->json(['error' => 'auth_required'], 401); + } + + $mode = $this->billingMode(); + if (!$this->paypalConfigured($mode)) { + return response()->json(['error' => 'paypal_not_configured'], 422); + } + $planId = $this->resolvePlanId($data['plan_code'], $mode); + if (!$planId) { + return response()->json(['error' => 'paypal_plan_missing'], 422); + } + + $token = $this->getAccessToken($mode); + if (!$token) { + return response()->json(['error' => 'paypal_auth_failed'], 502); + } + + $appUrl = rtrim(config('app.url'), '/'); + $payload = [ + 'plan_id' => $planId, + 'subscriber' => [ + 'name' => [ + 'given_name' => $user->name ?? 'User', + 'surname' => 'Dewemoji', + ], + 'email_address' => $user->email, + ], + 'application_context' => [ + 'brand_name' => 'Dewemoji', + 'locale' => 'en-US', + 'user_action' => 'SUBSCRIBE_NOW', + 'return_url' => $appUrl.'/billing/paypal/return?status=success', + 'cancel_url' => $appUrl.'/billing/paypal/return?status=cancel', + ], + ]; + + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/billing/subscriptions', $payload); + + $body = $res->json(); + $subscriptionId = $body['id'] ?? null; + $approveUrl = collect($body['links'] ?? [])->firstWhere('rel', 'approve')['href'] ?? null; + + if (!$subscriptionId || !$approveUrl) { + if (!$res->ok()) { + Log::warning('PayPal create subscription failed', [ + 'status' => $res->status(), + 'body' => $res->body(), + ]); + } else { + Log::warning('PayPal create subscription missing approve link', [ + 'status' => $res->status(), + 'body' => $res->body(), + ]); + } + return response()->json(['error' => 'paypal_invalid_response'], 502); + } + + $amountUsd = $this->resolvePlanAmountUsd($data['plan_code']); + + Subscription::where('user_id', $user->id) + ->where('provider', 'paypal') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + Order::where('user_id', $user->id) + ->where('provider', 'paypal') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + Payment::where('user_id', $user->id) + ->where('provider', 'paypal') + ->where('status', 'pending') + ->update(['status' => 'cancelled']); + + $order = Order::create([ + 'user_id' => $user->id, + 'plan_code' => $data['plan_code'], + 'type' => 'subscription', + 'currency' => 'USD', + 'amount' => $amountUsd, + 'status' => 'pending', + 'provider' => 'paypal', + 'provider_ref' => $subscriptionId, + ]); + + Payment::create([ + 'user_id' => $user->id, + 'order_id' => $order->id, + 'provider' => 'paypal', + 'type' => 'subscription', + 'plan_code' => $data['plan_code'], + 'currency' => 'USD', + 'amount' => $amountUsd, + 'status' => 'pending', + 'provider_ref' => $subscriptionId, + 'raw_payload' => $body, + ]); + + Subscription::firstOrCreate([ + 'provider' => 'paypal', + 'provider_ref' => $subscriptionId, + ], [ + 'user_id' => $user->id, + 'plan' => $data['plan_code'], + 'status' => 'pending', + 'started_at' => now(), + ]); + + return response()->json(['approve_url' => $approveUrl]); + } + + public function return(Request $request): RedirectResponse + { + $status = (string) $request->query('status', 'success'); + return redirect()->route('dashboard.billing', ['status' => $status]); + } + + public function webhook(Request $request): JsonResponse + { + $payload = $request->all(); + $eventId = (string) ($payload['id'] ?? ''); + $eventType = (string) ($payload['event_type'] ?? ''); + + $mode = config('dewemoji.billing.mode', 'sandbox'); + $webhookId = config("dewemoji.billing.providers.paypal.webhook_ids.{$mode}"); + + if ($webhookId) { + $verified = $this->verifySignature($mode, $webhookId, $payload, $request); + if (!$verified) { + return response()->json(['error' => 'invalid_signature'], 401); + } + } + + $event = WebhookEvent::create([ + 'provider' => 'paypal', + 'event_id' => $eventId ?: (string) Str::uuid(), + 'event_type' => $eventType, + 'status' => 'received', + 'payload' => $payload, + 'headers' => $request->headers->all(), + 'received_at' => now(), + ]); + + try { + $processed = $this->processPayPalEvent($payload); + $event->update([ + 'status' => $processed ? 'processed' : 'received', + 'processed_at' => $processed ? now() : null, + ]); + } catch (\Throwable $e) { + $event->update([ + 'status' => 'error', + 'error' => $e->getMessage(), + 'processed_at' => now(), + ]); + } + + return response()->json(['ok' => true]); + } + + private function processPayPalEvent(array $payload): bool + { + $type = (string) ($payload['event_type'] ?? ''); + $resource = $payload['resource'] ?? []; + $subscriptionId = (string) ($resource['id'] ?? $resource['subscription_id'] ?? ''); + + if ($subscriptionId === '') { + return false; + } + + if ($type === 'BILLING.SUBSCRIPTION.ACTIVATED') { + $sub = Subscription::firstOrNew([ + 'provider' => 'paypal', + 'provider_ref' => $subscriptionId, + ]); + if (!$sub->user_id) { + $order = Order::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->first(); + if ($order) { + $sub->user_id = $order->user_id; + } + } + $sub->status = 'active'; + $sub->started_at = $sub->started_at ?? now(); + $sub->next_renewal_at = $resource['billing_info']['next_billing_time'] ?? null; + $sub->save(); + + if ($sub->user_id) { + User::where('id', $sub->user_id)->update(['tier' => 'personal']); + } + + Order::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']); + Payment::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->update(['status' => 'paid']); + + return true; + } + + if (in_array($type, ['BILLING.SUBSCRIPTION.CANCELLED', 'BILLING.SUBSCRIPTION.SUSPENDED'], true)) { + $sub = Subscription::where('provider', 'paypal')->where('provider_ref', $subscriptionId)->first(); + if ($sub) { + $sub->status = 'canceled'; + $sub->canceled_at = now(); + $sub->save(); + } + return true; + } + + return false; + } + + private function resolvePlanId(string $planCode, string $mode): ?string + { + $plan = PricingPlan::where('code', $planCode)->first(); + if ($plan) { + $meta = $plan->meta ?? []; + $stored = $meta['paypal'][$mode]['plan']['id'] ?? null; + if ($stored) { + return $stored; + } + } + + return config("dewemoji.billing.providers.paypal.plan_ids.{$mode}.{$planCode}") ?: null; + } + + private function resolvePlanAmountUsd(string $planCode): int + { + $plan = PricingPlan::where('code', $planCode)->first(); + if (!$plan) { + return 0; + } + $rate = (int) config('dewemoji.pricing.usd_rate', 15000); + if ($rate <= 0) { + return 0; + } + return (int) round($plan->amount / $rate); + } + + private function getAccessToken(string $mode): ?string + { + $clientId = config("dewemoji.billing.providers.paypal.{$mode}.client_id"); + $clientSecret = config("dewemoji.billing.providers.paypal.{$mode}.client_secret"); + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + + if (!$clientId || !$clientSecret || !$apiBase) { + return null; + } + + $res = Http::asForm() + ->withBasicAuth($clientId, $clientSecret) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/oauth2/token', [ + 'grant_type' => 'client_credentials', + ]); + + if (!$res->ok()) { + return null; + } + + return $res->json('access_token'); + } + + private function paypalConfigured(string $mode): bool + { + $enabled = (bool) config('dewemoji.billing.providers.paypal.enabled', false); + $clientId = config("dewemoji.billing.providers.paypal.{$mode}.client_id"); + $clientSecret = config("dewemoji.billing.providers.paypal.{$mode}.client_secret"); + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + + return $enabled && $clientId && $clientSecret && $apiBase; + } + + private function billingMode(): string + { + $settings = app(SettingsService::class); + return (string) ($settings->get('billing_mode', config('dewemoji.billing.mode', 'sandbox')) ?: 'sandbox'); + } + + private function verifySignature(string $mode, string $webhookId, array $payload, Request $request): bool + { + $token = $this->getAccessToken($mode); + if (!$token) { + return false; + } + + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $verifyPayload = [ + 'auth_algo' => $request->header('paypal-auth-algo'), + 'cert_url' => $request->header('paypal-cert-url'), + 'transmission_id' => $request->header('paypal-transmission-id'), + 'transmission_sig' => $request->header('paypal-transmission-sig'), + 'transmission_time' => $request->header('paypal-transmission-time'), + 'webhook_id' => $webhookId, + 'webhook_event' => $payload, + ]; + + if (collect($verifyPayload)->contains(fn ($v) => empty($v))) { + return false; + } + + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/notifications/verify-webhook-signature', $verifyPayload); + + return $res->ok() && $res->json('verification_status') === 'SUCCESS'; + } +} diff --git a/app/app/Http/Controllers/Dashboard/AdminDashboardController.php b/app/app/Http/Controllers/Dashboard/AdminDashboardController.php new file mode 100644 index 0000000..439006c --- /dev/null +++ b/app/app/Http/Controllers/Dashboard/AdminDashboardController.php @@ -0,0 +1,688 @@ +query('q', '')); + $tier = trim((string) $request->query('tier', '')); + $role = trim((string) $request->query('role', '')); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'name', 'email', 'role', 'tier', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + + $query = User::query(); + if ($q !== '') { + $query->where(function ($sub) use ($q): void { + $sub->where('email', 'like', '%'.$q.'%') + ->orWhere('name', 'like', '%'.$q.'%'); + }); + } + if ($tier !== '') { + $query->where('tier', $tier); + } + if ($role !== '') { + $query->where('role', $role); + } + + $users = $query->orderBy($sort, $dir)->paginate(20)->withQueryString(); + + return view('dashboard.admin.users', [ + 'users' => $users, + 'filters' => ['q' => $q, 'tier' => $tier, 'role' => $role], + 'sort' => $sort, + 'dir' => $dir, + ]); + } + + public function userDetail(User $user): View + { + $subscriptions = Subscription::where('user_id', $user->id)->orderByDesc('id')->get(); + + return view('dashboard.admin.user-show', [ + 'user' => $user, + 'subscriptions' => $subscriptions, + ]); + } + + public function updateUserTier(Request $request): RedirectResponse + { + $data = $request->validate([ + 'user_id' => 'required|integer', + 'tier' => 'required|string|in:free,personal', + ]); + + User::where('id', $data['user_id'])->update(['tier' => $data['tier']]); + if ($data['tier'] === 'free') { + UserApiKey::where('user_id', $data['user_id'])->update(['revoked_at' => now()]); + } + $this->logAdminAction('user_tier_update', $data); + + return back()->with('status', 'User tier updated.'); + } + + public function createUser(Request $request): RedirectResponse + { + $data = $request->validate([ + 'name' => 'nullable|string|max:120', + 'email' => 'required|email|max:255|unique:users,email', + 'password' => 'required|string|min:8|max:255', + 'role' => 'required|string|in:admin,user', + 'tier' => 'required|string|in:free,personal', + ]); + + $name = $data['name'] ?: strtok($data['email'], '@'); + + $user = User::create([ + 'name' => $name ?: 'User', + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + 'role' => $data['role'], + 'tier' => $data['tier'], + ]); + + $this->logAdminAction('user_created', [ + 'user_id' => $user->id, + 'email' => $user->email, + 'role' => $user->role, + 'tier' => $user->tier, + ]); + + return back()->with('status', 'User created.'); + } + + public function deleteUser(Request $request, User $user): RedirectResponse + { + $admin = $request->user(); + + if ($admin && $admin->id === $user->id) { + return back()->withErrors(['user' => 'You cannot delete your own account.']); + } + + if (($user->role ?? 'user') === 'admin' && User::where('role', 'admin')->count() <= 1) { + return back()->withErrors(['user' => 'Cannot delete the last admin account.']); + } + + DB::transaction(function () use ($user): void { + Payment::where('user_id', $user->id)->delete(); + Order::where('user_id', $user->id)->delete(); + Subscription::where('user_id', $user->id)->delete(); + UserApiKey::where('user_id', $user->id)->delete(); + UserKeyword::where('user_id', $user->id)->delete(); + DB::table('password_reset_tokens')->where('email', $user->email)->delete(); + $user->delete(); + }); + + $this->logAdminAction('user_deleted', [ + 'user_id' => $user->id, + 'email' => $user->email, + ]); + + return back()->with('status', 'User deleted.'); + } + + public function subscriptions(Request $request): View + { + $query = Subscription::query()->with('user:id,email,name,tier'); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'plan', 'status', 'started_at', 'expires_at', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + + if ($userId = $request->query('user_id')) { + $query->where('user_id', (int) $userId); + } + if ($email = $request->query('email')) { + $query->whereHas('user', fn ($q) => $q->where('email', $email)); + } + if ($status = $request->query('status')) { + $query->where('status', (string) $status); + } + + $subscriptions = $query->orderBy($sort, $dir)->paginate(20)->withQueryString(); + + return view('dashboard.admin.subscriptions', [ + 'subscriptions' => $subscriptions, + 'filters' => [ + 'user_id' => $request->query('user_id'), + 'email' => $request->query('email'), + 'status' => $request->query('status'), + ], + 'sort' => $sort, + 'dir' => $dir, + ]); + } + + public function subscriptionDetail(Subscription $subscription): View + { + $subscription->loadMissing('user:id,name,email,tier,role'); + + return view('dashboard.admin.subscription-show', [ + 'subscription' => $subscription, + ]); + } + + public function grantSubscription(Request $request): RedirectResponse + { + $data = $request->validate([ + 'user_id' => 'nullable|integer', + 'email' => 'nullable|email|max:255', + 'plan' => 'required|string|max:20', + 'status' => 'required|string|in:active,pending,revoked', + 'provider' => 'nullable|string|max:20', + 'provider_ref' => 'nullable|string|max:100', + 'started_at' => 'nullable|date', + 'expires_at' => 'nullable|date', + ]); + + $user = $this->resolveUser($data['user_id'] ?? null, $data['email'] ?? null); + if (!$user) { + return back()->withErrors(['user' => 'User not found.']); + } + + $startedAt = $data['started_at'] ? Carbon::parse($data['started_at']) : now(); + $expiresAt = $data['expires_at'] ? Carbon::parse($data['expires_at']) : null; + + Subscription::create([ + 'user_id' => $user->id, + 'plan' => $data['plan'], + 'status' => $data['status'], + 'provider' => $data['provider'] ?? 'admin', + 'provider_ref' => $data['provider_ref'] ?? null, + 'started_at' => $startedAt, + 'expires_at' => $expiresAt, + ]); + + if ($data['status'] === 'active') { + $user->update(['tier' => 'personal']); + } + + $this->logAdminAction('subscription_grant', [ + 'user_id' => $user->id, + 'email' => $user->email, + 'plan' => $data['plan'], + 'status' => $data['status'], + ]); + + return back()->with('status', 'Subscription granted.'); + } + + public function revokeSubscription(Request $request): RedirectResponse + { + $data = $request->validate([ + 'subscription_id' => 'nullable|integer', + 'user_id' => 'nullable|integer', + 'email' => 'nullable|email|max:255', + ]); + + if (!empty($data['subscription_id'])) { + $sub = Subscription::find($data['subscription_id']); + if (!$sub) { + return back()->withErrors(['subscription' => 'Subscription not found.']); + } + $sub->update(['status' => 'revoked', 'expires_at' => now()]); + $this->syncUserTier($sub->user_id); + $this->logAdminAction('subscription_revoke', [ + 'subscription_id' => $sub->id, + 'user_id' => $sub->user_id, + ]); + return back()->with('status', 'Subscription revoked.'); + } + + $user = $this->resolveUser($data['user_id'] ?? null, $data['email'] ?? null); + if (!$user) { + return back()->withErrors(['user' => 'User not found.']); + } + + Subscription::where('user_id', $user->id) + ->where('status', 'active') + ->update(['status' => 'revoked', 'expires_at' => now()]); + $this->syncUserTier($user->id); + $this->logAdminAction('subscription_revoke_all', [ + 'user_id' => $user->id, + 'email' => $user->email, + ]); + + return back()->with('status', 'User subscriptions revoked.'); + } + + public function pricing(): View + { + $plans = PricingPlan::orderBy('id')->get(); + $changes = PricingChange::orderByDesc('id')->limit(5)->get(); + + return view('dashboard.admin.pricing', [ + 'plans' => $plans, + 'changes' => $changes, + ]); + } + + public function updatePricing(Request $request): RedirectResponse + { + $data = $request->validate([ + 'plans' => 'required|array|min:1', + 'plans.*.code' => 'required|string|max:30', + 'plans.*.name' => 'required|string|max:50', + 'plans.*.amount_idr' => 'required|integer|min:0', + 'plans.*.amount_usd' => 'nullable|numeric|min:0', + 'plans.*.period' => 'nullable|string|max:20', + 'plans.*.status' => 'nullable|string|max:20', + ]); + + $before = PricingPlan::orderBy('id')->get()->toArray(); + + DB::transaction(function () use ($data): void { + foreach ($data['plans'] as $plan) { + $meta = [ + 'prices' => [ + 'IDR' => (int) $plan['amount_idr'], + 'USD' => isset($plan['amount_usd']) ? (float) $plan['amount_usd'] : null, + ], + ]; + + PricingPlan::updateOrCreate( + ['code' => $plan['code']], + [ + 'name' => $plan['name'], + 'currency' => 'IDR', + 'amount' => (int) $plan['amount_idr'], + 'period' => $plan['period'] ?? null, + 'status' => $plan['status'] ?? 'active', + 'meta' => $meta, + ] + ); + } + }); + + $after = PricingPlan::orderBy('id')->get()->toArray(); + PricingChange::create([ + 'admin_ref' => (string) auth()->user()?->email, + 'before' => $before, + 'after' => $after, + ]); + $this->logAdminAction('pricing_update', ['plans' => count($data['plans'])]); + + return back()->with('status', 'Pricing updated.'); + } + + public function syncPaypalPlans(PayPalPlanSyncService $sync): RedirectResponse + { + $resultSandbox = $sync->sync('sandbox'); + $resultLive = $sync->sync('live'); + + $this->logAdminAction('paypal_plan_sync', [ + 'sandbox' => $resultSandbox, + 'live' => $resultLive, + ]); + + return back()->with('status', 'PayPal plans synced (sandbox + live).'); + } + + public function createPricingSnapshot(): RedirectResponse + { + $before = PricingPlan::orderBy('id')->get()->toArray(); + + PricingChange::create([ + 'admin_ref' => (string) auth()->user()?->email, + 'before' => $before, + 'after' => $before, + ]); + $this->logAdminAction('pricing_snapshot', ['plans' => count($before)]); + + return back()->with('status', 'Pricing snapshot created.'); + } + + public function resetPricing(): RedirectResponse + { + $defaults = config('dewemoji.pricing.defaults', []); + $before = PricingPlan::orderBy('id')->get()->toArray(); + + DB::transaction(function () use ($defaults): void { + PricingPlan::query()->delete(); + foreach ($defaults as $plan) { + PricingPlan::create([ + 'code' => $plan['code'], + 'name' => $plan['name'], + 'currency' => $plan['currency'], + 'amount' => $plan['amount'], + 'period' => $plan['period'], + 'status' => $plan['status'], + 'meta' => $plan['meta'] ?? null, + ]); + } + }); + + $after = PricingPlan::orderBy('id')->get()->toArray(); + PricingChange::create([ + 'admin_ref' => (string) auth()->user()?->email, + 'before' => $before, + 'after' => $after, + ]); + $this->logAdminAction('pricing_reset', ['plans' => count($after)]); + + return back()->with('status', 'Pricing reset to defaults.'); + } + + public function webhooks(Request $request): View + { + $query = WebhookEvent::query(); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'provider', 'status', 'received_at', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + if ($provider = $request->query('provider')) { + $query->where('provider', (string) $provider); + } + if ($status = $request->query('status')) { + $query->where('status', (string) $status); + } + + $events = $query->orderBy($sort, $dir)->paginate(20)->withQueryString(); + $providers = WebhookEvent::query()->distinct('provider')->orderBy('provider')->pluck('provider'); + + return view('dashboard.admin.webhooks', [ + 'events' => $events, + 'filters' => [ + 'provider' => $request->query('provider'), + 'status' => $request->query('status'), + ], + 'providers' => $providers, + 'sort' => $sort, + 'dir' => $dir, + ]); + } + + public function webhookDetail(WebhookEvent $event): View + { + return view('dashboard.admin.webhook-show', [ + 'event' => $event, + ]); + } + + public function replayWebhook(int $id): RedirectResponse + { + $event = WebhookEvent::find($id); + if (!$event) { + return back()->withErrors(['webhook' => 'Webhook not found.']); + } + + $event->update(['status' => 'pending', 'processed_at' => null, 'error' => null]); + $this->logAdminAction('webhook_replay', ['event_id' => $event->id]); + + return back()->with('status', 'Webhook queued for replay.'); + } + + public function replayFailedWebhooks(): RedirectResponse + { + $count = WebhookEvent::where('status', 'error')->count(); + WebhookEvent::where('status', 'error')->update([ + 'status' => 'pending', + 'processed_at' => null, + 'error' => null, + ]); + $this->logAdminAction('webhook_replay_failed', ['count' => $count]); + + return back()->with('status', 'Failed webhooks queued for replay.'); + } + + public function settings(): View + { + $all = $this->settings->all(); + + return view('dashboard.admin.settings', [ + 'settings' => $all, + ]); + } + + public function auditLogs(Request $request): View + { + $q = trim((string) $request->query('q', '')); + $action = trim((string) $request->query('action', '')); + + $query = AdminAuditLog::query()->orderByDesc('id'); + if ($q !== '') { + $query->where(function ($sub) use ($q): void { + $sub->where('admin_email', 'like', '%'.$q.'%') + ->orWhere('action', 'like', '%'.$q.'%'); + }); + } + if ($action !== '') { + $query->where('action', $action); + } + + $actions = AdminAuditLog::query()->distinct('action')->orderBy('action')->pluck('action'); + $logs = $query->paginate(25)->withQueryString(); + + return view('dashboard.admin.audit-logs', [ + 'logs' => $logs, + 'filters' => ['q' => $q, 'action' => $action], + 'actions' => $actions, + ]); + } + + public function updateSettings(Request $request): RedirectResponse + { + $data = $request->validate([ + 'maintenance_enabled' => 'nullable|boolean', + 'public_enforce' => 'nullable|boolean', + 'public_origins' => 'nullable|string', + 'public_extension_ids' => 'nullable|string', + 'public_hourly_limit' => 'nullable|integer|min:0', + 'billing_mode' => 'nullable|string|in:sandbox,live', + ]); + + $payload = [ + 'maintenance_enabled' => (bool) ($data['maintenance_enabled'] ?? false), + 'public_enforce' => (bool) ($data['public_enforce'] ?? false), + 'public_origins' => $this->splitCsv($data['public_origins'] ?? ''), + 'public_extension_ids' => $this->splitCsv($data['public_extension_ids'] ?? ''), + 'public_hourly_limit' => (int) ($data['public_hourly_limit'] ?? 0), + 'billing_mode' => $data['billing_mode'] ?? null, + ]; + + $this->settings->setMany($payload, (string) auth()->user()?->email); + $this->logAdminAction('settings_update', $payload); + + return back()->with('status', 'Settings updated.'); + } + + private function resolveUser(?int $userId, ?string $email): ?User + { + if ($userId) { + return User::find($userId); + } + if ($email) { + return User::where('email', $email)->first(); + } + + return null; + } + + private function syncUserTier(int $userId): void + { + $active = Subscription::where('user_id', $userId) + ->where('status', 'active') + ->where(function ($q): void { + $q->whereNull('expires_at') + ->orWhere('expires_at', '>', now()); + }) + ->exists(); + + User::where('id', $userId)->update([ + 'tier' => $active ? 'personal' : 'free', + ]); + if (!$active) { + UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]); + } + } + + public function exportCsv(Request $request, string $type): StreamedResponse + { + $type = strtolower($type); + $filename = "dewemoji-{$type}-export-".now()->format('Ymd_His').".csv"; + + return response()->streamDownload(function () use ($type, $request): void { + $out = fopen('php://output', 'w'); + + if ($type === 'users') { + $q = trim((string) $request->query('q', '')); + $tier = trim((string) $request->query('tier', '')); + $role = trim((string) $request->query('role', '')); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'name', 'email', 'role', 'tier', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + + $query = User::query(); + if ($q !== '') { + $query->where(function ($sub) use ($q): void { + $sub->where('email', 'like', '%'.$q.'%') + ->orWhere('name', 'like', '%'.$q.'%'); + }); + } + if ($tier !== '') { + $query->where('tier', $tier); + } + if ($role !== '') { + $query->where('role', $role); + } + + fputcsv($out, ['id', 'name', 'email', 'role', 'tier', 'created_at']); + $query->orderBy($sort, $dir)->chunk(500, function ($rows) use ($out): void { + foreach ($rows as $row) { + fputcsv($out, [ + $row->id, + $row->name, + $row->email, + $row->role, + $row->tier, + optional($row->created_at)->toDateTimeString(), + ]); + } + }); + } elseif ($type === 'subscriptions') { + $userId = $request->query('user_id'); + $email = $request->query('email'); + $status = $request->query('status'); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'plan', 'status', 'started_at', 'expires_at', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + + $query = Subscription::query()->with('user:id,email'); + if ($userId) { + $query->where('user_id', (int) $userId); + } + if ($email) { + $query->whereHas('user', fn ($q) => $q->where('email', $email)); + } + if ($status) { + $query->where('status', (string) $status); + } + + fputcsv($out, ['id', 'user_id', 'email', 'plan', 'status', 'started_at', 'expires_at']); + $query->orderBy($sort, $dir)->chunk(500, function ($rows) use ($out): void { + foreach ($rows as $row) { + fputcsv($out, [ + $row->id, + $row->user_id, + $row->user?->email, + $row->plan, + $row->status, + optional($row->started_at)->toDateTimeString(), + optional($row->expires_at)->toDateTimeString(), + ]); + } + }); + } elseif ($type === 'webhooks') { + $provider = $request->query('provider'); + $status = $request->query('status'); + $sort = $this->sanitizeSort($request->query('sort'), ['id', 'provider', 'status', 'received_at', 'created_at'], 'id'); + $dir = $this->sanitizeDir($request->query('dir')); + + $query = WebhookEvent::query(); + if ($provider) { + $query->where('provider', (string) $provider); + } + if ($status) { + $query->where('status', (string) $status); + } + + fputcsv($out, ['id', 'provider', 'event_type', 'status', 'received_at', 'processed_at']); + $query->orderBy($sort, $dir)->chunk(500, function ($rows) use ($out): void { + foreach ($rows as $row) { + fputcsv($out, [ + $row->id, + $row->provider, + $row->event_type, + $row->status, + optional($row->received_at)->toDateTimeString(), + optional($row->processed_at)->toDateTimeString(), + ]); + } + }); + } else { + fputcsv($out, ['error']); + fputcsv($out, ['unsupported_export_type']); + } + + fclose($out); + }, $filename, [ + 'Content-Type' => 'text/csv; charset=UTF-8', + ]); + } + + private function logAdminAction(string $action, array $payload = []): void + { + if (!Schema::hasTable('admin_audit_logs')) { + return; + } + $user = auth()->user(); + AdminAuditLog::create([ + 'admin_id' => $user?->id, + 'admin_email' => $user?->email, + 'action' => $action, + 'payload' => $payload, + 'ip_address' => request()->ip(), + ]); + } + + private function sanitizeSort(mixed $value, array $allowed, string $fallback): string + { + $sort = is_string($value) ? $value : ''; + return in_array($sort, $allowed, true) ? $sort : $fallback; + } + + private function sanitizeDir(mixed $value): string + { + return $value === 'asc' ? 'asc' : 'desc'; + } + + /** + * @return array + */ + private function splitCsv(string $value): array + { + $items = array_filter(array_map('trim', explode(',', $value))); + return array_values($items); + } +} diff --git a/app/app/Http/Controllers/Dashboard/UserDashboardController.php b/app/app/Http/Controllers/Dashboard/UserDashboardController.php new file mode 100644 index 0000000..b2badc0 --- /dev/null +++ b/app/app/Http/Controllers/Dashboard/UserDashboardController.php @@ -0,0 +1,452 @@ +user(); + if (Gate::allows('admin')) { + $days = 7; + $start = now()->subDays($days - 1)->startOfDay(); + $labels = []; + $values = []; + $subsValues = []; + $webhookValues = []; + + $rawUsers = DB::table('users') + ->selectRaw('DATE(created_at) as day, COUNT(*) as total') + ->where('created_at', '>=', $start) + ->groupBy('day') + ->orderBy('day') + ->get() + ->keyBy('day'); + + $rawSubs = DB::table('subscriptions') + ->selectRaw('DATE(created_at) as day, COUNT(*) as total') + ->where('created_at', '>=', $start) + ->groupBy('day') + ->orderBy('day') + ->get() + ->keyBy('day'); + + $rawWebhooks = DB::table('webhook_events') + ->selectRaw('DATE(COALESCE(received_at, created_at)) as day, COUNT(*) as total') + ->where('created_at', '>=', $start) + ->groupBy('day') + ->orderBy('day') + ->get() + ->keyBy('day'); + + for ($i = $days - 1; $i >= 0; $i--) { + $date = Carbon::now()->subDays($i)->format('Y-m-d'); + $labels[] = Carbon::parse($date)->format('M d'); + $values[] = (int) ($rawUsers[$date]->total ?? 0); + $subsValues[] = (int) ($rawSubs[$date]->total ?? 0); + $webhookValues[] = (int) ($rawWebhooks[$date]->total ?? 0); + } + + $usersTotal = User::count(); + $usersPersonal = User::where('tier', 'personal')->count(); + $subscriptionsActive = Subscription::where('status', 'active')->count(); + $subscriptionsTotal = Subscription::count(); + $webhookTotal = WebhookEvent::count(); + $webhookErrors = WebhookEvent::where('status', 'error')->count(); + + return view('dashboard.index', [ + 'chartLabels' => $labels, + 'chartValues' => $values, + 'chartSubs' => $subsValues, + 'chartWebhooks' => $webhookValues, + 'overviewMetrics' => [ + 'users_total' => $usersTotal, + 'users_personal' => $usersPersonal, + 'subscriptions_active' => $subscriptionsActive, + 'subscriptions_total' => $subscriptionsTotal, + 'webhook_total' => $webhookTotal, + 'webhook_errors' => $webhookErrors, + ], + ]); + } + + $recentKeywords = UserKeyword::where('user_id', $user?->id) + ->orderByDesc('id') + ->limit(6) + ->get(); + + $recentWeekCount = UserKeyword::where('user_id', $user?->id) + ->where('created_at', '>=', now()->subDays(7)) + ->count(); + + $totalKeywords = UserKeyword::where('user_id', $user?->id)->count(); + $apiKeyCount = UserApiKey::where('user_id', $user?->id) + ->whereNull('revoked_at') + ->count(); + + $activeSubscription = Subscription::where('user_id', $user?->id) + ->orderByDesc('started_at') + ->first(); + + return view('dashboard.user.overview', [ + 'totalKeywords' => $totalKeywords, + 'recentKeywords' => $recentKeywords, + 'recentWeekCount' => $recentWeekCount, + 'apiKeyCount' => $apiKeyCount, + 'subscription' => $activeSubscription, + ]); + } + + public function keywords(Request $request): View + { + $user = $request->user(); + + $items = UserKeyword::where('user_id', $user?->id) + ->orderByDesc('id') + ->get(); + + $emojiLookup = []; + $dataPath = (string) config('dewemoji.data_path'); + if (is_file($dataPath)) { + $raw = file_get_contents($dataPath); + $decoded = json_decode((string) $raw, true); + if (is_array($decoded)) { + foreach ($decoded['emojis'] ?? [] as $row) { + $slug = (string) ($row['slug'] ?? ''); + if ($slug !== '') { + $emojiLookup[$slug] = [ + 'emoji' => (string) ($row['emoji'] ?? ''), + 'name' => (string) ($row['name'] ?? $slug), + ]; + } + } + } + } + + return view('dashboard.user.keywords', [ + 'items' => $items, + 'user' => $user, + 'emojiLookup' => $emojiLookup, + 'freeLimit' => $this->keywordLimitFor($user), + ]); + } + + public function keywordSearch(Request $request, EmojiApiController $emoji): JsonResponse + { + $request->query->set('private', 'true'); + + return $emoji->search($request); + } + + public function storeKeyword(Request $request): RedirectResponse|JsonResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + + $data = $request->validate([ + 'emoji_slug' => 'required|string|max:120', + 'keyword' => 'required|string|max:200', + 'lang' => 'nullable|string|max:10', + ]); + + if ($limit = $this->keywordLimitFor($user)) { + $exists = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $data['emoji_slug']) + ->where('keyword', $data['keyword']) + ->exists(); + + if (!$exists) { + $count = UserKeyword::where('user_id', $user->id)->count(); + if ($count >= $limit) { + return $this->rejectKeywordLimit($request, $limit); + } + } + } + + $item = UserKeyword::updateOrCreate( + [ + 'user_id' => $user->id, + 'emoji_slug' => $data['emoji_slug'], + 'keyword' => $data['keyword'], + ], + [ + 'lang' => $data['lang'] ?? 'und', + ] + ); + + if ($request->expectsJson()) { + return response()->json(['ok' => true, 'item' => $item]); + } + + return back()->with('status', 'Keyword saved.'); + } + + public function updateKeyword(Request $request, UserKeyword $keyword): RedirectResponse|JsonResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + + if ($keyword->user_id !== $user->id) { + abort(403); + } + + $data = $request->validate([ + 'emoji_slug' => 'required|string|max:120', + 'keyword' => 'required|string|max:200', + 'lang' => 'nullable|string|max:10', + ]); + + $duplicate = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $data['emoji_slug']) + ->where('keyword', $data['keyword']) + ->first(); + + if ($duplicate && $duplicate->id !== $keyword->id) { + $keyword->delete(); + $keyword = $duplicate; + } else { + $keyword->update([ + 'emoji_slug' => $data['emoji_slug'], + 'keyword' => $data['keyword'], + 'lang' => $data['lang'] ?? 'und', + ]); + } + + if ($request->expectsJson()) { + return response()->json(['ok' => true, 'item' => $keyword]); + } + + return back()->with('status', 'Keyword updated.'); + } + + public function deleteKeyword(Request $request, UserKeyword $keyword): RedirectResponse|JsonResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + + if ($keyword->user_id !== $user->id) { + abort(403); + } + + $keyword->delete(); + + if ($request->expectsJson()) { + return response()->json(['ok' => true]); + } + + return back()->with('status', 'Keyword removed.'); + } + + public function importKeywords(Request $request): RedirectResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + + $payload = $request->input('payload'); + if ($request->hasFile('file')) { + $payload = $request->file('file')->get(); + } + + $items = json_decode((string) $payload, true); + if (!is_array($items)) { + return back()->withErrors(['payload' => 'Invalid JSON payload.']); + } + + $imported = 0; + $skipped = 0; + $limit = $this->keywordLimitFor($user); + $current = UserKeyword::where('user_id', $user->id)->count(); + foreach ($items as $row) { + if (!is_array($row)) { + continue; + } + $emojiSlug = trim((string) ($row['emoji_slug'] ?? '')); + $keyword = trim((string) ($row['keyword'] ?? '')); + $lang = trim((string) ($row['lang'] ?? 'und')); + if ($emojiSlug === '' || $keyword === '') { + continue; + } + $exists = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $emojiSlug) + ->where('keyword', $keyword) + ->exists(); + + if (!$exists && $limit !== null && $current >= $limit) { + $skipped += 1; + continue; + } + + UserKeyword::updateOrCreate( + [ + 'user_id' => $user->id, + 'emoji_slug' => $emojiSlug, + 'keyword' => $keyword, + ], + [ + 'lang' => $lang !== '' ? $lang : 'und', + ] + ); + if (!$exists) { + $current += 1; + } + $imported += 1; + } + + $message = "Imported {$imported} keywords."; + if ($skipped > 0) { + $message .= " {$skipped} skipped (free limit reached)."; + } + + return back()->with('status', $message); + } + + public function exportKeywords(Request $request): BinaryFileResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + + $items = UserKeyword::where('user_id', $user->id) + ->orderByDesc('id') + ->get(['emoji_slug', 'keyword', 'lang']) + ->values() + ->toJson(JSON_PRETTY_PRINT); + + $filename = 'dewemoji-keywords-'.$user->id.'-'.now()->format('Ymd-His').'.json'; + $path = storage_path('app/'.$filename); + file_put_contents($path, $items); + + return response()->download($path, $filename)->deleteFileAfterSend(true); + } + + public function apiKeys(Request $request): View + { + $user = $request->user(); + $keys = UserApiKey::where('user_id', $user?->id) + ->orderByDesc('id') + ->get(); + $canCreate = $user && (string) $user->tier === 'personal'; + + return view('dashboard.user.api-keys', [ + 'user' => $user, + 'keys' => $keys, + 'canCreate' => $canCreate, + 'newKey' => session('new_api_key'), + ]); + } + + public function createApiKey(Request $request): RedirectResponse + { + $user = $request->user(); + if (!$user) { + abort(403); + } + if ((string) $user->tier !== 'personal') { + return back()->withErrors(['api_key' => 'API keys are available on the Personal plan.']); + } + + $data = $request->validate([ + 'name' => 'nullable|string|max:100', + ]); + + $issued = $this->keys->issueKey($user, $data['name'] ?? null); + + return back()->with('new_api_key', $issued['plain']); + } + + public function revokeApiKey(Request $request, UserApiKey $key): RedirectResponse + { + $user = $request->user(); + if (!$user || $key->user_id !== $user->id) { + abort(403); + } + + $key->update(['revoked_at' => Carbon::now()]); + + return back()->with('status', 'API key revoked.'); + } + + public function billing(Request $request): View + { + $user = $request->user(); + $subscription = Subscription::where('user_id', $user?->id) + ->orderByDesc('started_at') + ->first(); + + $orders = Order::where('user_id', $user?->id) + ->orderByDesc('id') + ->limit(5) + ->get(); + + $payments = Payment::where('user_id', $user?->id) + ->orderByDesc('id') + ->limit(5) + ->get(); + + return view('dashboard.user.billing', [ + 'subscription' => $subscription, + 'user' => $user, + 'orders' => $orders, + 'payments' => $payments, + ]); + } + + public function preferences(Request $request): View + { + return view('dashboard.user.preferences'); + } + + private function rejectKeywordLimit(Request $request, int $limit): RedirectResponse|JsonResponse + { + if ($request->expectsJson()) { + return response()->json(['ok' => false, 'error' => 'free_limit_reached', 'limit' => $limit], 403); + } + + return back()->withErrors(['tier' => "Free plan limit reached ({$limit} keywords)."]); + } + + private function keywordLimitFor(?User $user): ?int + { + if (!$user) { + return null; + } + if ((string) $user->tier === 'personal') { + return null; + } + + return (int) config('dewemoji.pagination.free_max_limit', 20); + } +} diff --git a/app/app/Http/Controllers/ProfileController.php b/app/app/Http/Controllers/ProfileController.php new file mode 100644 index 0000000..b4f25af --- /dev/null +++ b/app/app/Http/Controllers/ProfileController.php @@ -0,0 +1,66 @@ + $request->user(), + ]); + } + + /** + * Update the user's profile information. + */ + public function update(ProfileUpdateRequest $request): RedirectResponse + { + $request->user()->fill($request->validated()); + + $emailChanged = $request->user()->isDirty('email'); + if ($emailChanged) { + $request->user()->email_verified_at = null; + } + + $request->user()->save(); + + if ($emailChanged && $request->user() instanceof MustVerifyEmail) { + $request->user()->sendEmailVerificationNotification(); + } + + return Redirect::route('profile.edit')->with('status', 'profile-updated'); + } + + /** + * Delete the user's account. + */ + public function destroy(Request $request): RedirectResponse + { + $request->validateWithBag('userDeletion', [ + 'password' => ['required', 'current_password'], + ]); + + $user = $request->user(); + + Auth::logout(); + + $user->delete(); + + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return Redirect::to('/'); + } +} diff --git a/app/app/Http/Controllers/Web/SiteController.php b/app/app/Http/Controllers/Web/SiteController.php index 3a5cbd7..108fe32 100644 --- a/app/app/Http/Controllers/Web/SiteController.php +++ b/app/app/Http/Controllers/Web/SiteController.php @@ -3,6 +3,9 @@ namespace App\Http\Controllers\Web; use App\Http\Controllers\Controller; +use App\Models\PricingPlan; +use App\Models\UserKeyword; +use App\Services\System\SettingsService; use Illuminate\Contracts\View\View; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; @@ -23,6 +26,12 @@ class SiteController extends Controller 'Flags' => 'flags', ]; + private function billingMode(): string + { + $settings = app(SettingsService::class); + return (string) ($settings->get('billing_mode', config('dewemoji.billing.mode', 'sandbox')) ?: 'sandbox'); + } + public function home(Request $request): View { return view('site.home', [ @@ -30,6 +39,7 @@ class SiteController extends Controller 'initialCategory' => trim((string) $request->query('category', '')), 'initialSubcategory' => trim((string) $request->query('subcategory', '')), 'canonicalPath' => '/', + 'userTier' => $request->user()?->tier, ]); } @@ -45,19 +55,21 @@ class SiteController extends Controller 'initialCategory' => trim((string) $request->query('category', '')), 'initialSubcategory' => trim((string) $request->query('subcategory', '')), 'canonicalPath' => '/browse', + 'userTier' => $request->user()?->tier, ]); } public function category(string $categorySlug): View { if ($categorySlug === 'all') { - return view('site.home', [ - 'initialQuery' => '', - 'initialCategory' => '', - 'initialSubcategory' => '', - 'canonicalPath' => '/', - ]); - } + return view('site.home', [ + 'initialQuery' => '', + 'initialCategory' => '', + 'initialSubcategory' => '', + 'canonicalPath' => '/', + 'userTier' => request()->user()?->tier, + ]); + } $categoryLabel = $this->categorySlugMap()[$categorySlug] ?? ''; abort_if($categoryLabel === '', 404); @@ -67,6 +79,7 @@ class SiteController extends Controller 'initialCategory' => $categoryLabel, 'initialSubcategory' => '', 'canonicalPath' => '/'.$categorySlug, + 'userTier' => request()->user()?->tier, ]); } @@ -84,6 +97,7 @@ class SiteController extends Controller 'initialCategory' => $categoryLabel, 'initialSubcategory' => $subcategorySlug, 'canonicalPath' => '/'.$categorySlug.'/'.$subcategorySlug, + 'userTier' => request()->user()?->tier, ]); } @@ -94,7 +108,96 @@ class SiteController extends Controller public function pricing(): View { - return view('site.pricing'); + $currencyPref = strtoupper((string) session('pricing_currency', '')); + if (!in_array($currencyPref, ['IDR', 'USD'], true)) { + $currencyPref = $this->detectPricingCurrency(request()); + session(['pricing_currency' => $currencyPref]); + } + + $rate = (int) config('dewemoji.pricing.usd_rate', 15000); + $plans = PricingPlan::where('status', 'active')->get()->keyBy('code'); + $defaults = config('dewemoji.pricing.defaults', []); + $fallback = collect($defaults)->keyBy('code'); + + $getPlanAmount = function (string $code) use ($plans, $fallback): int { + $plan = $plans->get($code) ?? $fallback->get($code); + return (int) ($plan['amount'] ?? $plan->amount ?? 0); + }; + + $pricing = [ + 'personal_monthly' => [ + 'idr' => $getPlanAmount('personal_monthly'), + ], + 'personal_annual' => [ + 'idr' => $getPlanAmount('personal_annual'), + ], + 'personal_lifetime' => [ + 'idr' => $getPlanAmount('personal_lifetime'), + ], + ]; + + foreach ($pricing as $key => $row) { + $pricing[$key]['usd'] = $rate > 0 ? round($row['idr'] / $rate, 2) : 0; + } + + return view('site.pricing', [ + 'currencyPref' => $currencyPref, + 'usdRate' => $rate, + 'pricing' => $pricing, + 'payments' => [ + 'qris_url' => (string) config('dewemoji.payments.qris_url', ''), + 'paypal_url' => (string) config('dewemoji.payments.paypal_url', ''), + ], + 'pakasirEnabled' => (bool) config('dewemoji.billing.providers.pakasir.enabled', false) + && (string) config('dewemoji.billing.providers.pakasir.api_base', '') !== '' + && (string) config('dewemoji.billing.providers.pakasir.api_key', '') !== '' + && (string) config('dewemoji.billing.providers.pakasir.project', '') !== '', + 'paypalEnabled' => $this->paypalEnabled($this->billingMode()), + 'paypalPlans' => $this->paypalPlanAvailability($this->billingMode()), + ]); + } + + private function paypalEnabled(string $mode): bool + { + $enabled = (bool) config('dewemoji.billing.providers.paypal.enabled', false); + $clientId = (string) config("dewemoji.billing.providers.paypal.{$mode}.client_id", ''); + $clientSecret = (string) config("dewemoji.billing.providers.paypal.{$mode}.client_secret", ''); + $apiBase = (string) config("dewemoji.billing.providers.paypal.{$mode}.api_base", ''); + + return $enabled && $clientId !== '' && $clientSecret !== '' && $apiBase !== ''; + } + + private function paypalPlanAvailability(string $mode): array + { + $plans = PricingPlan::whereIn('code', ['personal_monthly', 'personal_annual'])->get()->keyBy('code'); + + $fromDb = function (string $code) use ($plans, $mode): bool { + $plan = $plans->get($code); + if (!$plan) { + return false; + } + $meta = $plan->meta ?? []; + return (string) ($meta['paypal'][$mode]['plan']['id'] ?? '') !== ''; + }; + + $fromEnv = function (string $code) use ($mode): bool { + return (string) config("dewemoji.billing.providers.paypal.plan_ids.{$mode}.{$code}", '') !== ''; + }; + + return [ + 'personal_monthly' => $fromDb('personal_monthly') || $fromEnv('personal_monthly'), + 'personal_annual' => $fromDb('personal_annual') || $fromEnv('personal_annual'), + ]; + } + + public function setPricingCurrency(Request $request): RedirectResponse + { + $data = $request->validate([ + 'currency' => 'required|string|in:IDR,USD', + ]); + + session(['pricing_currency' => $data['currency']]); + return back(); } public function support(): View @@ -112,6 +215,18 @@ class SiteController extends Controller return view('site.terms'); } + private function detectPricingCurrency(Request $request): string + { + $country = strtoupper((string) ($request->header('CF-IPCountry') + ?? $request->header('X-Country-Code') + ?? $request->header('X-Geo-Country') + ?? $request->header('X-Appengine-Country') + ?? $request->header('CloudFront-Viewer-Country') + ?? '')); + + return $country === 'ID' ? 'IDR' : 'USD'; + } + public function emojiDetail(string $slug): View|Response { $dataPath = (string) config('dewemoji.data_path'); @@ -157,10 +272,22 @@ class SiteController extends Controller ]; } + $user = request()->user(); + $isPersonal = $user && (string) $user->tier === 'personal'; + $userKeywords = []; + if ($isPersonal) { + $userKeywords = UserKeyword::where('user_id', $user->id) + ->where('emoji_slug', $slug) + ->orderByDesc('id') + ->get(); + } + return view('site.emoji-detail', [ 'emoji' => $match, 'relatedDetails' => $relatedDetails, 'canonicalPath' => '/emoji/'.$slug, + 'userKeywords' => $userKeywords, + 'userTier' => $user?->tier, ]); } diff --git a/app/app/Http/Requests/Auth/LoginRequest.php b/app/app/Http/Requests/Auth/LoginRequest.php new file mode 100644 index 0000000..2574642 --- /dev/null +++ b/app/app/Http/Requests/Auth/LoginRequest.php @@ -0,0 +1,85 @@ +|string> + */ + public function rules(): array + { + return [ + 'email' => ['required', 'string', 'email'], + 'password' => ['required', 'string'], + ]; + } + + /** + * Attempt to authenticate the request's credentials. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function authenticate(): void + { + $this->ensureIsNotRateLimited(); + + if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) { + RateLimiter::hit($this->throttleKey()); + + throw ValidationException::withMessages([ + 'email' => trans('auth.failed'), + ]); + } + + RateLimiter::clear($this->throttleKey()); + } + + /** + * Ensure the login request is not rate limited. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function ensureIsNotRateLimited(): void + { + if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { + return; + } + + event(new Lockout($this)); + + $seconds = RateLimiter::availableIn($this->throttleKey()); + + throw ValidationException::withMessages([ + 'email' => trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ]), + ]); + } + + /** + * Get the rate limiting throttle key for the request. + */ + public function throttleKey(): string + { + return Str::transliterate(Str::lower($this->string('email')).'|'.$this->ip()); + } +} diff --git a/app/app/Http/Requests/ProfileUpdateRequest.php b/app/app/Http/Requests/ProfileUpdateRequest.php new file mode 100644 index 0000000..3622a8f --- /dev/null +++ b/app/app/Http/Requests/ProfileUpdateRequest.php @@ -0,0 +1,30 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => ['required', 'string', 'max:255'], + 'email' => [ + 'required', + 'string', + 'lowercase', + 'email', + 'max:255', + Rule::unique(User::class)->ignore($this->user()->id), + ], + ]; + } +} diff --git a/app/app/Mail/MailketingTransport.php b/app/app/Mail/MailketingTransport.php new file mode 100644 index 0000000..6ca48d3 --- /dev/null +++ b/app/app/Mail/MailketingTransport.php @@ -0,0 +1,88 @@ +getOriginalMessage(); + + if (! $email instanceof Email) { + throw new TransportException('Mailketing transport only supports Symfony Email messages.'); + } + + if ($email->getAttachments()) { + throw new TransportException('Mailketing transport does not support attachments without URL references.'); + } + + $from = $email->getFrom()[0] ?? null; + $fromName = $from?->getName() ?: $this->defaultFromName ?: ''; + $fromEmail = $from?->getAddress() ?: $this->defaultFromEmail ?: ''; + + if ($fromEmail === '') { + throw new TransportException('Mailketing transport requires a from email address.'); + } + + $subject = $email->getSubject() ?? ''; + $content = $email->getHtmlBody() ?? $email->getTextBody() ?? ''; + + $recipients = array_merge( + $email->getTo(), + $email->getCc(), + $email->getBcc(), + ); + + if ($recipients === []) { + throw new TransportException('Mailketing transport requires at least one recipient.'); + } + + foreach ($recipients as $recipient) { + $response = Http::asForm() + ->timeout($this->timeoutSeconds) + ->post($this->endpoint, [ + 'api_token' => $this->apiToken, + 'from_name' => $fromName, + 'from_email' => $fromEmail, + 'recipient' => $recipient->getAddress(), + 'subject' => $subject, + 'content' => $content, + ]); + + if (! $response->ok()) { + throw new TransportException(sprintf( + 'Mailketing request failed (%s): %s', + $response->status(), + $response->body() + )); + } + + $payload = $response->json(); + if (is_array($payload) && (($payload['status'] ?? null) !== 'success')) { + $detail = $payload['response'] ?? $payload['message'] ?? 'unknown'; + throw new TransportException('Mailketing responded with an error: '.$detail); + } + } + } +} diff --git a/app/app/Mail/TestMailketing.php b/app/app/Mail/TestMailketing.php new file mode 100644 index 0000000..f23e78d --- /dev/null +++ b/app/app/Mail/TestMailketing.php @@ -0,0 +1,23 @@ +subject('Dewemoji test email') + ->view('emails.test', [ + 'actionUrl' => $actionUrl, + ]); + } +} diff --git a/app/app/Models/AdminAuditLog.php b/app/app/Models/AdminAuditLog.php new file mode 100644 index 0000000..ebf9add --- /dev/null +++ b/app/app/Models/AdminAuditLog.php @@ -0,0 +1,20 @@ + 'array', + ]; +} diff --git a/app/app/Models/Order.php b/app/app/Models/Order.php new file mode 100644 index 0000000..be10121 --- /dev/null +++ b/app/app/Models/Order.php @@ -0,0 +1,31 @@ +belongsTo(User::class); + } + + public function payments(): HasMany + { + return $this->hasMany(Payment::class); + } +} diff --git a/app/app/Models/Payment.php b/app/app/Models/Payment.php new file mode 100644 index 0000000..2677310 --- /dev/null +++ b/app/app/Models/Payment.php @@ -0,0 +1,36 @@ + 'array', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } + + public function order(): BelongsTo + { + return $this->belongsTo(Order::class); + } +} diff --git a/app/app/Models/PricingChange.php b/app/app/Models/PricingChange.php new file mode 100644 index 0000000..4a752f7 --- /dev/null +++ b/app/app/Models/PricingChange.php @@ -0,0 +1,19 @@ + 'array', + 'after' => 'array', + ]; +} diff --git a/app/app/Models/PricingPlan.php b/app/app/Models/PricingPlan.php new file mode 100644 index 0000000..ea36cf8 --- /dev/null +++ b/app/app/Models/PricingPlan.php @@ -0,0 +1,23 @@ + 'integer', + 'meta' => 'array', + ]; +} diff --git a/app/app/Models/Setting.php b/app/app/Models/Setting.php new file mode 100644 index 0000000..c246532 --- /dev/null +++ b/app/app/Models/Setting.php @@ -0,0 +1,18 @@ + 'array', + ]; +} diff --git a/app/app/Models/Subscription.php b/app/app/Models/Subscription.php new file mode 100644 index 0000000..c75d391 --- /dev/null +++ b/app/app/Models/Subscription.php @@ -0,0 +1,33 @@ + 'datetime', + 'expires_at' => 'datetime', + 'canceled_at' => 'datetime', + 'next_renewal_at' => 'datetime', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/app/Models/User.php b/app/app/Models/User.php index 749c7b7..5edeb1f 100644 --- a/app/app/Models/User.php +++ b/app/app/Models/User.php @@ -2,15 +2,18 @@ namespace App\Models; -// use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract; +use Illuminate\Auth\MustVerifyEmail; +use App\Notifications\ResetPasswordNotification; +use App\Notifications\VerifyEmailNotification; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; -class User extends Authenticatable +class User extends Authenticatable implements MustVerifyEmailContract { /** @use HasFactory<\Database\Factories\UserFactory> */ - use HasFactory, Notifiable; + use HasFactory, Notifiable, MustVerifyEmail; /** * The attributes that are mass assignable. @@ -21,6 +24,8 @@ class User extends Authenticatable 'name', 'email', 'password', + 'role', + 'tier', ]; /** @@ -45,4 +50,19 @@ class User extends Authenticatable 'password' => 'hashed', ]; } + + public function isAdmin(): bool + { + return $this->role === 'admin'; + } + + public function sendEmailVerificationNotification(): void + { + $this->notify(new VerifyEmailNotification()); + } + + public function sendPasswordResetNotification($token): void + { + $this->notify(new ResetPasswordNotification($token)); + } } diff --git a/app/app/Models/UserApiKey.php b/app/app/Models/UserApiKey.php new file mode 100644 index 0000000..b899d68 --- /dev/null +++ b/app/app/Models/UserApiKey.php @@ -0,0 +1,28 @@ + 'datetime', + 'revoked_at' => 'datetime', + ]; + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/app/Models/UserKeyword.php b/app/app/Models/UserKeyword.php new file mode 100644 index 0000000..098a951 --- /dev/null +++ b/app/app/Models/UserKeyword.php @@ -0,0 +1,21 @@ +belongsTo(User::class); + } +} diff --git a/app/app/Models/WebhookEvent.php b/app/app/Models/WebhookEvent.php new file mode 100644 index 0000000..cc4f5f9 --- /dev/null +++ b/app/app/Models/WebhookEvent.php @@ -0,0 +1,27 @@ + 'array', + 'headers' => 'array', + 'received_at' => 'datetime', + 'processed_at' => 'datetime', + ]; +} diff --git a/app/app/Notifications/ResetPasswordNotification.php b/app/app/Notifications/ResetPasswordNotification.php new file mode 100644 index 0000000..97b0e4b --- /dev/null +++ b/app/app/Notifications/ResetPasswordNotification.php @@ -0,0 +1,20 @@ +resetUrl($notifiable); + + return (new MailMessage) + ->subject('Reset your password') + ->view('emails.reset-password', [ + 'resetUrl' => $resetUrl, + ]); + } +} diff --git a/app/app/Notifications/VerifyEmailNotification.php b/app/app/Notifications/VerifyEmailNotification.php new file mode 100644 index 0000000..9dbbf64 --- /dev/null +++ b/app/app/Notifications/VerifyEmailNotification.php @@ -0,0 +1,20 @@ +verificationUrl($notifiable); + + return (new MailMessage) + ->subject('Verify your email') + ->view('emails.verify-email', [ + 'verificationUrl' => $verificationUrl, + ]); + } +} diff --git a/app/app/Providers/AppServiceProvider.php b/app/app/Providers/AppServiceProvider.php index 452e6b6..08a8ada 100644 --- a/app/app/Providers/AppServiceProvider.php +++ b/app/app/Providers/AppServiceProvider.php @@ -3,6 +3,9 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Facades\Gate; +use Illuminate\Support\Facades\Mail; +use App\Mail\MailketingTransport; class AppServiceProvider extends ServiceProvider { @@ -19,6 +22,18 @@ class AppServiceProvider extends ServiceProvider */ public function boot(): void { - // + Gate::define('admin', function ($user) { + return $user && method_exists($user, 'isAdmin') ? $user->isAdmin() : false; + }); + + Mail::extend('mailketing', function (array $config) { + return new MailketingTransport( + apiToken: (string) ($config['token'] ?? ''), + endpoint: (string) ($config['endpoint'] ?? 'https://api.mailketing.co.id/api/v1/send'), + defaultFromName: config('mail.from.name'), + defaultFromEmail: config('mail.from.address'), + timeoutSeconds: (int) ($config['timeout'] ?? 10), + ); + }); } } diff --git a/app/app/Services/Auth/ApiKeyService.php b/app/app/Services/Auth/ApiKeyService.php new file mode 100644 index 0000000..69a01b5 --- /dev/null +++ b/app/app/Services/Auth/ApiKeyService.php @@ -0,0 +1,76 @@ +header('Authorization', '')); + if (str_starts_with($auth, 'Bearer ')) { + return trim(substr($auth, 7)); + } + + return trim((string) $request->header('X-Api-Key', '')); + } + + public function hashKey(string $key): string + { + return hash('sha256', $key); + } + + public function prefix(string $key): string + { + return substr($key, 0, 8); + } + + public function resolveUser(Request $request): ?User + { + $key = $this->parseKey($request); + if ($key === '') { + return null; + } + + $record = UserApiKey::where('key_hash', $this->hashKey($key)) + ->whereNull('revoked_at') + ->first(); + + if (!$record) { + return null; + } + + $record->last_used_at = Carbon::now(); + $record->save(); + + $user = $record->user; + if (!$user || (string) $user->tier !== 'personal') { + return null; + } + + return $user; + } + + public function issueKey(User $user, ?string $name = null): array + { + $plain = 'dew_'.bin2hex(random_bytes(16)); + $hash = $this->hashKey($plain); + $prefix = $this->prefix($plain); + + $record = UserApiKey::create([ + 'user_id' => $user->id, + 'key_hash' => $hash, + 'key_prefix' => $prefix, + 'name' => $name, + ]); + + return [ + 'plain' => $plain, + 'record' => $record, + ]; + } +} diff --git a/app/app/Services/Billing/PayPalPlanSyncService.php b/app/app/Services/Billing/PayPalPlanSyncService.php new file mode 100644 index 0000000..ee84946 --- /dev/null +++ b/app/app/Services/Billing/PayPalPlanSyncService.php @@ -0,0 +1,319 @@ + 0, + 'updated' => 0, + 'deactivated' => 0, + 'skipped' => 0, + ]; + + $token = $this->getAccessToken($mode); + if (!$token) { + Log::warning('PayPal plan sync aborted: missing access token', ['mode' => $mode]); + return $result; + } + + $productId = $this->ensureProduct($mode, $token); + if (!$productId) { + Log::warning('PayPal plan sync aborted: missing product id', ['mode' => $mode]); + return $result; + } + + $plans = PricingPlan::whereIn('code', ['personal_monthly', 'personal_annual'])->get(); + $keepIds = []; + foreach ($plans as $plan) { + $currentMeta = $plan->meta ?? []; + $currentPlanId = $currentMeta['paypal'][$mode]['plan']['id'] ?? null; + $history = $currentMeta['paypal'][$mode]['plan']['history'] ?? []; + if ($currentPlanId) { + $history = array_values(array_unique(array_merge([$currentPlanId], $history))); + } + + $amountUsd = $this->toUsdAmount($plan->amount); + $existing = $currentPlanId ? $this->getPlan($mode, $token, $currentPlanId) : null; + $existingAmount = $existing['billing_cycles'][0]['pricing_scheme']['fixed_price']['value'] ?? null; + + if ($existing && $existingAmount !== null && (float) $existingAmount === (float) $amountUsd) { + $currentMeta['paypal'][$mode]['plan'] = [ + 'id' => $currentPlanId, + 'amount_usd' => $amountUsd, + 'history' => $history, + 'synced_at' => now()->toIso8601String(), + ]; + $plan->update(['meta' => $currentMeta]); + if ($currentPlanId) { + $keepIds[] = $currentPlanId; + } + $result['skipped']++; + continue; + } + + $newPlanId = $this->createPlan($mode, $token, $productId, $plan->code, $plan->name, $amountUsd, $plan->period); + if (!$newPlanId) { + $result['skipped']++; + continue; + } + + $currentMeta['paypal'][$mode]['plan'] = [ + 'id' => $newPlanId, + 'amount_usd' => $amountUsd, + 'history' => $history, + 'synced_at' => now()->toIso8601String(), + ]; + + $plan->update(['meta' => $currentMeta]); + if ($currentPlanId) { + $result['updated']++; + } else { + $result['created']++; + } + $keepIds[] = $newPlanId; + + if ($this->canDeactivate($plan->code)) { + foreach ($history as $oldId) { + if ($oldId === $newPlanId) { + continue; + } + if ($this->deactivatePlan($mode, $token, $oldId)) { + $result['deactivated']++; + } + } + } + } + + // Deactivate any other active plans under this product to avoid confusion + $deactivated = $this->deactivateOtherPlansForProduct($mode, $token, $productId, $keepIds); + $result['deactivated'] += $deactivated; + + return $result; + } + + private function toUsdAmount(int $idrAmount): string + { + $rate = (int) config('dewemoji.pricing.usd_rate', 15000); + $usd = $rate > 0 ? $idrAmount / $rate : 0; + return number_format(max($usd, 1), 2, '.', ''); + } + + private function canDeactivate(string $planCode): bool + { + $activeCount = \App\Models\Subscription::query() + ->where('provider', 'paypal') + ->where('status', 'active') + ->where('plan', $planCode) + ->count(); + + return $activeCount === 0; + } + + private function getAccessToken(string $mode): ?string + { + $clientId = config("dewemoji.billing.providers.paypal.{$mode}.client_id"); + $clientSecret = config("dewemoji.billing.providers.paypal.{$mode}.client_secret"); + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + + if (!$clientId || !$clientSecret || !$apiBase) { + return null; + } + + $res = Http::asForm() + ->withBasicAuth($clientId, $clientSecret) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/oauth2/token', [ + 'grant_type' => 'client_credentials', + ]); + + if (!$res->ok()) { + Log::warning('PayPal auth failed', ['body' => $res->body()]); + return null; + } + + return $res->json('access_token'); + } + + private function ensureProduct(string $mode, string $token): ?string + { + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $list = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->get(rtrim($apiBase, '/').'/v1/catalogs/products', [ + 'page_size' => 20, + 'page' => 1, + ]); + + if ($list->ok()) { + $items = $list->json('products') ?? []; + foreach ($items as $item) { + if (($item['custom_id'] ?? '') === 'dewemoji-personal') { + return $item['id'] ?? null; + } + } + } + + $payload = [ + 'name' => 'Dewemoji Personal', + 'type' => 'SERVICE', + 'category' => 'SOFTWARE', + 'custom_id' => 'dewemoji-personal', + ]; + + $create = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/catalogs/products', $payload); + $createdId = $create->json('id'); + if ($createdId) { + if (!$create->ok()) { + Log::warning('PayPal product create returned non-OK but provided id', [ + 'status' => $create->status(), + 'body' => $create->body(), + ]); + } + return $createdId; + } + + Log::warning('PayPal product create failed', [ + 'status' => $create->status(), + 'body' => $create->body(), + ]); + return null; + } + + private function createPlan( + string $mode, + string $token, + string $productId, + string $code, + string $name, + string $amountUsd, + ?string $period + ): ?string { + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $intervalUnit = $period === 'year' ? 'YEAR' : 'MONTH'; + + $payload = [ + 'product_id' => $productId, + 'name' => $name, + 'description' => "{$name} subscription", + 'billing_cycles' => [ + [ + 'frequency' => [ + 'interval_unit' => $intervalUnit, + 'interval_count' => 1, + ], + 'tenure_type' => 'REGULAR', + 'sequence' => 1, + 'total_cycles' => 0, + 'pricing_scheme' => [ + 'fixed_price' => [ + 'value' => $amountUsd, + 'currency_code' => 'USD', + ], + ], + ], + ], + 'payment_preferences' => [ + 'auto_bill_outstanding' => true, + 'setup_fee_failure_action' => 'CONTINUE', + 'payment_failure_threshold' => 3, + ], + ]; + + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/billing/plans', $payload); + + $planId = $res->json('id'); + if ($planId) { + if (!$res->ok()) { + Log::warning('PayPal plan create returned non-OK but provided id', [ + 'code' => $code, + 'status' => $res->status(), + 'body' => $res->body(), + ]); + } + return $planId; + } + + Log::warning('PayPal plan create failed', [ + 'code' => $code, + 'status' => $res->status(), + 'body' => $res->body(), + ]); + return null; + } + + private function getPlan(string $mode, string $token, string $planId): ?array + { + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->get(rtrim($apiBase, '/').'/v1/billing/plans/'.$planId); + + if (!$res->ok()) { + return null; + } + + return $res->json(); + } + + private function deactivatePlan(string $mode, string $token, string $planId): bool + { + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->post(rtrim($apiBase, '/').'/v1/billing/plans/'.$planId.'/deactivate'); + + return $res->ok(); + } + + private function deactivateOtherPlansForProduct(string $mode, string $token, string $productId, array $keepIds): int + { + $apiBase = config("dewemoji.billing.providers.paypal.{$mode}.api_base"); + $res = Http::withToken($token) + ->timeout((int) config('dewemoji.billing.providers.paypal.timeout', 10)) + ->get(rtrim($apiBase, '/').'/v1/billing/plans', [ + 'product_id' => $productId, + 'page_size' => 20, + 'page' => 1, + ]); + + if (!$res->ok()) { + return 0; + } + + $items = $res->json('plans') ?? []; + if (!is_array($items)) { + return 0; + } + + $count = 0; + foreach ($items as $plan) { + $id = $plan['id'] ?? null; + $status = strtoupper((string) ($plan['status'] ?? '')); + if (!$id || in_array($id, $keepIds, true)) { + continue; + } + if ($status !== 'ACTIVE') { + continue; + } + if ($this->deactivatePlan($mode, $token, $id)) { + $count++; + } + } + + return $count; + } +} diff --git a/app/app/Services/Billing/PaypalWebhookProcessor.php b/app/app/Services/Billing/PaypalWebhookProcessor.php new file mode 100644 index 0000000..6192edb --- /dev/null +++ b/app/app/Services/Billing/PaypalWebhookProcessor.php @@ -0,0 +1,78 @@ + $payload + */ + public function process(string $eventType, array $payload): void + { + $resource = $payload['resource'] ?? []; + if (!is_array($resource)) { + return; + } + + $subscriptionId = (string) ($resource['id'] ?? ''); + $email = (string) ($resource['subscriber']['email_address'] ?? ''); + + if ($subscriptionId === '' || $email === '') { + return; + } + + $user = User::where('email', $email)->first(); + if (!$user) { + throw new \RuntimeException('User not found for webhook email.'); + } + + if ($eventType === 'BILLING.SUBSCRIPTION.ACTIVATED') { + Subscription::create([ + 'user_id' => $user->id, + 'plan' => 'personal', + 'status' => 'active', + 'provider' => 'paypal', + 'provider_ref' => $subscriptionId, + 'started_at' => now(), + 'expires_at' => null, + ]); + $user->update(['tier' => 'personal']); + return; + } + + if ($eventType === 'BILLING.SUBSCRIPTION.CANCELLED' || $eventType === 'BILLING.SUBSCRIPTION.SUSPENDED') { + Subscription::where('user_id', $user->id) + ->where('provider', 'paypal') + ->where('provider_ref', $subscriptionId) + ->where('status', 'active') + ->update([ + 'status' => $eventType === 'BILLING.SUBSCRIPTION.CANCELLED' ? 'cancelled' : 'suspended', + 'expires_at' => now(), + ]); + + $this->syncUserTier($user->id); + } + } + + private function syncUserTier(int $userId): void + { + $active = Subscription::where('user_id', $userId) + ->where('status', 'active') + ->where(function ($q): void { + $q->whereNull('expires_at') + ->orWhere('expires_at', '>', now()); + }) + ->exists(); + + User::where('id', $userId)->update([ + 'tier' => $active ? 'personal' : 'free', + ]); + if (!$active) { + UserApiKey::where('user_id', $userId)->update(['revoked_at' => now()]); + } + } +} diff --git a/app/app/Services/Extension/ExtensionVerificationService.php b/app/app/Services/Extension/ExtensionVerificationService.php new file mode 100644 index 0000000..03b3d56 --- /dev/null +++ b/app/app/Services/Extension/ExtensionVerificationService.php @@ -0,0 +1,60 @@ + $expectedExtensionIds + */ + public function verifyToken(string $token, array $expectedExtensionIds): bool + { + if ($token === '') { + return false; + } + + $config = config('dewemoji.extension_verification', []); + if (!(bool) ($config['enabled'] ?? true)) { + return true; + } + + $projectId = (string) ($config['project_id'] ?? ''); + $serverKey = (string) ($config['server_key'] ?? ''); + if ($projectId === '' || $serverKey === '') { + return false; + } + + $cacheKey = 'dw_ext_verify_'.sha1($token); + $ttl = max((int) ($config['cache_ttl'] ?? 3600), 60); + + return Cache::remember($cacheKey, $ttl, function () use ($token, $serverKey, $expectedExtensionIds): bool { + $url = 'https://iid.googleapis.com/iid/info/'.$token.'?details=true'; + $response = Http::withHeaders([ + 'Authorization' => 'key='.$serverKey, + ])->get($url); + + if (!$response->ok()) { + return false; + } + + $data = $response->json(); + if (!is_array($data)) { + return false; + } + + $application = (string) ($data['application'] ?? ''); + if ($application === '') { + return false; + } + + if (count($expectedExtensionIds) === 0) { + return true; + } + + return in_array($application, $expectedExtensionIds, true); + }); + } +} diff --git a/app/app/Services/System/SettingsService.php b/app/app/Services/System/SettingsService.php new file mode 100644 index 0000000..c28ab73 --- /dev/null +++ b/app/app/Services/System/SettingsService.php @@ -0,0 +1,46 @@ + + */ + public function all(): array + { + return Cache::remember(self::CACHE_KEY, self::CACHE_TTL, function (): array { + $out = []; + foreach (Setting::all(['key', 'value']) as $setting) { + $out[$setting->key] = $setting->value; + } + return $out; + }); + } + + public function get(string $key, mixed $default = null): mixed + { + $all = $this->all(); + return array_key_exists($key, $all) ? $all[$key] : $default; + } + + /** + * @param array $values + */ + public function setMany(array $values, ?string $updatedBy = null): void + { + foreach ($values as $key => $value) { + Setting::updateOrCreate( + ['key' => (string) $key], + ['value' => $value, 'updated_by' => $updatedBy] + ); + } + Cache::forget(self::CACHE_KEY); + } +} diff --git a/app/app/View/Components/AppLayout.php b/app/app/View/Components/AppLayout.php new file mode 100644 index 0000000..de0d46f --- /dev/null +++ b/app/app/View/Components/AppLayout.php @@ -0,0 +1,17 @@ +withRouting( - web: __DIR__.'/../routes/web.php', + web: [ + __DIR__.'/../routes/web.php', + __DIR__.'/../routes/dashboard.php', + ], api: __DIR__.'/../routes/api.php', apiPrefix: '', commands: __DIR__.'/../routes/console.php', diff --git a/app/composer.json b/app/composer.json index 72dfb9a..b62117a 100644 --- a/app/composer.json +++ b/app/composer.json @@ -15,6 +15,7 @@ }, "require-dev": { "fakerphp/faker": "^1.23", + "laravel/breeze": "*", "laravel/pail": "^1.2.2", "laravel/pint": "^1.24", "laravel/sail": "^1.41", diff --git a/app/composer.lock b/app/composer.lock index c18749c..25549d8 100644 --- a/app/composer.lock +++ b/app/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "79cd7bb4d53c32c6fa51bec0f240bd28", + "content-hash": "4f99c59819e467f4dda33565265ea286", "packages": [ { "name": "brick/math", @@ -6182,6 +6182,67 @@ }, "time": "2025-04-30T06:54:44+00:00" }, + { + "name": "laravel/breeze", + "version": "v2.3.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/breeze.git", + "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/breeze/zipball/1a29c5792818bd4cddf70b5f743a227e02fbcfcd", + "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd", + "shasum": "" + }, + "require": { + "illuminate/console": "^11.0|^12.0", + "illuminate/filesystem": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "illuminate/validation": "^11.0|^12.0", + "php": "^8.2.0", + "symfony/console": "^7.0" + }, + "require-dev": { + "laravel/framework": "^11.0|^12.0", + "orchestra/testbench-core": "^9.0|^10.0", + "phpstan/phpstan": "^2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Breeze\\BreezeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Breeze\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Minimal Laravel authentication scaffolding with Blade and Tailwind.", + "keywords": [ + "auth", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/breeze/issues", + "source": "https://github.com/laravel/breeze" + }, + "time": "2025-07-18T18:49:59+00:00" + }, { "name": "laravel/pail", "version": "v1.2.4", diff --git a/app/config/dewemoji.php b/app/config/dewemoji.php index 8d3ba49..d4b65f2 100644 --- a/app/config/dewemoji.php +++ b/app/config/dewemoji.php @@ -44,19 +44,109 @@ return [ // Optional stub keys for local testing without external HTTP calls. 'test_keys' => array_values(array_filter(array_map('trim', explode(',', (string) env('DEWEMOJI_MAYAR_TEST_KEYS', ''))))), ], + 'paypal' => [ + 'enabled' => filter_var(env('DEWEMOJI_PAYPAL_ENABLED', false), FILTER_VALIDATE_BOOL), + 'timeout' => (int) env('DEWEMOJI_PAYPAL_TIMEOUT', 10), + 'webhook_ids' => [ + 'sandbox' => env('DEWEMOJI_PAYPAL_SANDBOX_WEBHOOK_ID', ''), + 'live' => env('DEWEMOJI_PAYPAL_LIVE_WEBHOOK_ID', ''), + ], + 'plan_ids' => [ + 'sandbox' => [ + 'personal_monthly' => env('DEWEMOJI_PAYPAL_SANDBOX_PLAN_PERSONAL_MONTHLY', ''), + 'personal_annual' => env('DEWEMOJI_PAYPAL_SANDBOX_PLAN_PERSONAL_ANNUAL', ''), + ], + 'live' => [ + 'personal_monthly' => env('DEWEMOJI_PAYPAL_LIVE_PLAN_PERSONAL_MONTHLY', ''), + 'personal_annual' => env('DEWEMOJI_PAYPAL_LIVE_PLAN_PERSONAL_ANNUAL', ''), + ], + ], + 'sandbox' => [ + 'api_base' => env('DEWEMOJI_PAYPAL_SANDBOX_API_BASE', 'https://api-m.sandbox.paypal.com'), + 'web_base' => env('DEWEMOJI_PAYPAL_SANDBOX_WEB_BASE', 'https://www.sandbox.paypal.com'), + 'client_id' => env('DEWEMOJI_PAYPAL_SANDBOX_CLIENT_ID', ''), + 'client_secret' => env('DEWEMOJI_PAYPAL_SANDBOX_CLIENT_SECRET', ''), + ], + 'live' => [ + 'api_base' => env('DEWEMOJI_PAYPAL_LIVE_API_BASE', 'https://api-m.paypal.com'), + 'web_base' => env('DEWEMOJI_PAYPAL_LIVE_WEB_BASE', 'https://www.paypal.com'), + 'client_id' => env('DEWEMOJI_PAYPAL_LIVE_CLIENT_ID', ''), + 'client_secret' => env('DEWEMOJI_PAYPAL_LIVE_CLIENT_SECRET', ''), + ], + ], + 'pakasir' => [ + 'enabled' => filter_var(env('DEWEMOJI_PAKASIR_ENABLED', false), FILTER_VALIDATE_BOOL), + 'api_base' => env('DEWEMOJI_PAKASIR_API_BASE', ''), + 'api_key' => env('DEWEMOJI_PAKASIR_API_KEY', ''), + 'project' => env('DEWEMOJI_PAKASIR_PROJECT', ''), + 'timeout' => (int) env('DEWEMOJI_PAKASIR_TIMEOUT', 10), + ], ], ], 'cors' => [ 'allowed_origins' => array_values(array_filter(array_map('trim', explode(',', (string) env('DEWEMOJI_ALLOWED_ORIGINS', 'http://127.0.0.1:8000,http://localhost:8000,https://dewemoji.com,https://www.dewemoji.com'))))), 'allow_methods' => 'GET, POST, OPTIONS', - 'allow_headers' => 'Content-Type, Authorization, X-License-Key, X-Account-Id, X-Dewemoji-Frontend', + 'allow_headers' => 'Content-Type, Authorization, X-License-Key, X-Api-Key, X-Admin-Token, X-Account-Id, X-Dewemoji-Frontend, X-Extension-Token', + ], + + 'admin' => [ + 'token' => env('DEWEMOJI_ADMIN_TOKEN', ''), + ], + + 'pricing' => [ + 'usd_rate' => (int) env('DEWEMOJI_USD_RATE', 15000), + 'defaults' => [ + [ + 'code' => 'personal_monthly', + 'name' => 'Personal Monthly', + 'currency' => 'IDR', + 'amount' => 30000, + 'period' => 'month', + 'status' => 'active', + ], + [ + 'code' => 'personal_annual', + 'name' => 'Personal Annual', + 'currency' => 'IDR', + 'amount' => 300000, + 'period' => 'year', + 'status' => 'active', + ], + [ + 'code' => 'personal_lifetime', + 'name' => 'Personal Lifetime', + 'currency' => 'IDR', + 'amount' => 900000, + 'period' => null, + 'status' => 'active', + ], + ], + ], + + 'payments' => [ + 'qris_url' => env('DEWEMOJI_QRIS_URL', ''), + 'paypal_url' => env('DEWEMOJI_PAYPAL_URL', ''), ], 'frontend' => [ 'header_token' => env('DEWEMOJI_FRONTEND_HEADER', 'web-v1'), ], + 'public_access' => [ + 'enforce_whitelist' => filter_var(env('DEWEMOJI_PUBLIC_ENFORCE', true), FILTER_VALIDATE_BOOL), + 'allowed_origins' => array_values(array_filter(array_map('trim', explode(',', (string) env('DEWEMOJI_PUBLIC_ORIGINS', 'http://127.0.0.1:8000,http://localhost:8000,https://dewemoji.com,https://www.dewemoji.com'))))), + 'extension_ids' => array_values(array_filter(array_map('trim', explode(',', (string) env('DEWEMOJI_EXTENSION_IDS', ''))))), + 'hourly_limit' => (int) env('DEWEMOJI_PUBLIC_HOURLY_LIMIT', 5000), + ], + + 'extension_verification' => [ + 'enabled' => filter_var(env('DEWEMOJI_EXTENSION_VERIFY_ENABLED', true), FILTER_VALIDATE_BOOL), + 'project_id' => env('DEWEMOJI_GOOGLE_PROJECT_ID', ''), + 'server_key' => env('DEWEMOJI_GOOGLE_SERVER_KEY', ''), + 'cache_ttl' => (int) env('DEWEMOJI_EXTENSION_VERIFY_CACHE_TTL', 3600), + ], + 'metrics' => [ 'enabled' => filter_var(env('DEWEMOJI_METRICS_ENABLED', true), FILTER_VALIDATE_BOOL), 'token' => (string) env('DEWEMOJI_METRICS_TOKEN', ''), diff --git a/app/config/mail.php b/app/config/mail.php index 522b284..3e7c7f8 100644 --- a/app/config/mail.php +++ b/app/config/mail.php @@ -61,6 +61,13 @@ return [ // ], ], + 'mailketing' => [ + 'transport' => 'mailketing', + 'endpoint' => env('MAILKETING_API_URL', 'https://api.mailketing.co.id/api/v1/send'), + 'token' => env('MAILKETING_API_TOKEN'), + 'timeout' => env('MAILKETING_TIMEOUT', 10), + ], + 'resend' => [ 'transport' => 'resend', ], diff --git a/app/database/migrations/2026_02_08_000100_add_tier_to_users.php b/app/database/migrations/2026_02_08_000100_add_tier_to_users.php new file mode 100644 index 0000000..b3be880 --- /dev/null +++ b/app/database/migrations/2026_02_08_000100_add_tier_to_users.php @@ -0,0 +1,22 @@ +string('tier', 20)->default('free')->after('password'); + }); + } + + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('tier'); + }); + } +}; diff --git a/app/database/migrations/2026_02_08_000200_create_user_api_keys_table.php b/app/database/migrations/2026_02_08_000200_create_user_api_keys_table.php new file mode 100644 index 0000000..59803e2 --- /dev/null +++ b/app/database/migrations/2026_02_08_000200_create_user_api_keys_table.php @@ -0,0 +1,27 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('key_hash', 64)->unique(); + $table->string('key_prefix', 12)->index(); + $table->string('name', 100)->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('revoked_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_api_keys'); + } +}; diff --git a/app/database/migrations/2026_02_08_000300_create_user_keywords_table.php b/app/database/migrations/2026_02_08_000300_create_user_keywords_table.php new file mode 100644 index 0000000..a23e174 --- /dev/null +++ b/app/database/migrations/2026_02_08_000300_create_user_keywords_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('emoji_slug'); + $table->string('keyword', 200); + $table->string('lang', 10)->default('und'); + $table->timestamps(); + + $table->unique(['user_id', 'emoji_slug', 'keyword']); + $table->index(['user_id', 'emoji_slug']); + }); + } + + public function down(): void + { + Schema::dropIfExists('user_keywords'); + } +}; diff --git a/app/database/migrations/2026_02_08_000400_create_subscriptions_table.php b/app/database/migrations/2026_02_08_000400_create_subscriptions_table.php new file mode 100644 index 0000000..d9681e3 --- /dev/null +++ b/app/database/migrations/2026_02_08_000400_create_subscriptions_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('plan', 20); + $table->string('status', 20)->default('active'); + $table->string('provider', 20)->nullable(); + $table->string('provider_ref', 100)->nullable(); + $table->timestamp('started_at')->nullable(); + $table->timestamp('expires_at')->nullable(); + $table->timestamp('canceled_at')->nullable(); + $table->timestamp('next_renewal_at')->nullable(); + $table->timestamps(); + + $table->index(['user_id', 'status']); + }); + } + + public function down(): void + { + Schema::dropIfExists('subscriptions'); + } +}; diff --git a/app/database/migrations/2026_02_08_000500_create_pricing_plans_table.php b/app/database/migrations/2026_02_08_000500_create_pricing_plans_table.php new file mode 100644 index 0000000..68ebd69 --- /dev/null +++ b/app/database/migrations/2026_02_08_000500_create_pricing_plans_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('code', 30)->unique(); + $table->string('name', 50); + $table->string('currency', 10)->default('IDR'); + $table->unsignedBigInteger('amount'); + $table->string('period', 20)->nullable(); + $table->string('status', 20)->default('active'); + $table->json('meta')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('pricing_plans'); + } +}; diff --git a/app/database/migrations/2026_02_08_000600_create_pricing_changes_table.php b/app/database/migrations/2026_02_08_000600_create_pricing_changes_table.php new file mode 100644 index 0000000..090e43e --- /dev/null +++ b/app/database/migrations/2026_02_08_000600_create_pricing_changes_table.php @@ -0,0 +1,24 @@ +id(); + $table->string('admin_ref', 120)->nullable(); + $table->json('before')->nullable(); + $table->json('after')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('pricing_changes'); + } +}; diff --git a/app/database/migrations/2026_02_08_000700_create_settings_table.php b/app/database/migrations/2026_02_08_000700_create_settings_table.php new file mode 100644 index 0000000..81ac148 --- /dev/null +++ b/app/database/migrations/2026_02_08_000700_create_settings_table.php @@ -0,0 +1,24 @@ +id(); + $table->string('key', 120)->unique(); + $table->json('value')->nullable(); + $table->string('updated_by', 120)->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('settings'); + } +}; diff --git a/app/database/migrations/2026_02_08_000800_create_webhook_events_table.php b/app/database/migrations/2026_02_08_000800_create_webhook_events_table.php new file mode 100644 index 0000000..a0a7b9c --- /dev/null +++ b/app/database/migrations/2026_02_08_000800_create_webhook_events_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('provider', 50); + $table->string('event_type', 120)->nullable(); + $table->string('status', 50)->default('received'); + $table->json('payload')->nullable(); + $table->text('error')->nullable(); + $table->timestamp('received_at')->nullable(); + $table->timestamp('processed_at')->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('webhook_events'); + } +}; diff --git a/app/database/migrations/2026_02_08_000900_add_event_id_to_webhook_events_table.php b/app/database/migrations/2026_02_08_000900_add_event_id_to_webhook_events_table.php new file mode 100644 index 0000000..5e65fb4 --- /dev/null +++ b/app/database/migrations/2026_02_08_000900_add_event_id_to_webhook_events_table.php @@ -0,0 +1,26 @@ +string('event_id', 120)->nullable()->after('provider'); + $table->json('headers')->nullable()->after('payload'); + $table->index(['provider', 'event_id']); + }); + } + + public function down(): void + { + Schema::table('webhook_events', function (Blueprint $table): void { + $table->dropIndex(['provider', 'event_id']); + $table->dropColumn('event_id'); + $table->dropColumn('headers'); + }); + } +}; diff --git a/app/database/migrations/2026_02_09_000300_add_role_to_users_table.php b/app/database/migrations/2026_02_09_000300_add_role_to_users_table.php new file mode 100644 index 0000000..ae6b014 --- /dev/null +++ b/app/database/migrations/2026_02_09_000300_add_role_to_users_table.php @@ -0,0 +1,30 @@ +string('role', 32)->default('user')->after('password'); + $table->index('role'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropIndex(['role']); + $table->dropColumn('role'); + }); + } +}; diff --git a/app/database/migrations/2026_02_09_000400_create_admin_audit_logs_table.php b/app/database/migrations/2026_02_09_000400_create_admin_audit_logs_table.php new file mode 100644 index 0000000..080fb8a --- /dev/null +++ b/app/database/migrations/2026_02_09_000400_create_admin_audit_logs_table.php @@ -0,0 +1,25 @@ +id(); + $table->unsignedBigInteger('admin_id')->nullable()->index(); + $table->string('admin_email', 255)->nullable()->index(); + $table->string('action', 64)->index(); + $table->json('payload')->nullable(); + $table->string('ip_address', 64)->nullable(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('admin_audit_logs'); + } +}; diff --git a/app/database/migrations/2026_02_10_000100_create_orders_table.php b/app/database/migrations/2026_02_10_000100_create_orders_table.php new file mode 100644 index 0000000..efca1d5 --- /dev/null +++ b/app/database/migrations/2026_02_10_000100_create_orders_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->string('plan_code', 40); + $table->string('type', 20); // one_time | subscription + $table->string('currency', 10); + $table->unsignedInteger('amount'); + $table->string('status', 20)->default('pending'); + $table->string('provider', 20)->nullable(); + $table->string('provider_ref', 100)->nullable(); + $table->timestamps(); + + $table->index(['user_id', 'status']); + $table->index(['provider', 'provider_ref']); + }); + } + + public function down(): void + { + Schema::dropIfExists('orders'); + } +}; diff --git a/app/database/migrations/2026_02_10_000200_create_payments_table.php b/app/database/migrations/2026_02_10_000200_create_payments_table.php new file mode 100644 index 0000000..1aa8651 --- /dev/null +++ b/app/database/migrations/2026_02_10_000200_create_payments_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('order_id')->constrained()->cascadeOnDelete(); + $table->string('provider', 20); + $table->string('type', 20); // one_time | subscription + $table->string('plan_code', 40); + $table->string('currency', 10); + $table->unsignedInteger('amount'); + $table->string('status', 20)->default('pending'); + $table->string('provider_ref', 100)->nullable(); + $table->json('raw_payload')->nullable(); + $table->timestamps(); + + $table->index(['user_id', 'status']); + $table->index(['provider', 'provider_ref']); + }); + } + + public function down(): void + { + Schema::dropIfExists('payments'); + } +}; diff --git a/app/database/seeders/DatabaseSeeder.php b/app/database/seeders/DatabaseSeeder.php index 6b901f8..da571f5 100644 --- a/app/database/seeders/DatabaseSeeder.php +++ b/app/database/seeders/DatabaseSeeder.php @@ -15,11 +15,6 @@ class DatabaseSeeder extends Seeder */ public function run(): void { - // User::factory(10)->create(); - - User::factory()->create([ - 'name' => 'Test User', - 'email' => 'test@example.com', - ]); + $this->call(PricingPlanSeeder::class); } } diff --git a/app/database/seeders/PricingPlanSeeder.php b/app/database/seeders/PricingPlanSeeder.php new file mode 100644 index 0000000..7f1c057 --- /dev/null +++ b/app/database/seeders/PricingPlanSeeder.php @@ -0,0 +1,27 @@ + $plan['code']], + [ + 'name' => $plan['name'], + 'currency' => $plan['currency'], + 'amount' => $plan['amount'], + 'period' => $plan['period'], + 'status' => $plan['status'], + 'meta' => $plan['meta'] ?? null, + ] + ); + } + } +} diff --git a/app/dewemoji-billing-integration-plan.md b/app/dewemoji-billing-integration-plan.md new file mode 100644 index 0000000..294a6b0 --- /dev/null +++ b/app/dewemoji-billing-integration-plan.md @@ -0,0 +1,195 @@ +# Dewemoji Billing Integration Plan (QRIS + PayPal) + +This document outlines a proper, production-grade billing flow for Dewemoji using **QRIS (Pakasir)** and **PayPal Subscriptions**, including webhooks, retries, and license activation. + +--- + +## 1) Goals + +- Replace primitive payment links with real provider integrations. +- Support **subscription** billing (monthly/annual) and **one-time lifetime**. +- Activate or revoke licenses based on webhook-confirmed payments. +- Log all webhook events and payment activity for audit. + +--- + +## 2) Data Model + +### `orders` (new) + +Acts as the primary record of what the user is buying. Payments link back to orders. + +- `id` +- `user_id` +- `plan_code` +- `type` (`one_time`, `subscription`) +- `currency` (`IDR`, `USD`) +- `amount` +- `status` (`pending`, `paid`, `failed`, `expired`, `refunded`) +- `provider` (`qris`, `paypal`) +- `provider_ref` +- `created_at`, `updated_at` + +### `payments` (new) + +- `id` +- `user_id` +- `order_id` +- `provider` (`qris`, `paypal`) +- `type` (`one_time`, `subscription`) +- `plan_code` (`personal_monthly`, `personal_annual`, `personal_lifetime`) +- `currency` (`IDR`, `USD`) +- `amount` +- `status` (`pending`, `paid`, `failed`, `expired`, `refunded`) +- `provider_ref` (invoice_id / order_id / subscription_id) +- `raw_payload` (json) +- `created_at`, `updated_at` + +### `subscriptions` (existing) +Extend with: +- `provider` +- `provider_ref` +- `status` (`active`, `pending`, `canceled`, `expired`) +- `started_at`, `expires_at`, `canceled_at` + - `next_renewal_at` (optional) + +### `webhook_events` (existing) +Continue to log inbound payloads and processing status: +- `provider`, `event_type`, `status`, `payload`, `received_at`, `processed_at`, `error_message` + +--- + +## 3) Payment Flow (User Journey) + +### Pricing Page (Frontend) + +Each plan shows: +- **Primary currency** (based on geo + user toggle) +- **Two payment buttons** (real provider flow): + - **QRIS (IDR)** → subscription or one-time + - **PayPal (USD)** → subscription or one-time + +### Backend Endpoints + +#### QRIS (Pakasir) +- `POST /billing/qris/create` + - Creates invoice via Pakasir API + - Stores `payments` with `pending` + - Returns QR payment URL or QR code data +- `GET /billing/qris/return` (optional) + - Shows “pending / processing” state + +#### PayPal Subscriptions +- `POST /billing/paypal/create` + - Creates PayPal subscription + - Stores `payments` with `pending` + - Returns approval URL +- `GET /billing/paypal/return` + - Shows “pending / processing” state + +--- + +## 4) Webhook Processing (Critical) + +Webhook endpoint: +``` +POST /webhooks/{provider} +``` + +Store inbound payloads in `webhook_events`, then process async (queue). + +### PayPal Events +- `BILLING.SUBSCRIPTION.ACTIVATED` → mark subscription active, set `users.tier = personal` +- `BILLING.SUBSCRIPTION.CANCELLED` → mark subscription canceled +- `PAYMENT.SALE.COMPLETED` → mark payment paid +- `PAYMENT.SALE.DENIED` → mark payment failed + +### Pakasir / QRIS Events +- `payment.paid` → mark payment paid, grant access +- `payment.expired` → mark payment failed/expired + +--- + +## 5) License Activation Rules + +When a payment or subscription is confirmed: +- Create or update a `subscriptions` record +- Set `users.tier = personal` +- Store provider refs (`provider_ref`) +- Log admin audit record + +When revoked/expired: +- Update `subscriptions.status` +- Downgrade user if no active subscription remains + +### Renewal Logic (QRIS manual renew) + +- **If still active:** extend from current `expires_at` + - `expires_at = expires_at + duration` +- **If expired:** start from now + - `expires_at = now + duration` + +--- + +## 6) Admin Dashboard Enhancements + +Add or extend: +- **Payments list** (new screen) + - filter by provider/status/currency + - show raw provider ref +- **Subscriptions list** (already exists) + - show provider + status +- **Webhook events** (already exists) + - replay capability + +--- + +## 7) Security & Reliability + +- Validate webhook signatures (PayPal + Pakasir) +- Reject duplicate events (idempotency) +- Use queues for webhook processing +- Log all webhook failures + +--- + +## 8) Required Inputs (From Owner) + +Before implementation: + +1. **Pakasir API docs** (create invoice, webhook payload format) +2. **PayPal API credentials** (client_id, secret, webhook signing key) +3. Confirm **plans & pricing**: + - Monthly + - Annual + - Lifetime + +--- + +## 9) Implementation Phases + +**Phase 1 — Schema + Core Models** +- Add `orders` table +- Add `payments` table (link to orders) +- Extend `subscriptions` +- Update webhook model if needed + +**Phase 2 — Provider APIs** +- Pakasir invoice create +- PayPal subscription create + +**Phase 3 — Webhooks** +- Save raw events +- Process via queue + idempotency + +**Phase 4 — UI** +- Pricing page buttons → real flows +- Admin payment + subscription tools + +--- + +## 10) Notes + +- This plan assumes **proper subscription lifecycle** with webhooks. +- PayPal.me / static links are **not sufficient** for subscriptions. +- All access control must be tied to **confirmed payment status**. diff --git a/app/dewemoji-user-dashboard-implementation-plan.md b/app/dewemoji-user-dashboard-implementation-plan.md new file mode 100644 index 0000000..0588fa4 --- /dev/null +++ b/app/dewemoji-user-dashboard-implementation-plan.md @@ -0,0 +1,143 @@ +# Dewemoji User Dashboard Implementation Plan + +**Source:** `dewemoji-ux-flow-brief.md` +**Goal:** Build the Personal user dashboard + inline personalization flows aligned with the UX brief. + +--- + +## 1) Scope & Principles + +- **Primary flow**: Add keywords directly on emoji detail pages (fast, contextual). +- **Secondary flow**: Manage keywords in the dashboard (bulk + power tools). +- **Zero friction** for Visitors/Free users; gentle upgrade prompts. +- **Shared layout** with admin (same shell, role-based sidebar). + +--- + +## 2) User States & Routing + +### Visitor (non-logged) +- Public search + emoji detail only. +- CTA: “Sign up free” / “Upgrade to Personal”. + +### Free user (logged, no subscription) +- See public content, “Your keywords” section locked. +- Upgrade nudges on detail + empty states in dashboard. + +### Personal user (paid) +- Full access: quick add on detail + dashboard CRUD. + +--- + +## 3) UI Screens (User Dashboard) + +### 3.1 Dashboard shell (shared) +- Same layout as admin (sidebar, top bar). +- Role-based sidebar menu: + - Overview + - My Keywords + - API Keys + - Billing + - Preferences + - Support / Logout + +### 3.2 Overview (user) +- Show: + - Total keywords + - Recent keyword additions (last 7 days) + - Synced devices (optional later) +- Small quick link to “My Keywords”. + +### 3.3 My Keywords (primary management) +- Table: Emoji | Your keywords | Language | Actions +- Toolbar: + - + Add Keyword + - Import JSON + - Export JSON + - Search/filter +- Modal: emoji picker → add keywords + language. + +### 3.4 API Keys +- List user API keys +- Create/revoke key + +### 3.5 Billing +- Current plan + renewal / expiry +- Payment method (future) +- Upgrade CTA if free + +### 3.6 Preferences +- Theme +- Tone lock / preferred skin tone (future) +- Locale + +--- + +## 4) Site Page Enhancements (Non-dashboard) + +### 4.1 Emoji Detail Page (critical) +- Show public keywords for everyone. +- If Personal: show “Your Keywords” list + quick add modal. +- If Free: show locked section + upgrade CTA. +- If Visitor: CTA to sign up. + +### 4.2 Search Results Page +- Personal user: blend public + user keywords. +- Show “Your keyword” badge and “quick edit” button. + +--- + +## 5) API Endpoints (v1) + +### Keyword CRUD +- `GET /v1/emoji/{slug}?include_user_keywords=true` +- `POST /v1/keywords` (add keyword) +- `PUT /v1/keywords/{id}` (edit) +- `DELETE /v1/keywords/{id}` +- `GET /v1/keywords` (list user keywords) + +### User keyword import/export +- `POST /v1/keywords/import` +- `GET /v1/keywords/export` + +### Dashboard data +- `GET /v1/user/summary` (counts + recents) +- `GET /v1/user/apikeys` / `POST /v1/user/apikeys` +- `GET /v1/user/billing` (subscription status) + +--- + +## 6) Database / Models + +Existing: +- `user_keywords` +- `subscriptions` + +Add if needed: +- `user_keyword_imports` (optional audit) + +--- + +## 7) Implementation Phases + +### Phase A — Foundation +- Add user routes + dashboard views +- Layout reuse with role‑based sidebar + +### Phase B — Keywords UX +- Detail page quick add +- Dashboard keyword CRUD + import/export + +### Phase C — Billing & API Keys +- Billing summary + upgrade CTA +- API key list + create/revoke + +--- + +## 8) Acceptance Criteria + +- Personal user can add keywords from detail page in <5 seconds. +- Keyword appears in search results immediately. +- Dashboard keyword table supports filter + edit + delete. +- Free users see upgrade prompts, not broken UI. + diff --git a/app/package-lock.json b/app/package-lock.json new file mode 100644 index 0000000..926565e --- /dev/null +++ b/app/package-lock.json @@ -0,0 +1,3581 @@ +{ + "name": "app", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "apexcharts": "^5.3.6" + }, + "devDependencies": { + "@tailwindcss/forms": "^0.5.2", + "@tailwindcss/vite": "^4.0.0", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", + "axios": "^1.11.0", + "chart.js": "^4.4.1", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^2.0.0", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", + "vite": "^7.0.7" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", + "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", + "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", + "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", + "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", + "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", + "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", + "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", + "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", + "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", + "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", + "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", + "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", + "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", + "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", + "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", + "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", + "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", + "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", + "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", + "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", + "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", + "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", + "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", + "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", + "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@svgdotjs/svg.draggable.js": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.draggable.js/-/svg.draggable.js-3.0.6.tgz", + "integrity": "sha512-7iJFm9lL3C40HQcqzEfezK2l+dW2CpoVY3b77KQGqc8GXWa6LhhmX5Ckv7alQfUXBuZbjpICZ+Dvq1czlGx7gA==", + "license": "MIT", + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@svgdotjs/svg.filter.js": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.filter.js/-/svg.filter.js-3.0.9.tgz", + "integrity": "sha512-/69XMRCDoam2HgC4ldHIaDgeQf1ViHIsa0Ld4uWgiXtZ+E24DWHe/9Ib6kbNiZ7WRIdlVokUDR1Fg0kjIpkfbw==", + "license": "MIT", + "dependencies": { + "@svgdotjs/svg.js": "^3.2.4" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@svgdotjs/svg.js": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.js/-/svg.js-3.2.5.tgz", + "integrity": "sha512-/VNHWYhNu+BS7ktbYoVGrCmsXDh+chFMaONMwGNdIBcFHrWqk2jY8fNyr3DLdtQUIalvkPfM554ZSFa3dm3nxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Fuzzyma" + } + }, + "node_modules/@svgdotjs/svg.resize.js": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.resize.js/-/svg.resize.js-2.0.5.tgz", + "integrity": "sha512-4heRW4B1QrJeENfi7326lUPYBCevj78FJs8kfeDxn5st0IYPIRXoTtOSYvTzFWgaWWXd3YCDE6ao4fmv91RthA==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.select.js": "^4.0.1" + } + }, + "node_modules/@svgdotjs/svg.select.js": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@svgdotjs/svg.select.js/-/svg.select.js-4.0.3.tgz", + "integrity": "sha512-qkMgso1sd2hXKd1FZ1weO7ANq12sNmQJeGDjs46QwDVsxSRcHmvWKL2NDF7Yimpwf3sl5esOLkPqtV2bQ3v/Jg==", + "license": "MIT", + "engines": { + "node": ">= 14.18" + }, + "peerDependencies": { + "@svgdotjs/svg.js": "^3.2.4" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.11.tgz", + "integrity": "sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", + "integrity": "sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.1", + "lightningcss": "1.30.2", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.18" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.18.tgz", + "integrity": "sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-arm64": "4.1.18", + "@tailwindcss/oxide-darwin-x64": "4.1.18", + "@tailwindcss/oxide-freebsd-x64": "4.1.18", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.18", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.18", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.18", + "@tailwindcss/oxide-linux-x64-musl": "4.1.18", + "@tailwindcss/oxide-wasm32-wasi": "4.1.18", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.18", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.18" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.18.tgz", + "integrity": "sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.18.tgz", + "integrity": "sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.18.tgz", + "integrity": "sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.18.tgz", + "integrity": "sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.18.tgz", + "integrity": "sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.18.tgz", + "integrity": "sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.18.tgz", + "integrity": "sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.18.tgz", + "integrity": "sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.18.tgz", + "integrity": "sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.18.tgz", + "integrity": "sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.0", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.18.tgz", + "integrity": "sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.18.tgz", + "integrity": "sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.18.tgz", + "integrity": "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.18", + "@tailwindcss/oxide": "4.1.18", + "tailwindcss": "4.1.18" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.1.18", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", + "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", + "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.1.5" + } + }, + "node_modules/@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@yr/monotone-cubic-spline": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz", + "integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==", + "license": "MIT" + }, + "node_modules/alpinejs": { + "version": "3.15.8", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.15.8.tgz", + "integrity": "sha512-zxIfCRTBGvF1CCLIOMQOxAyBuqibxSEwS6Jm1a3HGA9rgrJVcjEWlwLcQTVGAWGS8YhAsTRLVrtQ5a5QT9bSSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "~3.1.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/apexcharts": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.3.6.tgz", + "integrity": "sha512-sVEPw+J0Gp0IHQabKu8cfdsxlfME0e36Wid7RIaPclGM2OUt+O7O4+6mfAmTUYhy5bDk8cNHzEhPfVtLCIXEJA==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@svgdotjs/svg.draggable.js": "^3.0.4", + "@svgdotjs/svg.filter.js": "^3.0.8", + "@svgdotjs/svg.js": "^3.2.4", + "@svgdotjs/svg.resize.js": "^2.0.2", + "@svgdotjs/svg.select.js": "^4.0.1", + "@yr/monotone-cubic-spline": "^1.0.3" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.24", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", + "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001766", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", + "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", + "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001769", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", + "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.286", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", + "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-2.1.0.tgz", + "integrity": "sha512-z+ck2BSV6KWtYcoIzk9Y5+p4NEjqM+Y4i8/H+VZRLq0OgNjW2DqyADquwYu5j8qRvaXwzNmfCWl1KrMlV1zpsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^7.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", + "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.30.2", + "lightningcss-darwin-arm64": "1.30.2", + "lightningcss-darwin-x64": "1.30.2", + "lightningcss-freebsd-x64": "1.30.2", + "lightningcss-linux-arm-gnueabihf": "1.30.2", + "lightningcss-linux-arm64-gnu": "1.30.2", + "lightningcss-linux-arm64-musl": "1.30.2", + "lightningcss-linux-x64-gnu": "1.30.2", + "lightningcss-linux-x64-musl": "1.30.2", + "lightningcss-win32-arm64-msvc": "1.30.2", + "lightningcss-win32-x64-msvc": "1.30.2" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", + "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", + "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.57.1", + "@rollup/rollup-android-arm64": "4.57.1", + "@rollup/rollup-darwin-arm64": "4.57.1", + "@rollup/rollup-darwin-x64": "4.57.1", + "@rollup/rollup-freebsd-arm64": "4.57.1", + "@rollup/rollup-freebsd-x64": "4.57.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", + "@rollup/rollup-linux-arm-musleabihf": "4.57.1", + "@rollup/rollup-linux-arm64-gnu": "4.57.1", + "@rollup/rollup-linux-arm64-musl": "4.57.1", + "@rollup/rollup-linux-loong64-gnu": "4.57.1", + "@rollup/rollup-linux-loong64-musl": "4.57.1", + "@rollup/rollup-linux-ppc64-gnu": "4.57.1", + "@rollup/rollup-linux-ppc64-musl": "4.57.1", + "@rollup/rollup-linux-riscv64-gnu": "4.57.1", + "@rollup/rollup-linux-riscv64-musl": "4.57.1", + "@rollup/rollup-linux-s390x-gnu": "4.57.1", + "@rollup/rollup-linux-x64-gnu": "4.57.1", + "@rollup/rollup-linux-x64-musl": "4.57.1", + "@rollup/rollup-openbsd-x64": "4.57.1", + "@rollup/rollup-openharmony-arm64": "4.57.1", + "@rollup/rollup-win32-arm64-msvc": "4.57.1", + "@rollup/rollup-win32-ia32-msvc": "4.57.1", + "@rollup/rollup-win32-x64-gnu": "4.57.1", + "@rollup/rollup-win32-x64-msvc": "4.57.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite-plugin-full-reload/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/app/package.json b/app/package.json index 7686b29..8219749 100644 --- a/app/package.json +++ b/app/package.json @@ -7,11 +7,19 @@ "dev": "vite" }, "devDependencies": { + "@tailwindcss/forms": "^0.5.2", "@tailwindcss/vite": "^4.0.0", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", "axios": "^1.11.0", + "chart.js": "^4.4.1", "concurrently": "^9.0.1", "laravel-vite-plugin": "^2.0.0", - "tailwindcss": "^4.0.0", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", "vite": "^7.0.7" + }, + "dependencies": { + "apexcharts": "^5.3.6" } } diff --git a/app/postcss.config.js b/app/postcss.config.js new file mode 100644 index 0000000..49c0612 --- /dev/null +++ b/app/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/app/public/assets/fonts/PlusJakartaSans-Bold.ttf b/app/public/assets/fonts/PlusJakartaSans-Bold.ttf new file mode 100644 index 0000000..0ff3da5 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-Bold.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-BoldItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-BoldItalic.ttf new file mode 100644 index 0000000..ebd7f01 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-BoldItalic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-ExtraBold.ttf b/app/public/assets/fonts/PlusJakartaSans-ExtraBold.ttf new file mode 100644 index 0000000..d22fa69 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-ExtraBold.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-ExtraBoldItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..74608e1 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-ExtraBoldItalic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-ExtraLight.ttf b/app/public/assets/fonts/PlusJakartaSans-ExtraLight.ttf new file mode 100644 index 0000000..2a72c18 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-ExtraLight.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-ExtraLightItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-ExtraLightItalic.ttf new file mode 100644 index 0000000..0818b49 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-ExtraLightItalic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-Italic.ttf b/app/public/assets/fonts/PlusJakartaSans-Italic.ttf new file mode 100644 index 0000000..392a6fc Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-Italic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-Light.ttf b/app/public/assets/fonts/PlusJakartaSans-Light.ttf new file mode 100644 index 0000000..2faaa67 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-Light.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-LightItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-LightItalic.ttf new file mode 100644 index 0000000..d0905c6 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-LightItalic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-Medium.ttf b/app/public/assets/fonts/PlusJakartaSans-Medium.ttf new file mode 100644 index 0000000..f72e9c8 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-Medium.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-MediumItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-MediumItalic.ttf new file mode 100644 index 0000000..1f65ded Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-MediumItalic.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-Regular.ttf b/app/public/assets/fonts/PlusJakartaSans-Regular.ttf new file mode 100644 index 0000000..a68ad8d Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-Regular.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-SemiBold.ttf b/app/public/assets/fonts/PlusJakartaSans-SemiBold.ttf new file mode 100644 index 0000000..e675450 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-SemiBold.ttf differ diff --git a/app/public/assets/fonts/PlusJakartaSans-SemiBoldItalic.ttf b/app/public/assets/fonts/PlusJakartaSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..83354d8 Binary files /dev/null and b/app/public/assets/fonts/PlusJakartaSans-SemiBoldItalic.ttf differ diff --git a/app/references/email-branded-designs/admin-invite-role-change.html b/app/references/email-branded-designs/admin-invite-role-change.html new file mode 100644 index 0000000..cb91d49 --- /dev/null +++ b/app/references/email-branded-designs/admin-invite-role-change.html @@ -0,0 +1,102 @@ + + + + + + Admin invite + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Admin access +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🧭 + + Admin invite +
+
+ You have been granted admin access for Dewemoji. Use the link below to enter the admin dashboard. +
+ Role: {{ role_name }}
+ Granted by: {{ granted_by }} +
+ + Open Admin Dashboard + +
+ If you do not expect this invite, please ignore the message. +
+
+ + + + + + + +
+ Admins can manage users, subscriptions, and pricing. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/api-key-created.html b/app/references/email-branded-designs/api-key-created.html new file mode 100644 index 0000000..44a3609 --- /dev/null +++ b/app/references/email-branded-designs/api-key-created.html @@ -0,0 +1,102 @@ + + + + + + API key created + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ API key +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🔐 + + API key created +
+
+ A new API key was created for your Dewemoji account. +
+ Label: {{ key_label }}
+ Created: {{ created_at }} +
+ + Manage API Keys + +
+ If you did not create this key, revoke it immediately. +
+
+ + + + + + + +
+ Never share your API key publicly. Treat it like a password. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/api-key-rotated.html b/app/references/email-branded-designs/api-key-rotated.html new file mode 100644 index 0000000..50b1263 --- /dev/null +++ b/app/references/email-branded-designs/api-key-rotated.html @@ -0,0 +1,102 @@ + + + + + + API key rotated + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ API key +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🔁 + + API key rotated +
+
+ Your API key was rotated. Update any integrations using the old key. +
+ Label: {{ key_label }}
+ Rotated: {{ rotated_at }} +
+ + View API Keys + +
+ If you did not rotate this key, revoke it immediately. +
+
+ + + + + + + +
+ Keep your API key secure and do not commit it to public repos. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/email-verification.html b/app/references/email-branded-designs/email-verification.html new file mode 100644 index 0000000..6fdf45a --- /dev/null +++ b/app/references/email-branded-designs/email-verification.html @@ -0,0 +1,98 @@ + + + + + + Dewemoji Email Verification + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Email verification +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ + + Verify your email +
+
+ Thanks for joining Dewemoji. Confirm your email to activate your account and start saving emoji keywords. +
+ + Verify Email + +
+ If the button does not work, paste this link into your browser: +
+ {{ verification_url }} +
+
+ + + + + + + +
+ This link expires in 60 minutes. If you did not request this email, you can safely ignore it. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/license-key-issued.html b/app/references/email-branded-designs/license-key-issued.html new file mode 100644 index 0000000..d50409b --- /dev/null +++ b/app/references/email-branded-designs/license-key-issued.html @@ -0,0 +1,103 @@ + + + + + + License key issued + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ License +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🔑 + + License key issued +
+
+ Your license key is ready. Use it to unlock Dewemoji in the extension and API. +
+ License: {{ license_key }}
+ Tier: {{ tier }}
+ Devices: {{ max_devices }} +
+ + Manage License + +
+ Keep your license secure. You can rotate it anytime from your dashboard. +
+
+ + + + + + + +
+ Need help getting started? Visit your API docs from the dashboard. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/license-key-updated.html b/app/references/email-branded-designs/license-key-updated.html new file mode 100644 index 0000000..7e0c15e --- /dev/null +++ b/app/references/email-branded-designs/license-key-updated.html @@ -0,0 +1,103 @@ + + + + + + License key updated + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ License +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🧩 + + License updated +
+
+ Your Dewemoji license details have been updated. +
+ License: {{ license_key }}
+ Tier: {{ tier }}
+ Devices: {{ max_devices }} +
+ + View License + +
+ If you did not request this change, please contact support. +
+
+ + + + + + + +
+ Keep your license secure and avoid sharing it publicly. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/new-login-alert.html b/app/references/email-branded-designs/new-login-alert.html new file mode 100644 index 0000000..ccc748e --- /dev/null +++ b/app/references/email-branded-designs/new-login-alert.html @@ -0,0 +1,104 @@ + + + + + + New login detected + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Security alert +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🛡️ + + New login detected +
+
+ We noticed a new login to your Dewemoji account. +
+ Time: {{ login_time }}
+ Device: {{ login_device }}
+ Location: {{ login_location }}
+ IP: {{ login_ip }} +
+ + Review Activity + +
+ If this was you, no action is needed. +
+
+ + + + + + + +
+ If you do not recognize this login, secure your account immediately. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/password-reset.html b/app/references/email-branded-designs/password-reset.html new file mode 100644 index 0000000..12a8acc --- /dev/null +++ b/app/references/email-branded-designs/password-reset.html @@ -0,0 +1,98 @@ + + + + + + Dewemoji Password Reset + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Password reset +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ 🔒 + + Reset your password +
+
+ We received a request to reset your Dewemoji password. Click the button below to choose a new one. +
+ + Reset Password + +
+ If the button does not work, paste this link into your browser: +
+ {{ reset_url }} +
+
+ + + + + + + +
+ This link expires in 60 minutes. If you did not request a password reset, you can safely ignore this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/payment-failed-action-required.html b/app/references/email-branded-designs/payment-failed-action-required.html new file mode 100644 index 0000000..31e74ce --- /dev/null +++ b/app/references/email-branded-designs/payment-failed-action-required.html @@ -0,0 +1,103 @@ + + + + + + Payment failed + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Billing alert +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ ⚠️ + + Payment failed +
+
+ We were unable to process your latest payment. Please update your billing details to keep your subscription active. +
+ Plan: {{ plan_name }}
+ Amount: {{ amount }}
+ Date: {{ failed_date }} +
+ + Update Payment Method + +
+ If you already updated your payment method, you can ignore this email. +
+
+ + + + + + + +
+ Need help? Reply to this email and we will assist you. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/qris-payment-confirmed.html b/app/references/email-branded-designs/qris-payment-confirmed.html new file mode 100644 index 0000000..275e017 --- /dev/null +++ b/app/references/email-branded-designs/qris-payment-confirmed.html @@ -0,0 +1,103 @@ + + + + + + QRIS payment confirmed + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ QRIS payment +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🎉 + + Payment confirmed +
+
+ Your QRIS payment was successful. Your access has been updated. +
+ Amount: {{ amount }}
+ Plan: {{ plan_name }}
+ Payment ID: {{ payment_reference }} +
+ + Go to Dashboard + +
+ Thank you for supporting Dewemoji. +
+
+ + + + + + + +
+ If you need a receipt, you can download it from your billing page. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/qris-payment-pending.html b/app/references/email-branded-designs/qris-payment-pending.html new file mode 100644 index 0000000..ec3f00e --- /dev/null +++ b/app/references/email-branded-designs/qris-payment-pending.html @@ -0,0 +1,103 @@ + + + + + + QRIS payment pending + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ QRIS payment +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ + + Payment pending +
+
+ We are waiting for your QRIS payment. Please complete it before it expires. +
+ Amount: {{ amount }}
+ Expires: {{ expires_at }}
+ Payment ID: {{ payment_reference }} +
+ + View Payment Details + +
+ You can also reopen the QR from your billing page. +
+
+ + + + + + + +
+ If you have already paid, please wait a moment for confirmation. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/subscription-activated-paypal.html b/app/references/email-branded-designs/subscription-activated-paypal.html new file mode 100644 index 0000000..8c758b0 --- /dev/null +++ b/app/references/email-branded-designs/subscription-activated-paypal.html @@ -0,0 +1,104 @@ + + + + + + Subscription activated + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Subscription +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ + + Subscription activated +
+
+ Your PayPal subscription is now active. Enjoy full Dewemoji features. +
+ Plan: {{ plan_name }}
+ Billing: {{ billing_cycle }}
+ Amount: {{ amount }}
+ Next charge: {{ next_billing_date }} +
+ + Manage Subscription + +
+ Need an invoice? You can download it from your billing page. +
+
+ + + + + + + +
+ If you have questions about your subscription, reply to this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/subscription-canceled.html b/app/references/email-branded-designs/subscription-canceled.html new file mode 100644 index 0000000..fbc14a5 --- /dev/null +++ b/app/references/email-branded-designs/subscription-canceled.html @@ -0,0 +1,102 @@ + + + + + + Subscription canceled + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Subscription +
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ 🧾 + + Subscription canceled +
+
+ Your subscription has been canceled. You will keep access until the end of the current billing period. +
+ Plan: {{ plan_name }}
+ Access ends: {{ end_date }} +
+ + View Plans + +
+ You can re-subscribe anytime from your dashboard. +
+
+ + + + + + + +
+ If this was a mistake, reply to this email and we will help you out. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-branded-designs/welcome-onboarding.html b/app/references/email-branded-designs/welcome-onboarding.html new file mode 100644 index 0000000..a557e43 --- /dev/null +++ b/app/references/email-branded-designs/welcome-onboarding.html @@ -0,0 +1,110 @@ + + + + + + Welcome to Dewemoji + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Welcome +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ 🎉 + + Welcome to Dewemoji +
+
+ Hey {{ first_name }}, you now have a home for every emoji keyword. Save, search, and sync your favorites across devices. +
+ Start here +
+ 1. Add your first emoji keyword +
+ 2. Generate an API key for your workflows +
+ 3. Sync your list to the extension +
+ + Open Dashboard + +
+ Need help? Visit the docs: {{ docs_url }} +
+
+ + + + + + + +
+ If you have questions, reply to this email and we will help you out. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/email-verification-light.html b/app/references/email-designs/email-verification-light.html new file mode 100644 index 0000000..00677de --- /dev/null +++ b/app/references/email-designs/email-verification-light.html @@ -0,0 +1,89 @@ + + + + + + Dewemoji Email Verification + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + Dewemoji +
+
+ Email verification +
+
+ + + + + + + + + + + + + +
+ Verify your email to unlock Dewemoji +
+ Thanks for joining. Please confirm your email address to activate your account and start saving your favorite emoji keywords. +
+ + Verify Email + +
+ If the button does not work, paste this link into your browser: +
+ {{ verification_url }} +
+
+ + + + + + + +
+ This link will expire in 60 minutes. If you did not request this email, you can safely ignore it. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/email-verification-v2.html b/app/references/email-designs/email-verification-v2.html new file mode 100644 index 0000000..a007049 --- /dev/null +++ b/app/references/email-designs/email-verification-v2.html @@ -0,0 +1,89 @@ + + + + + + Dewemoji Email Verification + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + Dewemoji +
+
+ Email verification +
+
+ + + + + + + + + + + + + +
+ Verify your email to unlock Dewemoji +
+ Thanks for joining. Please confirm your email address to activate your account and start saving your favorite emoji keywords. +
+ + Verify Email + +
+ If the button doesn’t work, paste this link into your browser: +
+ {{ verification_url }} +
+
+ + + + + + + +
+ This link will expire in 60 minutes. If you didn’t request this email, you can safely ignore it. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/password-reset-brand.html b/app/references/email-designs/password-reset-brand.html new file mode 100644 index 0000000..f4ac554 --- /dev/null +++ b/app/references/email-designs/password-reset-brand.html @@ -0,0 +1,98 @@ + + + + + + Dewemoji Password Reset + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ D + + Dewemoji +
+
+ Password reset +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ 🔒 + + Reset your password +
+
+ We received a request to reset your Dewemoji password. Click the button below to choose a new one. +
+ + Reset Password + +
+ If the button does not work, paste this link into your browser: +
+ {{ reset_url }} +
+
+ + + + + + + +
+ This link will expire in 60 minutes. If you did not request a password reset, you can safely ignore this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/password-reset-light.html b/app/references/email-designs/password-reset-light.html new file mode 100644 index 0000000..8ab89f8 --- /dev/null +++ b/app/references/email-designs/password-reset-light.html @@ -0,0 +1,89 @@ + + + + + + Dewemoji Password Reset + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ 🔒 + + Dewemoji +
+
+ Password reset +
+
+ + + + + + + + + + + + + +
+ Reset your password +
+ We received a request to reset your Dewemoji password. Click the button below to choose a new one. +
+ + Reset Password + +
+ If the button does not work, paste this link into your browser: +
+ {{ reset_url }} +
+
+ + + + + + + +
+ This link will expire in 60 minutes. If you did not request a password reset, you can safely ignore this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/password-reset-no-wrapper.html b/app/references/email-designs/password-reset-no-wrapper.html new file mode 100644 index 0000000..e3b0876 --- /dev/null +++ b/app/references/email-designs/password-reset-no-wrapper.html @@ -0,0 +1,98 @@ + + + + + + Dewemoji Password Reset + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ D + + Dewemoji +
+
+ Password reset +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ 🔒 + + Reset your password +
+
+ We received a request to reset your Dewemoji password. Click the button below to choose a new one. +
+ + Reset Password + +
+ If the button does not work, paste this link into your browser: +
+ {{ reset_url }} +
+
+ + + + + + + +
+ This link will expire in 60 minutes. If you did not request a password reset, you can safely ignore this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/references/email-designs/welcome-onboarding-light.html b/app/references/email-designs/welcome-onboarding-light.html new file mode 100644 index 0000000..1734b6f --- /dev/null +++ b/app/references/email-designs/welcome-onboarding-light.html @@ -0,0 +1,101 @@ + + + + + + Welcome to Dewemoji + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ 🎉 + + Dewemoji +
+
+ Welcome +
+
+ + + + + + + + + + + + + + + + + + + +
+ Welcome to Dewemoji, {{ first_name }} +
+ You now have a home for every emoji keyword. Save, search, and sync your favorites across devices with a single license. +
+ Start here +
+ 1. Add your first emoji keyword +
+ 2. Generate an API key for your workflows +
+ 3. Sync your list to the extension +
+ + Open Dashboard + +
+ Need help? Visit the docs: {{ docs_url }} +
+
+ + + + + + + +
+ If you have questions, reply to this email and we will help you out. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/resources/css/app.css b/app/resources/css/app.css index 3e6abea..b5c61c9 100644 --- a/app/resources/css/app.css +++ b/app/resources/css/app.css @@ -1,11 +1,3 @@ -@import 'tailwindcss'; - -@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; -@source '../../storage/framework/views/*.php'; -@source '../**/*.blade.php'; -@source '../**/*.js'; - -@theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; -} +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/app/resources/js/app.js b/app/resources/js/app.js index e59d6a0..656145b 100644 --- a/app/resources/js/app.js +++ b/app/resources/js/app.js @@ -1 +1,9 @@ import './bootstrap'; + +import ApexCharts from 'apexcharts'; +import Alpine from 'alpinejs'; + +window.Alpine = Alpine; +window.ApexCharts = ApexCharts; + +Alpine.start(); diff --git a/app/resources/views/auth/confirm-password.blade.php b/app/resources/views/auth/confirm-password.blade.php new file mode 100644 index 0000000..c0df2f5 --- /dev/null +++ b/app/resources/views/auth/confirm-password.blade.php @@ -0,0 +1,27 @@ + +
+ {{ __('This is a secure area of the application. Please confirm your password before continuing.') }} +
+ +
+ @csrf + + +
+ + + + + +
+ +
+ + {{ __('Confirm') }} + +
+
+
diff --git a/app/resources/views/auth/forgot-password.blade.php b/app/resources/views/auth/forgot-password.blade.php new file mode 100644 index 0000000..ad3eca7 --- /dev/null +++ b/app/resources/views/auth/forgot-password.blade.php @@ -0,0 +1,25 @@ + +
+ {{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }} +
+ + + + +
+ @csrf + + +
+ + + +
+ +
+ + {{ __('Email Password Reset Link') }} + +
+
+
diff --git a/app/resources/views/auth/login.blade.php b/app/resources/views/auth/login.blade.php new file mode 100644 index 0000000..2938ec6 --- /dev/null +++ b/app/resources/views/auth/login.blade.php @@ -0,0 +1,53 @@ + + @section('title', 'Login - '.config('app.name', 'Dewemoji')) + + + +
+ @csrf + + +
+ + + +
+ + +
+ + + + + +
+ + +
+ +
+ +
+ + {{ __('Log in') }} + + + @if (Route::has('password.request')) + + {{ __('Forgot your password?') }} + + @endif +
+ +
+ Don't have an account? + Register +
+
+
diff --git a/app/resources/views/auth/register.blade.php b/app/resources/views/auth/register.blade.php new file mode 100644 index 0000000..553be9b --- /dev/null +++ b/app/resources/views/auth/register.blade.php @@ -0,0 +1,53 @@ + + @section('title', 'Register - '.config('app.name', 'Dewemoji')) +
+ @csrf + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Already registered?') }} + + + + {{ __('Register') }} + +
+
+
diff --git a/app/resources/views/auth/reset-password.blade.php b/app/resources/views/auth/reset-password.blade.php new file mode 100644 index 0000000..a6494cc --- /dev/null +++ b/app/resources/views/auth/reset-password.blade.php @@ -0,0 +1,39 @@ + +
+ @csrf + + + + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Reset Password') }} + +
+
+
diff --git a/app/resources/views/auth/verify-email.blade.php b/app/resources/views/auth/verify-email.blade.php new file mode 100644 index 0000000..d3089dd --- /dev/null +++ b/app/resources/views/auth/verify-email.blade.php @@ -0,0 +1,31 @@ + +
+ {{ __('Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }} +
+ + @if (session('status') == 'verification-link-sent') +
+ {{ __('A new verification link has been sent to the email address you provided during registration.') }} +
+ @endif + +
+
+ @csrf + +
+ + {{ __('Resend Verification Email') }} + +
+
+ +
+ @csrf + + +
+
+
diff --git a/app/resources/views/components/application-logo.blade.php b/app/resources/views/components/application-logo.blade.php new file mode 100644 index 0000000..46579cf --- /dev/null +++ b/app/resources/views/components/application-logo.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/app/resources/views/components/auth-session-status.blade.php b/app/resources/views/components/auth-session-status.blade.php new file mode 100644 index 0000000..c4bd6e2 --- /dev/null +++ b/app/resources/views/components/auth-session-status.blade.php @@ -0,0 +1,7 @@ +@props(['status']) + +@if ($status) +
merge(['class' => 'font-medium text-sm text-green-600']) }}> + {{ $status }} +
+@endif diff --git a/app/resources/views/components/danger-button.blade.php b/app/resources/views/components/danger-button.blade.php new file mode 100644 index 0000000..16a418a --- /dev/null +++ b/app/resources/views/components/danger-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/app/resources/views/components/dropdown-link.blade.php b/app/resources/views/components/dropdown-link.blade.php new file mode 100644 index 0000000..e0f8ce1 --- /dev/null +++ b/app/resources/views/components/dropdown-link.blade.php @@ -0,0 +1 @@ +merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }} diff --git a/app/resources/views/components/dropdown.blade.php b/app/resources/views/components/dropdown.blade.php new file mode 100644 index 0000000..a46f7c8 --- /dev/null +++ b/app/resources/views/components/dropdown.blade.php @@ -0,0 +1,35 @@ +@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white']) + +@php +$alignmentClasses = match ($align) { + 'left' => 'ltr:origin-top-left rtl:origin-top-right start-0', + 'top' => 'origin-top', + default => 'ltr:origin-top-right rtl:origin-top-left end-0', +}; + +$width = match ($width) { + '48' => 'w-48', + default => $width, +}; +@endphp + +
+
+ {{ $trigger }} +
+ + +
diff --git a/app/resources/views/components/input-error.blade.php b/app/resources/views/components/input-error.blade.php new file mode 100644 index 0000000..33f4a48 --- /dev/null +++ b/app/resources/views/components/input-error.blade.php @@ -0,0 +1,9 @@ +@props(['messages']) + +@if ($messages) +
    merge(['class' => 'text-sm text-red-500 dark:text-red-400 space-y-1']) }}> + @foreach ((array) $messages as $message) +
  • {{ $message }}
  • + @endforeach +
+@endif diff --git a/app/resources/views/components/input-label.blade.php b/app/resources/views/components/input-label.blade.php new file mode 100644 index 0000000..b21401a --- /dev/null +++ b/app/resources/views/components/input-label.blade.php @@ -0,0 +1,5 @@ +@props(['value']) + + diff --git a/app/resources/views/components/modal.blade.php b/app/resources/views/components/modal.blade.php new file mode 100644 index 0000000..70704c1 --- /dev/null +++ b/app/resources/views/components/modal.blade.php @@ -0,0 +1,78 @@ +@props([ + 'name', + 'show' => false, + 'maxWidth' => '2xl' +]) + +@php +$maxWidth = [ + 'sm' => 'sm:max-w-sm', + 'md' => 'sm:max-w-md', + 'lg' => 'sm:max-w-lg', + 'xl' => 'sm:max-w-xl', + '2xl' => 'sm:max-w-2xl', +][$maxWidth]; +@endphp + +
+
+
+
+ +
+ {{ $slot }} +
+
diff --git a/app/resources/views/components/nav-link.blade.php b/app/resources/views/components/nav-link.blade.php new file mode 100644 index 0000000..5c101a2 --- /dev/null +++ b/app/resources/views/components/nav-link.blade.php @@ -0,0 +1,11 @@ +@props(['active']) + +@php +$classes = ($active ?? false) + ? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out' + : 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out'; +@endphp + +merge(['class' => $classes]) }}> + {{ $slot }} + diff --git a/app/resources/views/components/primary-button.blade.php b/app/resources/views/components/primary-button.blade.php new file mode 100644 index 0000000..782ac61 --- /dev/null +++ b/app/resources/views/components/primary-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/app/resources/views/components/responsive-nav-link.blade.php b/app/resources/views/components/responsive-nav-link.blade.php new file mode 100644 index 0000000..43b91e7 --- /dev/null +++ b/app/resources/views/components/responsive-nav-link.blade.php @@ -0,0 +1,11 @@ +@props(['active']) + +@php +$classes = ($active ?? false) + ? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out' + : 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out'; +@endphp + +merge(['class' => $classes]) }}> + {{ $slot }} + diff --git a/app/resources/views/components/secondary-button.blade.php b/app/resources/views/components/secondary-button.blade.php new file mode 100644 index 0000000..b32b69f --- /dev/null +++ b/app/resources/views/components/secondary-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/app/resources/views/components/text-input.blade.php b/app/resources/views/components/text-input.blade.php new file mode 100644 index 0000000..16299e9 --- /dev/null +++ b/app/resources/views/components/text-input.blade.php @@ -0,0 +1,3 @@ +@props(['disabled' => false]) + +merge(['class' => 'rounded-xl border border-slate-300/80 bg-white/90 px-4 py-2 text-sm text-slate-900 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-brand-ocean/40 dark:border-white/10 dark:bg-slate-900/70 dark:text-slate-100 dark:placeholder-slate-500']) }}> diff --git a/app/resources/views/dashboard.blade.php b/app/resources/views/dashboard.blade.php new file mode 100644 index 0000000..dca6e52 --- /dev/null +++ b/app/resources/views/dashboard.blade.php @@ -0,0 +1,26 @@ +{{-- LEGACY VIEW (NOT USED) + This file is the default Breeze dashboard and is NOT wired to any routes. + The active dashboard layout lives in resources/views/dashboard/app.blade.php + and pages in resources/views/dashboard/*.blade.php +--}} + + +

+ {{ __('Dashboard') }} +

+
+ +
+
+
+ Legacy template: This view is not used by the current dashboard routes. + The live dashboard uses resources/views/dashboard/app.blade.php. +
+
+
+ {{ __("You're logged in!") }} +
+
+
+
+
diff --git a/app/resources/views/dashboard/admin/audit-logs.blade.php b/app/resources/views/dashboard/admin/audit-logs.blade.php new file mode 100644 index 0000000..61e4251 --- /dev/null +++ b/app/resources/views/dashboard/admin/audit-logs.blade.php @@ -0,0 +1,64 @@ +@extends('dashboard.app') + +@section('page_title', 'Audit Logs') +@section('page_subtitle', 'Track administrative actions and changes.') + +@section('dashboard_content') +
+
+
+
Audit trail
+
Recent admin actions
+
+
+ + + +
+
+ +
+ + + + + + + + + + + + @forelse ($logs ?? [] as $log) + + + + + + + + @empty + + + + @endforelse + +
AdminActionIPTimePayload
+
{{ $log->admin_email ?? '—' }}
+
#{{ $log->admin_id ?? 'n/a' }}
+
{{ $log->action }}{{ $log->ip_address ?? '—' }}{{ $log->created_at?->toDateTimeString() ?? '—' }} +
{{ json_encode($log->payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}
+
No audit logs yet.
+
+ +
+ {{ $logs->links('vendor.pagination.dashboard') }} +
+
+@endsection diff --git a/app/resources/views/dashboard/admin/pricing.blade.php b/app/resources/views/dashboard/admin/pricing.blade.php new file mode 100644 index 0000000..3e8bb37 --- /dev/null +++ b/app/resources/views/dashboard/admin/pricing.blade.php @@ -0,0 +1,145 @@ +@extends('dashboard.app') + +@section('page_title', 'Admin Pricing') +@section('page_subtitle', 'Manage plan pricing and rollout changes.') + +@section('dashboard_content') + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ @foreach ([ + ['label' => 'Plans', 'value' => number_format(($plans ?? collect())->count()), 'note' => 'Active tiers'], + ['label' => 'Pending changes', 'value' => number_format(($changes ?? collect())->count()), 'note' => 'Latest snapshots'], + ['label' => 'Currency', 'value' => optional(($plans ?? collect())->first())->currency ?? 'IDR', 'note' => 'Default'], + ] as $card) +
+
{{ $card['label'] }}
+
{{ $card['value'] }}
+
{{ $card['note'] }}
+
+ @endforeach +
+ +
+ @csrf + @forelse ($plans ?? [] as $plan) +
+
+
{{ $plan->code }}
+ {{ $plan->status }} +
+
+ + +
+ + +
+
+ + +
+
+
PayPal Plan IDs
+
+
Sandbox: {{ $plan->meta['paypal']['sandbox']['plan']['id'] ?? '—' }}
+
Live: {{ $plan->meta['paypal']['live']['plan']['id'] ?? '—' }}
+
Last sync: {{ $plan->meta['paypal']['live']['plan']['synced_at'] ?? $plan->meta['paypal']['sandbox']['plan']['synced_at'] ?? '—' }}
+
+
+
+
+ @empty +
+ No pricing plans yet. Use reset to defaults to create base plans. +
+ @endforelse +
+ + + +
+
+ +
+ @csrf +
+ +
+ @csrf +
+ +
+
+
+
Change log
+
Recent pricing updates
+
+
+ @csrf + +
+
+
+ @forelse ($changes ?? [] as $change) +
+
+
Pricing change #{{ $change->id }}
+
{{ $change->created_at?->toDateString() }} · {{ $change->admin_ref ?? 'system' }}
+
+ Published +
+ @empty +
No pricing changes recorded yet.
+ @endforelse +
+
+ + +@endsection diff --git a/app/resources/views/dashboard/admin/settings.blade.php b/app/resources/views/dashboard/admin/settings.blade.php new file mode 100644 index 0000000..27d1c3b --- /dev/null +++ b/app/resources/views/dashboard/admin/settings.blade.php @@ -0,0 +1,93 @@ +@extends('dashboard.app') + +@section('page_title', 'Admin Settings') +@section('page_subtitle', 'System configuration and feature flags.') + +@section('dashboard_content') + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ @foreach ([ + ['label' => 'Billing mode', 'value' => ($settings['billing_mode'] ?? config('dewemoji.billing.mode')), 'note' => isset($settings['billing_mode']) ? 'DB' : 'Env'], + ['label' => 'Rate limit', 'value' => config('dewemoji.rate_limit_enabled') ? 'On' : 'Off', 'note' => 'Global'], + ['label' => 'Public access', 'value' => ((bool) ($settings['public_enforce'] ?? config('dewemoji.public_access.enforce_whitelist'))) ? 'Whitelist' : 'Open', 'note' => 'Origin policy'], + ] as $card) +
+
{{ $card['label'] }}
+
{{ $card['value'] }}
+
{{ $card['note'] }}
+
+ @endforeach +
+ +
+
+
Feature flags
+
System toggles
+
+ @foreach ([ + ['label' => 'Maintenance mode', 'desc' => 'Temporarily block public API access', 'state' => ((bool) ($settings['maintenance_enabled'] ?? false)) ? 'On' : 'Off'], + ['label' => 'Extension verification', 'desc' => 'Require GCM token for extension calls', 'state' => config('dewemoji.extension_verification.enabled') ? 'On' : 'Off'], + ['label' => 'Metrics', 'desc' => 'Allow internal metrics endpoints', 'state' => config('dewemoji.metrics.enabled') ? 'On' : 'Off'], + ] as $row) +
+
+
{{ $row['label'] }}
+
{{ $row['desc'] }}
+
+ + {{ $row['state'] }} + +
+ @endforeach +
+
+ +
+
Public access
+
Allowlist configuration
+
+ @csrf + + + + + + + +

Changes update the settings store immediately.

+
+
+
+@endsection diff --git a/app/resources/views/dashboard/admin/subscription-show.blade.php b/app/resources/views/dashboard/admin/subscription-show.blade.php new file mode 100644 index 0000000..b2fc1c5 --- /dev/null +++ b/app/resources/views/dashboard/admin/subscription-show.blade.php @@ -0,0 +1,65 @@ +@extends('dashboard.app') + +@section('page_title', 'Subscription Details') +@section('page_subtitle', 'Plan status, provider info, and timeline.') + +@section('dashboard_content') + + Back to subscriptions + + +
+
+
Subscriber
+
{{ $subscription->user?->name ?? '—' }}
+
{{ $subscription->user?->email ?? '—' }}
+ @if ($subscription->user) + + View user + + @endif +
+
+
Plan
+
{{ $subscription->plan }}
+
Status: {{ $subscription->status }}
+
+
+
Provider
+
{{ $subscription->provider ?? 'admin' }}
+
Ref: {{ $subscription->provider_ref ?? '—' }}
+
+
+ +
+
+
Timeline
+
Subscription dates
+
+
+ Started + {{ $subscription->started_at?->toDateString() ?? '—' }} +
+
+ Expires + {{ $subscription->expires_at?->toDateString() ?? '—' }} +
+
+ Created + {{ $subscription->created_at?->toDateString() ?? '—' }} +
+
+
+
+
Actions
+
Manage subscription
+
+
+ @csrf + + +
+
+
+
+@endsection diff --git a/app/resources/views/dashboard/admin/subscriptions.blade.php b/app/resources/views/dashboard/admin/subscriptions.blade.php new file mode 100644 index 0000000..888614c --- /dev/null +++ b/app/resources/views/dashboard/admin/subscriptions.blade.php @@ -0,0 +1,196 @@ +@extends('dashboard.app') + +@section('page_title', 'Admin Subscriptions') +@section('page_subtitle', 'Grant, revoke, and audit Pro access.') + +@section('dashboard_content') + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ @foreach ([ + ['label' => 'Active', 'value' => number_format(\App\Models\Subscription::where('status', 'active')->count()), 'note' => 'Subscriptions'], + ['label' => 'Revoked', 'value' => number_format(\App\Models\Subscription::where('status', 'revoked')->count()), 'note' => 'All time'], + ['label' => 'Pending', 'value' => number_format(\App\Models\Subscription::where('status', 'pending')->count()), 'note' => 'Manual review'], + ] as $card) +
+
{{ $card['label'] }}
+
{{ $card['value'] }}
+
{{ $card['note'] }}
+
+ @endforeach +
+ +
+
+
+
Filters
+
Refine subscriptions
+
+
+ + + + + + +
+
+
+ +
+
+
Grant access
+
Create subscription
+
+ @csrf +
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+
Revoke access
+
Cancel subscription
+
+ @csrf + + + + +
+
+
+ +
+
+
+
Subscription list
+
Recent subscriptions
+
+
+
+ + + + @php + $sortParam = $sort ?? 'id'; + $dirParam = $dir ?? 'desc'; + $toggle = fn ($field) => ($sortParam === $field && $dirParam === 'asc') ? 'desc' : 'asc'; + $sortUrl = fn ($field) => request()->fullUrlWithQuery(['sort' => $field, 'dir' => $toggle($field)]); + @endphp + + + + + + + + + @forelse ($subscriptions ?? [] as $row) + + + + + + + + @empty + + + + @endforelse + +
Subscriber + + Plan + + + + + Status + + + + + Next billing + + + Actions
+
{{ $row->user?->name ?? '—' }}
+
{{ $row->user?->email ?? '—' }}
+
{{ $row->plan }} + @php + $inactive = in_array($row->status, ['revoked', 'cancelled', 'suspended'], true); + $pill = $inactive + ? ['bg' => 'bg-rose-100 dark:bg-rose-500/20', 'text' => 'text-rose-800 dark:text-rose-200'] + : ($row->status === 'pending' + ? ['bg' => 'bg-amber-100 dark:bg-amber-500/20', 'text' => 'text-amber-800 dark:text-amber-200'] + : ['bg' => 'bg-emerald-100 dark:bg-emerald-500/20', 'text' => 'text-emerald-800 dark:text-emerald-200']); + @endphp + + {{ $row->status }} + + {{ $row->expires_at?->toDateString() ?? '—' }} + View +
No subscriptions found.
+
+
+ {{ $subscriptions->links('vendor.pagination.dashboard') }} +
+
+@endsection diff --git a/app/resources/views/dashboard/admin/user-show.blade.php b/app/resources/views/dashboard/admin/user-show.blade.php new file mode 100644 index 0000000..9481a7a --- /dev/null +++ b/app/resources/views/dashboard/admin/user-show.blade.php @@ -0,0 +1,88 @@ +@extends('dashboard.app') + +@section('page_title', 'User Details') +@section('page_subtitle', 'Profile, access, and subscription history.') + +@section('dashboard_content') + + Back to users + + +
+
User ID: {{ $user->id }}
+
+ @csrf + @method('DELETE') + +
+
+ +
+
+
Account
+
{{ $user->name ?? '—' }}
+
{{ $user->email }}
+
+
+
Access
+
{{ $user->role ?? 'user' }}
+
Tier: {{ $user->tier ?? 'free' }}
+
+
+
Joined
+
{{ $user->created_at?->toDateString() ?? '—' }}
+
{{ $user->created_at?->diffForHumans() ?? '' }}
+
+
+ +
+
+
+
Subscriptions
+
Recent access records
+
+
+
+ + + + + + + + + + + + @forelse ($subscriptions as $row) + + + + + + + + @empty + + + + @endforelse + +
PlanStatusStartedExpiresActions
{{ $row->plan }} + @php + $inactive = in_array($row->status, ['revoked', 'cancelled', 'suspended'], true); + $pill = $inactive + ? ['bg' => 'bg-rose-100 dark:bg-rose-500/20', 'text' => 'text-rose-800 dark:text-rose-200'] + : ($row->status === 'pending' + ? ['bg' => 'bg-amber-100 dark:bg-amber-500/20', 'text' => 'text-amber-800 dark:text-amber-200'] + : ['bg' => 'bg-emerald-100 dark:bg-emerald-500/20', 'text' => 'text-emerald-800 dark:text-emerald-200']); + @endphp + + {{ $row->status }} + + {{ $row->started_at?->toDateString() ?? '—' }}{{ $row->expires_at?->toDateString() ?? '—' }} + View +
No subscriptions found.
+
+
+@endsection diff --git a/app/resources/views/dashboard/admin/users.blade.php b/app/resources/views/dashboard/admin/users.blade.php new file mode 100644 index 0000000..e54ead7 --- /dev/null +++ b/app/resources/views/dashboard/admin/users.blade.php @@ -0,0 +1,207 @@ +@extends('dashboard.app') + +@section('page_title', 'Admin Users') +@section('page_subtitle', 'Manage accounts, roles, and access tiers.') + +@section('dashboard_content') + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + @if ($errors->any()) +
+ {{ $errors->first() }} +
+ @endif + +
+ @foreach ([ + ['label' => 'Total users', 'value' => number_format(\App\Models\User::count()), 'note' => 'All accounts'], + ['label' => 'Personal tier', 'value' => number_format(\App\Models\User::where('tier', 'personal')->count()), 'note' => 'Active subscriptions'], + ['label' => 'Admins', 'value' => number_format(\App\Models\User::where('role', 'admin')->count()), 'note' => 'Staff'], + ] as $card) +
+
{{ $card['label'] }}
+
{{ $card['value'] }}
+
{{ $card['note'] }}
+
+ @endforeach +
+ +
+
+
+
+
Create
+
Add new user
+
+ +
+ +
+ +
+
+
Directory
+
User list
+
+
+ + + + + + +
+
+ +
+ + + + @php + $sortParam = $sort ?? 'id'; + $dirParam = $dir ?? 'desc'; + $toggle = fn ($field) => ($sortParam === $field && $dirParam === 'asc') ? 'desc' : 'asc'; + $sortUrl = fn ($field) => request()->fullUrlWithQuery(['sort' => $field, 'dir' => $toggle($field)]); + @endphp + + + + + + + + + + @forelse ($users ?? [] as $user) + + + + + + + + + @empty + + + + @endforelse + +
+ + User + + + + + Role + + + + + Tier + + + Status + + Joined + + + Actions
+
{{ $user->name ?? '—' }}
+
{{ $user->email }}
+
{{ $user->role ?? 'user' }} +
+ @csrf + + + +
+
+ Active + {{ $user->created_at?->toDateString() }} +
+ View +
+ @csrf + @method('DELETE') + +
+
+
No users found.
+
+
+ {{ $users->links('vendor.pagination.dashboard') }} +
+
+@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/admin/webhook-show.blade.php b/app/resources/views/dashboard/admin/webhook-show.blade.php new file mode 100644 index 0000000..f8b3388 --- /dev/null +++ b/app/resources/views/dashboard/admin/webhook-show.blade.php @@ -0,0 +1,57 @@ +@extends('dashboard.app') + +@section('page_title', 'Webhook Detail') +@section('page_subtitle', 'Event payload, headers, and processing status.') + +@section('dashboard_content') + + Back to webhooks + + +
+
+
Event
+
#{{ $event->id }}
+
{{ $event->event_type ?? 'event' }}
+
+
+
Provider
+
{{ $event->provider }}
+
Event ID: {{ $event->event_id ?? '—' }}
+
+
+
Status
+
{{ $event->status }}
+
Received: {{ $event->received_at?->toDateTimeString() ?? $event->created_at?->toDateTimeString() }}
+
+
+ +
+
+
+
+
Payload
+
Event body
+
+
+ @csrf + +
+
+
{{ json_encode($event->payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}
+ @if ($event->error) +
+ {{ $event->error }} +
+ @endif +
+
+
Headers
+
Request metadata
+
{{ json_encode($event->headers, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) }}
+
+ Processed: {{ $event->processed_at?->toDateTimeString() ?? '—' }} +
+
+
+@endsection diff --git a/app/resources/views/dashboard/admin/webhooks.blade.php b/app/resources/views/dashboard/admin/webhooks.blade.php new file mode 100644 index 0000000..580bd45 --- /dev/null +++ b/app/resources/views/dashboard/admin/webhooks.blade.php @@ -0,0 +1,139 @@ +@extends('dashboard.app') + +@section('page_title', 'Admin Webhooks') +@section('page_subtitle', 'Monitor deliveries, failures, and replays.') + +@section('dashboard_content') + @if (session('status')) +
+ {{ session('status') }} +
+ @endif + +
+ @foreach ([ + ['label' => 'Events (total)', 'value' => number_format(\App\Models\WebhookEvent::count()), 'note' => 'All providers'], + ['label' => 'Failures', 'value' => number_format(\App\Models\WebhookEvent::where('status', 'error')->count()), 'note' => 'Needs replay'], + ['label' => 'Providers', 'value' => number_format(\App\Models\WebhookEvent::distinct('provider')->count('provider')), 'note' => 'Configured'], + ] as $card) +
+
{{ $card['label'] }}
+
{{ $card['value'] }}
+
{{ $card['note'] }}
+
+ @endforeach +
+ +
+
+
+
Delivery log
+
Recent events
+
+
+
+ + + + + +
+
+ @csrf + +
+
+
+ +
+ + + + @php + $sortParam = $sort ?? 'id'; + $dirParam = $dir ?? 'desc'; + $toggle = fn ($field) => ($sortParam === $field && $dirParam === 'asc') ? 'desc' : 'asc'; + $sortUrl = fn ($field) => request()->fullUrlWithQuery(['sort' => $field, 'dir' => $toggle($field)]); + @endphp + + + + + + + + + @forelse ($events ?? [] as $row) + + + + + + + + @empty + + + + @endforelse + +
+ + Event + + + + + Provider + + + + + Status + + + + + Time + + + Actions
+
#{{ $row->id }}
+
{{ $row->event_type ?? 'event' }}
+
{{ $row->provider }} + @php + $pill = $row->status === 'error' + ? ['bg' => 'bg-rose-100 dark:bg-rose-500/20', 'text' => 'text-rose-800 dark:text-rose-200'] + : ($row->status === 'pending' || $row->status === 'received' + ? ['bg' => 'bg-amber-100 dark:bg-amber-500/20', 'text' => 'text-amber-800 dark:text-amber-200'] + : ['bg' => 'bg-emerald-100 dark:bg-emerald-500/20', 'text' => 'text-emerald-800 dark:text-emerald-200']); + @endphp + + {{ $row->status }} + + {{ $row->received_at?->diffForHumans() ?? $row->created_at?->diffForHumans() }} +
+ View +
+ @csrf + +
+
+
No webhook events found.
+
+
+ {{ $events->links('vendor.pagination.dashboard') }} +
+
+@endsection diff --git a/app/resources/views/dashboard/app.blade.php b/app/resources/views/dashboard/app.blade.php new file mode 100644 index 0000000..9ef3c7c --- /dev/null +++ b/app/resources/views/dashboard/app.blade.php @@ -0,0 +1,286 @@ +@extends('site.layout') + +@php + $user = auth()->user(); + $isAdmin = Gate::allows('admin'); + + $navUser = [ + ['label' => 'Overview', 'route' => 'dashboard.overview', 'icon' => 'layout-dashboard'], + ['label' => 'My Keywords', 'route' => 'dashboard.keywords', 'icon' => 'hash'], + ['label' => 'API Keys', 'route' => 'dashboard.api-keys', 'icon' => 'key-round'], + ['label' => 'Billing', 'route' => 'dashboard.billing', 'icon' => 'badge-dollar-sign'], + ['label' => 'Preferences', 'route' => 'dashboard.preferences', 'icon' => 'settings-2'], + ['label' => 'Profile', 'route' => 'profile.edit', 'icon' => 'user-round'], + ]; + + $navAdmin = [ + ['label' => 'Overview', 'route' => 'dashboard.overview', 'icon' => 'layout-dashboard'], + ['label' => 'Users', 'route' => 'dashboard.admin.users', 'icon' => 'users'], + ['label' => 'Subscriptions', 'route' => 'dashboard.admin.subscriptions', 'icon' => 'credit-card'], + ['label' => 'Pricing', 'route' => 'dashboard.admin.pricing', 'icon' => 'badge-dollar-sign'], + ['label' => 'Webhooks', 'route' => 'dashboard.admin.webhooks', 'icon' => 'webhook'], + ['label' => 'Audit Logs', 'route' => 'dashboard.admin.audit_logs', 'icon' => 'list-checks'], + ['label' => 'Settings', 'route' => 'dashboard.admin.settings', 'icon' => 'settings'], + ['label' => 'Profile', 'route' => 'profile.edit', 'icon' => 'user-round'], + ]; + + $nav = $isAdmin ? $navAdmin : $navUser; + $exportQuery = request()->query(); +@endphp + +@section('content') +
+ + +
+
+
+
+
+
Workspace
+

{{ trim($__env->yieldContent('page_title')) ?: 'Dashboard Overview' }}

+

{{ trim($__env->yieldContent('page_subtitle')) ?: 'A shared layout with role-based navigation.' }}

+
+ +
+
+
+ +
+ @if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail()) +
+
+
+
Verify your email to unlock billing and API keys.
+
No reminders will be sent automatically.
+
+
+ @csrf + +
+
+
+ @endif + @yield('dashboard_content') +
+
+
+@endsection + +@section('mobile_nav') + +@endsection + +@section('more_menu') + + +@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/index.blade.php b/app/resources/views/dashboard/index.blade.php new file mode 100644 index 0000000..65560f4 --- /dev/null +++ b/app/resources/views/dashboard/index.blade.php @@ -0,0 +1,182 @@ +@extends('dashboard.app') + +@section('title', 'Dashboard') +@section('page_title', 'Dashboard Overview') +@section('page_subtitle', 'A shared layout with role-based navigation.') + +@section('dashboard_content') +@php + $isAdmin = Gate::allows('admin'); + $metrics = $overviewMetrics ?? [ + 'users_total' => 0, + 'users_personal' => 0, + 'subscriptions_active' => 0, + 'subscriptions_total' => 0, + 'webhook_total' => 0, + 'webhook_errors' => 0, + ]; + $personalPct = $metrics['users_total'] > 0 + ? round(($metrics['users_personal'] / $metrics['users_total']) * 100) + : 0; +@endphp + +
+
+
Total users
+
{{ number_format($metrics['users_total']) }}
+
{{ number_format($metrics['users_personal']) }} personal users
+
+
+
+
+
+
Active subscriptions
+
{{ number_format($metrics['subscriptions_active']) }}
+
{{ number_format($metrics['subscriptions_total']) }} total subscriptions
+
+ + {{ $metrics['subscriptions_active'] > 0 ? 'Live access enabled' : 'No active subs' }} +
+
+
+
Webhook events
+
{{ number_format($metrics['webhook_total']) }}
+
{{ number_format($metrics['webhook_errors']) }} failures
+
+ + {{ $metrics['webhook_errors'] > 0 ? 'Needs review' : 'All clear' }} +
+
+
+ +
+
+
+
+
Insights
+
Usage highlights
+
+ Last 7 days +
+
+
+
Top search
+
"smile"
+
14% of queries
+
+
+
Most used category
+
Smileys
+
8,214 views
+
+
+
+
New users
+
Last 7 days
+
+
+
+
+
+
+
Subscriptions
+
Created last 7 days
+
+
+
+
+
+
Webhooks
+
Events last 7 days
+
+
+
+
+
+
+ +
+@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/layout.blade.php b/app/resources/views/dashboard/layout.blade.php new file mode 100644 index 0000000..3d56fbe --- /dev/null +++ b/app/resources/views/dashboard/layout.blade.php @@ -0,0 +1,164 @@ + + + + + + @yield('title', 'Dashboard') · Dewemoji + + + + + + + +@php + $user = auth()->user(); + $isAdmin = Gate::allows('admin'); + + $navUser = [ + ['label' => 'Overview', 'href' => route('dashboard.overview')], + ['label' => 'Usage', 'href' => route('dashboard.usage')], + ['label' => 'API Keys', 'href' => route('dashboard.api-keys')], + ['label' => 'Billing', 'href' => route('dashboard.billing')], + ['label' => 'Preferences', 'href' => route('dashboard.preferences')], + ]; + $navAdmin = [ + ['label' => 'Overview', 'href' => route('dashboard.overview')], + ['label' => 'Users', 'href' => route('dashboard.admin.users')], + ['label' => 'Subscriptions', 'href' => route('dashboard.admin.subscriptions')], + ['label' => 'Pricing', 'href' => route('dashboard.admin.pricing')], + ['label' => 'Webhooks', 'href' => route('dashboard.admin.webhooks')], + ['label' => 'Settings', 'href' => route('dashboard.admin.settings')], + ]; + $nav = $isAdmin ? $navAdmin : $navUser; +@endphp + +
+
+ + +
+
+
+
+
+
Workspace
+

+ @yield('page_title', 'Dashboard Overview') +

+

@yield('page_subtitle', 'Everything you need in one calm, focused place.')

+
+
+ + +
+
+
+ +
+ @yield('content') +
+
+
+
+
+ + diff --git a/app/resources/views/dashboard/page.blade.php b/app/resources/views/dashboard/page.blade.php new file mode 100644 index 0000000..afc6517 --- /dev/null +++ b/app/resources/views/dashboard/page.blade.php @@ -0,0 +1,42 @@ +@extends('dashboard.app') + +@section('title', $title) +@section('page_title', $title) +@section('page_subtitle', $subtitle) + +@section('dashboard_content') +
+ @foreach ($kpis as $kpi) +
+
{{ $kpi['label'] }}
+
{{ $kpi['value'] }}
+
{{ $kpi['note'] }}
+
+ @endforeach +
+ +
+
+
+
Summary
+
{{ $summaryTitle }}
+
+ {{ $summaryTag }} +
+

{{ $summaryBody }}

+ +
+ @foreach ($highlights as $highlight) +
+
{{ $highlight['title'] }}
+
{{ $highlight['value'] }}
+
{{ $highlight['note'] }}
+
+ @endforeach +
+ +
+ {{ $footerNote }} +
+
+@endsection diff --git a/app/resources/views/dashboard/user/api-keys.blade.php b/app/resources/views/dashboard/user/api-keys.blade.php new file mode 100644 index 0000000..967b129 --- /dev/null +++ b/app/resources/views/dashboard/user/api-keys.blade.php @@ -0,0 +1,117 @@ +@extends('dashboard.app') + +@section('title', 'API Keys') +@section('page_title', 'API Keys') +@section('page_subtitle', 'Create and manage access tokens for integrations.') + +@section('dashboard_content') +
+
+
+
+
Your keys
+
Manage API access
+
+ @if ($canCreate) +
+ @csrf + + +
+ @endif +
+ @if (!$canCreate) +
+ API keys are available on the Personal plan. Upgrade to unlock API access. +
+ @endif + + @if ($newKey) +
+ New key created. Copy it now; you won’t be able to see it again. +
+ {{ $newKey }} + +
+
+ @endif + +
+ + + + + + + + + + + + @forelse ($keys as $key) + + + + + + + + @empty + + + + @endforelse + +
PrefixNameCreatedLast usedActions
{{ $key->key_prefix }}{{ $key->name ?? '—' }}{{ $key->created_at?->toDateString() }}{{ $key->last_used_at?->diffForHumans() ?? 'Never' }} + @if ($key->revoked_at) + Revoked + @else +
+ @csrf + +
+ @endif +
No API keys yet.
+
+
+ +
+
+
Tips
+
Keep keys safe
+
+
+ Use separate keys for apps and automate revocation if you suspect compromise. +
+
+ API keys are required to access private keyword search results. +
+
+
+@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/user/billing.blade.php b/app/resources/views/dashboard/user/billing.blade.php new file mode 100644 index 0000000..94c5add --- /dev/null +++ b/app/resources/views/dashboard/user/billing.blade.php @@ -0,0 +1,127 @@ +@extends('dashboard.app') + +@section('title', 'Billing') +@section('page_title', 'Billing') +@section('page_subtitle', 'Subscription status and plan details.') + +@section('dashboard_content') +@php + $user = $user ?? auth()->user(); + $subscription = $subscription ?? null; + $hasSub = $subscription !== null; + $orders = $orders ?? collect(); + $payments = $payments ?? collect(); +@endphp + +
+
+
Plan
+
{{ $hasSub ? ucfirst($subscription->plan ?? 'Personal') : 'Free' }}
+
{{ $hasSub ? ucfirst($subscription->status ?? 'active') : 'No subscription' }}
+
+
+
Renewal
+
+ {{ $subscription?->next_renewal_at?->toDateString() ?? '—' }} +
+
Next charge date
+
+
+
Status
+
+ {{ $subscription?->expires_at?->toDateString() ?? 'Active' }} +
+
Access ends
+
+
+ +
+
+
+
Billing summary
+
Subscription details
+
+ Current cycle +
+
+ @if ($hasSub) + Provider: {{ $subscription->provider ?? 'direct' }} · Started {{ $subscription->started_at?->toDateString() }} + @else + You are on the free plan. Upgrade to unlock private keywords and sync. + @endif +
+
+ Downgrading to Free revokes any active API keys immediately. +
+ +
+
+
Payment method
+
Card
+
Coming soon
+
+
+
Invoices
+
0
+
Billing history
+
+
+ + @if ($payments->count() > 0) +
+
Recent payments
+
+ + + + + + + + + + + + @foreach ($payments as $payment) + @php + $status = $payment->status ?? 'pending'; + $pill = $status === 'paid' + ? ['bg' => 'bg-emerald-100 dark:bg-emerald-500/20', 'text' => 'text-emerald-800 dark:text-emerald-200'] + : ($status === 'failed' + ? ['bg' => 'bg-rose-100 dark:bg-rose-500/20', 'text' => 'text-rose-800 dark:text-rose-200'] + : ['bg' => 'bg-amber-100 dark:bg-amber-500/20', 'text' => 'text-amber-800 dark:text-amber-200']); + @endphp + + + + + + + + @endforeach + +
ProviderPlanAmountStatusCreated
{{ $payment->provider ?? '—' }}{{ $payment->plan_code ?? '—' }}{{ $payment->currency ?? 'USD' }} {{ number_format((float) ($payment->amount ?? 0), 2) }} + {{ $status }} + {{ $payment->created_at?->toDateString() ?? '—' }}
+
+ @if ($payments->contains(fn ($payment) => in_array($payment->status, ['pending', 'failed'], true))) +
+ Pending or failed payments need a new checkout. Start a fresh transaction from the pricing page. +
+ + Start new checkout + + @endif +
+ @endif + + @if (!$hasSub || (string) $user?->tier !== 'personal') +
+ Upgrade to Personal for private keywords and synced personalization. +
+ + Upgrade to Personal + + @endif +
+@endsection diff --git a/app/resources/views/dashboard/user/keywords.blade.php b/app/resources/views/dashboard/user/keywords.blade.php new file mode 100644 index 0000000..749f361 --- /dev/null +++ b/app/resources/views/dashboard/user/keywords.blade.php @@ -0,0 +1,251 @@ +@extends('dashboard.app') + +@section('title', 'My Keywords') +@section('page_title', 'My Keywords') +@section('page_subtitle', 'Manage your private emoji keywords and language tags.') + +@section('dashboard_content') +@php + $user = $user ?? auth()->user(); + $isPersonal = $user && (string) $user->tier === 'personal'; + $freeLimit = $freeLimit ?? null; + $limitReached = $freeLimit !== null && $items->count() >= $freeLimit; + $emojiLookup = $emojiLookup ?? []; +@endphp + +@if (session('status')) +
+ {{ session('status') }} +
+@endif +@if ($errors->any()) +
+ {{ $errors->first() }} +
+@endif + +
+
+
+
Keyword library
+
{{ $isPersonal ? 'Ready to personalize' : 'Free plan keywords' }}
+

Add keywords to emojis to improve your personal search results.

+ @if (!$isPersonal && $freeLimit) +

Free plan limit: {{ $items->count() }} / {{ $freeLimit }} keywords.

+ @endif +
+
+ + + + Export JSON + +
+ +
+
+
+ + @if (!$isPersonal && $freeLimit) +
+ Free plan includes up to {{ $freeLimit }} keywords total. Upgrade for unlimited keywords. +
+ @endif + + + +
+ + + + + + + + + + + @forelse ($items as $item) + + @php + $lookup = $emojiLookup[$item->emoji_slug] ?? null; + @endphp + + + + + + @empty + + + + @endforelse + +
EmojiKeywordLanguageActions
+
+ {{ $lookup['emoji'] ?? '⬚' }} +
+
{{ $lookup['name'] ?? $item->emoji_slug }}
+
{{ $item->emoji_slug }}
+
+
+
{{ $item->keyword }}{{ $item->lang ?? 'und' }} + +
+ @csrf + @method('DELETE') + +
+
No keywords yet.
+
+
+ + +@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/user/overview.blade.php b/app/resources/views/dashboard/user/overview.blade.php new file mode 100644 index 0000000..c7e5147 --- /dev/null +++ b/app/resources/views/dashboard/user/overview.blade.php @@ -0,0 +1,93 @@ +@extends('dashboard.app') + +@section('title', 'Dashboard') +@section('page_title', 'Your Overview') +@section('page_subtitle', 'Quick stats and recent keyword activity.') + +@section('dashboard_content') +@php + $user = auth()->user(); + $isPersonal = $user && (string) $user->tier === 'personal'; + $subscription = $subscription ?? null; +@endphp + +
+
+
Total keywords
+
{{ number_format($totalKeywords ?? 0) }}
+
Across your emoji library
+
+
+
Last 7 days
+
{{ number_format($recentWeekCount ?? 0) }}
+
New keywords added
+
+
+
API keys
+
{{ number_format($apiKeyCount ?? 0) }}
+
Active keys
+
+
+
Plan
+
{{ $isPersonal ? 'Personal' : 'Free' }}
+
+ {{ $subscription?->status ? ucfirst($subscription->status) : 'No active subscription' }} +
+
+
+
Synced devices
+
0
+
Coming soon
+
+
+ +
+
+
+
+
Recent keywords
+
Latest additions
+
+ + Manage keywords + +
+ +
+ @forelse ($recentKeywords ?? [] as $keyword) +
+
{{ $keyword->lang ?? 'und' }}
+
{{ $keyword->keyword }}
+
Emoji slug: {{ $keyword->emoji_slug }}
+
+ @empty +
+ No keywords yet. Add your first keyword from an emoji detail page or the dashboard. +
+ @endforelse +
+
+ +
+
+
Next steps
+
Personalize faster
+
+
+ Add keywords right on emoji detail pages to speed up your searches. +
+ @if (!$isPersonal) +
+ Upgrade to Personal to unlock private keywords and sync across devices. +
+ + Upgrade to Personal + + @else + + Add keywords + + @endif +
+
+@endsection diff --git a/app/resources/views/dashboard/user/preferences.blade.php b/app/resources/views/dashboard/user/preferences.blade.php new file mode 100644 index 0000000..6d14a50 --- /dev/null +++ b/app/resources/views/dashboard/user/preferences.blade.php @@ -0,0 +1,122 @@ +@extends('dashboard.app') + +@section('title', 'Preferences') +@section('page_title', 'Preferences') +@section('page_subtitle', 'Personalize your Dewemoji experience.') + +@section('dashboard_content') +
+
+
Personal settings
+
Preferences
+

Saved locally for now. We will sync these to your account later.

+ +
+
+ + +
Matches the global theme toggle.
+
+
+ + +
Controls language defaults.
+
+
+ + +
Prefer a skin tone when available.
+
+
+ + +
Default action for emoji pickers.
+
+
+ +
+
+ +
+
+
Preferences
+
What’s next
+
+
+ Sync preferences across devices and extensions once account settings are wired. +
+
+ Add tone presets and quick language switching. +
+
+
+@endsection + +@push('scripts') + +@endpush diff --git a/app/resources/views/dashboard/user/profile.blade.php b/app/resources/views/dashboard/user/profile.blade.php new file mode 100644 index 0000000..ef5a4e5 --- /dev/null +++ b/app/resources/views/dashboard/user/profile.blade.php @@ -0,0 +1,25 @@ +@extends('dashboard.app') + +@section('title', 'Profile') +@section('page_title', 'Profile') +@section('page_subtitle', 'Update your account details and security settings.') + +@section('dashboard_content') + @if (session('status') === 'profile-updated') +
+ Profile updated. +
+ @endif + +
+
+ @include('profile.partials.update-profile-information-form') +
+
+ @include('profile.partials.update-password-form') +
+
+ @include('profile.partials.delete-user-form') +
+
+@endsection diff --git a/app/resources/views/emails/reset-password.blade.php b/app/resources/views/emails/reset-password.blade.php new file mode 100644 index 0000000..c7051f6 --- /dev/null +++ b/app/resources/views/emails/reset-password.blade.php @@ -0,0 +1,101 @@ +@php + $logoUrl = rtrim(config('app.url', ''), '/') . '/assets/logo/logo-mark-128.png'; +@endphp + + + + + + Dewemoji Password Reset + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Password reset +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ 🔒 + + Reset your password +
+
+ We received a request to reset your Dewemoji password. Click the button below to choose a new one. +
+ + Reset Password + +
+ If the button does not work, paste this link into your browser: +
+ {{ $resetUrl }} +
+
+ + + + + + + +
+ This link expires in 60 minutes. If you did not request a password reset, you can safely ignore this email. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/resources/views/emails/test.blade.php b/app/resources/views/emails/test.blade.php new file mode 100644 index 0000000..34fedd1 --- /dev/null +++ b/app/resources/views/emails/test.blade.php @@ -0,0 +1,40 @@ + + + + + + Dewemoji test email + + + + + + +
+ + + + + + + + + + + + + +
+ Dewemoji +
+ This is a test email sent via the Mailketing API from your Dewemoji app. +
+ + Open Dewemoji + +
+ If the button does not work, open this link: {{ $actionUrl }} +
+
+ + diff --git a/app/resources/views/emails/verify-email.blade.php b/app/resources/views/emails/verify-email.blade.php new file mode 100644 index 0000000..0de0373 --- /dev/null +++ b/app/resources/views/emails/verify-email.blade.php @@ -0,0 +1,101 @@ +@php + $logoUrl = rtrim(config('app.url', ''), '/') . '/assets/logo/logo-mark-128.png'; +@endphp + + + + + + Dewemoji Email Verification + + + + + + +
+ + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ Dewemoji + + Dewemoji +
+
+ Email verification +
+
+ + + + + + + + + + + + + +
+ + + + + +
+ + + Verify your email +
+
+ Thanks for joining Dewemoji. Confirm your email to activate your account and start saving emoji keywords. +
+ + Verify Email + +
+ If the button does not work, paste this link into your browser: +
+ {{ $verificationUrl }} +
+
+ + + + + + + +
+ This link expires in 60 minutes. If you did not request this email, you can safely ignore it. +
+ Dewemoji • Emoji discovery and keywords for creators +
+
+
+ + diff --git a/app/resources/views/layouts/app.blade.php b/app/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..0719113 --- /dev/null +++ b/app/resources/views/layouts/app.blade.php @@ -0,0 +1,36 @@ + + + + + + + + {{ config('app.name', 'Dewemoji') }} + + + + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + +
+ @include('layouts.navigation') + + + @isset($header) +
+
+ {{ $header }} +
+
+ @endisset + + +
+ {{ $slot }} +
+
+ + diff --git a/app/resources/views/layouts/guest.blade.php b/app/resources/views/layouts/guest.blade.php new file mode 100644 index 0000000..82bb9b6 --- /dev/null +++ b/app/resources/views/layouts/guest.blade.php @@ -0,0 +1,144 @@ + + + + + + + + @yield('title', config('app.name', 'Dewemoji')) + + + + + + + + + + + + + + + @vite(['resources/js/app.js']) + + + +
+
+
+
+ +
+
+
+ + + Dewemoji logo + + Dewemoji + + +
+ +
+ {{ $slot }} +
+
+
+ + + + + diff --git a/app/resources/views/layouts/navigation.blade.php b/app/resources/views/layouts/navigation.blade.php new file mode 100644 index 0000000..16a500d --- /dev/null +++ b/app/resources/views/layouts/navigation.blade.php @@ -0,0 +1,100 @@ + diff --git a/app/resources/views/profile/edit.blade.php b/app/resources/views/profile/edit.blade.php new file mode 100644 index 0000000..e0e1d38 --- /dev/null +++ b/app/resources/views/profile/edit.blade.php @@ -0,0 +1,29 @@ + + +

+ {{ __('Profile') }} +

+
+ +
+
+
+
+ @include('profile.partials.update-profile-information-form') +
+
+ +
+
+ @include('profile.partials.update-password-form') +
+
+ +
+
+ @include('profile.partials.delete-user-form') +
+
+
+
+
diff --git a/app/resources/views/profile/partials/delete-user-form.blade.php b/app/resources/views/profile/partials/delete-user-form.blade.php new file mode 100644 index 0000000..edeeb4a --- /dev/null +++ b/app/resources/views/profile/partials/delete-user-form.blade.php @@ -0,0 +1,55 @@ +
+
+

+ {{ __('Delete Account') }} +

+ +

+ {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }} +

+
+ + {{ __('Delete Account') }} + + +
+ @csrf + @method('delete') + +

+ {{ __('Are you sure you want to delete your account?') }} +

+ +

+ {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} +

+ +
+ + + + + +
+ +
+ + {{ __('Cancel') }} + + + + {{ __('Delete Account') }} + +
+
+
+
diff --git a/app/resources/views/profile/partials/update-password-form.blade.php b/app/resources/views/profile/partials/update-password-form.blade.php new file mode 100644 index 0000000..eaca1ac --- /dev/null +++ b/app/resources/views/profile/partials/update-password-form.blade.php @@ -0,0 +1,48 @@ +
+
+

+ {{ __('Update Password') }} +

+ +

+ {{ __('Ensure your account is using a long, random password to stay secure.') }} +

+
+ +
+ @csrf + @method('put') + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ {{ __('Save') }} + + @if (session('status') === 'password-updated') +

{{ __('Saved.') }}

+ @endif +
+
+
diff --git a/app/resources/views/profile/partials/update-profile-information-form.blade.php b/app/resources/views/profile/partials/update-profile-information-form.blade.php new file mode 100644 index 0000000..5ae3d35 --- /dev/null +++ b/app/resources/views/profile/partials/update-profile-information-form.blade.php @@ -0,0 +1,64 @@ +
+
+

+ {{ __('Profile Information') }} +

+ +

+ {{ __("Update your account's profile information and email address.") }} +

+
+ +
+ @csrf +
+ +
+ @csrf + @method('patch') + +
+ + + +
+ +
+ + + + + @if ($user instanceof \Illuminate\Contracts\Auth\MustVerifyEmail && ! $user->hasVerifiedEmail()) +
+

+ {{ __('Your email address is unverified.') }} + + +

+ + @if (session('status') === 'verification-link-sent') +

+ {{ __('A new verification link has been sent to your email address.') }} +

+ @endif +
+ @endif +
+ +
+ {{ __('Save') }} + + @if (session('status') === 'profile-updated') +

{{ __('Saved.') }}

+ @endif +
+
+
diff --git a/app/resources/views/site/api-docs.blade.php b/app/resources/views/site/api-docs.blade.php index 747e20b..ed5736d 100644 --- a/app/resources/views/site/api-docs.blade.php +++ b/app/resources/views/site/api-docs.blade.php @@ -5,7 +5,7 @@ @push('head') @endpush @@ -48,6 +49,18 @@
+ @auth + + + + + @endauth + @guest + + + + + @endguest @@ -65,11 +78,11 @@
-
+
- + @@ -77,14 +90,18 @@
- - + -
@@ -159,41 +176,48 @@
-
-
Copied!
+ + @endsection @push('scripts') + - - - + + @vite(['resources/js/app.js']) @stack('head') @stack('jsonld') - +
@@ -132,7 +355,255 @@ @yield('content') + @hasSection('mobile_nav') + @yield('mobile_nav') + @else + + @endif + + @hasSection('more_menu') + @yield('more_menu') + @else + + + @endif + + + + + + + + @stack('scripts') diff --git a/app/resources/views/site/pricing.blade.php b/app/resources/views/site/pricing.blade.php index e10f341..414517d 100644 --- a/app/resources/views/site/pricing.blade.php +++ b/app/resources/views/site/pricing.blade.php @@ -1,7 +1,7 @@ @extends('site.layout') @section('title', 'Pricing - Dewemoji') -@section('meta_description', 'Choose Dewemoji pricing for Free, Pro subscription, and Lifetime access for website, extension, and API usage.') +@section('meta_description', 'Choose Dewemoji pricing for Free, Personal subscription, and Lifetime access for website, extension, and API usage.') @push('jsonld') + + + + + +@endpush diff --git a/app/resources/views/site/privacy.blade.php b/app/resources/views/site/privacy.blade.php index d0b215a..c09facf 100644 --- a/app/resources/views/site/privacy.blade.php +++ b/app/resources/views/site/privacy.blade.php @@ -5,10 +5,10 @@ @push('head') @endpush @@ -30,6 +30,12 @@
+ @auth + + @endauth + @guest + + @endguest
@@ -41,9 +47,16 @@
Legal / Privacy Policy

Privacy Policy

-
-
Last Updated
-
February 5, 2026
+
+
+
Last Updated
+
February 5, 2026
+
+
diff --git a/app/resources/views/site/support.blade.php b/app/resources/views/site/support.blade.php index 4f694e3..e17ffc3 100644 --- a/app/resources/views/site/support.blade.php +++ b/app/resources/views/site/support.blade.php @@ -35,15 +35,28 @@
+ @auth + + @endauth + @guest + + @endguest
-
-
Public / Support
-

Support Center

+
+
+
Public / Support
+

Support Center

+
+
diff --git a/app/resources/views/site/terms.blade.php b/app/resources/views/site/terms.blade.php index 1f29282..3493ddd 100644 --- a/app/resources/views/site/terms.blade.php +++ b/app/resources/views/site/terms.blade.php @@ -5,9 +5,9 @@ @push('head') @endpush @@ -29,6 +29,12 @@
+ @auth + + @endauth + @guest + + @endguest
@@ -40,9 +46,16 @@
Legal / Terms

Terms of Service

-
-
Last Updated
-
February 5, 2026
+
+
+
Last Updated
+
February 5, 2026
+
+
diff --git a/app/resources/views/vendor/pagination/dashboard.blade.php b/app/resources/views/vendor/pagination/dashboard.blade.php new file mode 100644 index 0000000..986d4ec --- /dev/null +++ b/app/resources/views/vendor/pagination/dashboard.blade.php @@ -0,0 +1,43 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/app/resources/views/welcome.blade.php b/app/resources/views/welcome.blade.php index b7355d7..9491021 100644 --- a/app/resources/views/welcome.blade.php +++ b/app/resources/views/welcome.blade.php @@ -4,7 +4,7 @@ - {{ config('app.name', 'Laravel') }} + {{ config('app.name', 'Dewemoji') }} diff --git a/app/routes/api.php b/app/routes/api.php index af52449..1209641 100644 --- a/app/routes/api.php +++ b/app/routes/api.php @@ -3,12 +3,25 @@ use App\Http\Controllers\Api\V1\EmojiApiController; use App\Http\Controllers\Api\V1\LicenseController; use App\Http\Controllers\Api\V1\SystemController; +use App\Http\Controllers\Api\V1\AdminUserController; +use App\Http\Controllers\Api\V1\AdminPricingController; +use App\Http\Controllers\Api\V1\AdminSettingsController; +use App\Http\Controllers\Api\V1\AdminSubscriptionController; +use App\Http\Controllers\Api\V1\AdminAnalyticsController; +use App\Http\Controllers\Api\V1\AdminWebhookController; +use App\Http\Controllers\Api\V1\PaypalWebhookController; +use App\Http\Controllers\Api\V1\ExtensionController; +use App\Http\Controllers\Api\V1\UserController; +use App\Http\Controllers\Api\V1\UserKeywordController; +use App\Http\Controllers\Api\V1\PricingController; +use App\Http\Controllers\Billing\PayPalController; +use App\Http\Controllers\Billing\PakasirController; use Illuminate\Support\Facades\Route; Route::options('/v1/{any}', function () { $headers = [ - 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS', - 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-License-Key, X-Account-Id, X-Dewemoji-Frontend', + 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-License-Key, X-Api-Key, X-Admin-Token, X-Account-Id, X-Dewemoji-Frontend, X-Extension-Token', 'Vary' => 'Origin', ]; $origin = request()->headers->get('Origin', ''); @@ -20,16 +33,56 @@ Route::options('/v1/{any}', function () { return response('', 204, $headers); })->where('any', '.*'); +Route::post('/paypal/webhook', [PayPalController::class, 'webhook']); +Route::post('/webhooks/pakasir', [PakasirController::class, 'webhook']); + Route::prefix('v1')->group(function () { Route::get('/categories', [EmojiApiController::class, 'categories']); Route::get('/emojis', [EmojiApiController::class, 'emojis']); + Route::get('/search', [EmojiApiController::class, 'search']); Route::get('/emoji', [EmojiApiController::class, 'emoji']); Route::get('/emoji/{slug}', [EmojiApiController::class, 'emoji']); + Route::get('/pricing', [PricingController::class, 'index']); + Route::post('/extension/verify', [ExtensionController::class, 'verify']); + Route::get('/extension/search', [ExtensionController::class, 'search']); Route::post('/license/verify', [LicenseController::class, 'verify']); Route::post('/license/activate', [LicenseController::class, 'activate']); Route::post('/license/deactivate', [LicenseController::class, 'deactivate']); + Route::post('/user/register', [UserController::class, 'register']); + Route::post('/user/login', [UserController::class, 'login']); + Route::post('/user/logout', [UserController::class, 'logout']); + Route::get('/user/apikeys', [UserController::class, 'listApiKeys']); + Route::post('/user/apikeys', [UserController::class, 'createApiKey']); + Route::delete('/user/apikeys/{key}', [UserController::class, 'revokeApiKey']); + + Route::get('/keywords', [UserKeywordController::class, 'index']); + Route::post('/keywords', [UserKeywordController::class, 'store']); + Route::put('/keywords/{id}', [UserKeywordController::class, 'update']); + Route::delete('/keywords/{id}', [UserKeywordController::class, 'destroy']); + Route::post('/keywords/import', [UserKeywordController::class, 'import']); + Route::get('/keywords/export', [UserKeywordController::class, 'export']); + + Route::post('/admin/user/tier', [AdminUserController::class, 'setTier']); + Route::get('/admin/users', [AdminUserController::class, 'index']); + Route::get('/admin/user', [AdminUserController::class, 'show']); + Route::get('/admin/pricing', [AdminPricingController::class, 'index']); + Route::post('/admin/pricing', [AdminPricingController::class, 'update']); + Route::get('/admin/pricing/changes', [AdminPricingController::class, 'changes']); + Route::post('/admin/pricing/reset', [AdminPricingController::class, 'reset']); + Route::get('/admin/settings', [AdminSettingsController::class, 'index']); + Route::post('/admin/settings', [AdminSettingsController::class, 'update']); + Route::get('/admin/subscriptions', [AdminSubscriptionController::class, 'index']); + Route::post('/admin/subscription/grant', [AdminSubscriptionController::class, 'grant']); + Route::post('/admin/subscription/revoke', [AdminSubscriptionController::class, 'revoke']); + Route::get('/admin/analytics', [AdminAnalyticsController::class, 'overview']); + Route::get('/admin/webhooks', [AdminWebhookController::class, 'index']); + Route::get('/admin/webhooks/{id}', [AdminWebhookController::class, 'show']); + Route::post('/admin/webhooks/{id}/replay', [AdminWebhookController::class, 'replay']); + + Route::post('/paypal/webhook', [PaypalWebhookController::class, 'handle']); + Route::get('/health', [SystemController::class, 'health']); Route::get('/metrics-lite', [SystemController::class, 'metricsLite']); Route::get('/metrics', [SystemController::class, 'metrics']); diff --git a/app/routes/auth.php b/app/routes/auth.php new file mode 100644 index 0000000..3926ecf --- /dev/null +++ b/app/routes/auth.php @@ -0,0 +1,59 @@ +group(function () { + Route::get('register', [RegisteredUserController::class, 'create']) + ->name('register'); + + Route::post('register', [RegisteredUserController::class, 'store']); + + Route::get('login', [AuthenticatedSessionController::class, 'create']) + ->name('login'); + + Route::post('login', [AuthenticatedSessionController::class, 'store']); + + Route::get('forgot-password', [PasswordResetLinkController::class, 'create']) + ->name('password.request'); + + Route::post('forgot-password', [PasswordResetLinkController::class, 'store']) + ->name('password.email'); + + Route::get('reset-password/{token}', [NewPasswordController::class, 'create']) + ->name('password.reset'); + + Route::post('reset-password', [NewPasswordController::class, 'store']) + ->name('password.store'); +}); + +Route::middleware('auth')->group(function () { + Route::get('verify-email', EmailVerificationPromptController::class) + ->name('verification.notice'); + + Route::get('verify-email/{id}/{hash}', VerifyEmailController::class) + ->middleware(['signed', 'throttle:6,1']) + ->name('verification.verify'); + + Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store']) + ->middleware('throttle:6,1') + ->name('verification.send'); + + Route::get('confirm-password', [ConfirmablePasswordController::class, 'show']) + ->name('password.confirm'); + + Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']); + + Route::put('password', [PasswordController::class, 'update'])->name('password.update'); + + Route::post('logout', [AuthenticatedSessionController::class, 'destroy']) + ->name('logout'); +}); diff --git a/app/routes/console.php b/app/routes/console.php index 71c153c..f2d3255 100644 --- a/app/routes/console.php +++ b/app/routes/console.php @@ -2,7 +2,13 @@ use Illuminate\Foundation\Inspiring; use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Schedule; use App\Services\LiveSqlImportService; +use App\Services\Billing\PaypalWebhookProcessor; +use App\Services\Billing\PayPalPlanSyncService; +use App\Models\WebhookEvent; +use Illuminate\Support\Facades\Mail; +use App\Mail\TestMailketing; Artisan::command('inspire', function () { $this->comment(Inspiring::quote()); @@ -16,3 +22,80 @@ Artisan::command('dewemoji:import-live-sql {path : Absolute path to dewemojiAPI_ $importer = app(LiveSqlImportService::class); $importer->import($path, $truncate, $batch, $this->output); })->purpose('Import live SQL dump into the current database'); + +Artisan::command('dewemoji:webhooks:process {--limit=100 : Max events to process} {--status=pending,received : Comma-separated statuses}', function () { + $limit = (int) $this->option('limit'); + $statuses = array_filter(array_map('trim', explode(',', (string) $this->option('status')))); + + if (empty($statuses)) { + $this->error('No statuses provided.'); + return 1; + } + + $processor = app(PaypalWebhookProcessor::class); + + $events = WebhookEvent::query() + ->whereIn('status', $statuses) + ->orderBy('id') + ->limit($limit) + ->get(); + + $processed = 0; + $failed = 0; + + foreach ($events as $event) { + try { + if ($event->provider === 'paypal') { + $processor->process((string) ($event->event_type ?? ''), $event->payload ?? []); + } + $event->update([ + 'status' => 'processed', + 'processed_at' => now(), + 'error' => null, + ]); + $processed++; + } catch (\Throwable $e) { + $event->update([ + 'status' => 'error', + 'processed_at' => now(), + 'error' => $e->getMessage(), + ]); + $failed++; + } + } + + $this->info("Processed {$processed} events, failed {$failed}."); + return 0; +})->purpose('Process pending webhook events'); + +Schedule::command('dewemoji:webhooks:process --limit=200')->everyMinute()->withoutOverlapping(); + +Artisan::command('paypal:sync-plans {--mode=both : sandbox|live|both}', function () { + $mode = (string) $this->option('mode'); + $service = app(PayPalPlanSyncService::class); + + $runMode = match ($mode) { + 'sandbox' => ['sandbox'], + 'live' => ['live'], + default => ['sandbox', 'live'], + }; + + foreach ($runMode as $env) { + $this->info("Syncing PayPal plans: {$env}"); + $result = $service->sync($env); + $this->line("Created: {$result['created']} · Updated: {$result['updated']} · Deactivated: {$result['deactivated']} · Skipped: {$result['skipped']}"); + } +})->purpose('Create/rotate PayPal plans based on pricing plans'); + +Artisan::command('mailketing:test {email : Recipient email address}', function () { + $email = (string) $this->argument('email'); + + try { + Mail::to($email)->send(new TestMailketing()); + $this->info("Mailketing test email sent to {$email}."); + return 0; + } catch (\Throwable $e) { + $this->error('Mailketing test failed: '.$e->getMessage()); + return 1; + } +})->purpose('Send a Mailketing API test email'); diff --git a/app/routes/dashboard.php b/app/routes/dashboard.php new file mode 100644 index 0000000..1e8371f --- /dev/null +++ b/app/routes/dashboard.php @@ -0,0 +1,56 @@ +prefix('dashboard')->name('dashboard.')->group(function () { + Route::middleware('verified')->group(function () { + Route::get('/', [UserDashboardController::class, 'overview'])->name('overview'); + Route::get('/keywords', [UserDashboardController::class, 'keywords'])->name('keywords'); + Route::get('/keywords/search', [UserDashboardController::class, 'keywordSearch'])->name('keywords.search'); + Route::post('/keywords', [UserDashboardController::class, 'storeKeyword'])->name('keywords.store'); + Route::put('/keywords/{keyword}', [UserDashboardController::class, 'updateKeyword'])->name('keywords.update'); + Route::delete('/keywords/{keyword}', [UserDashboardController::class, 'deleteKeyword'])->name('keywords.delete'); + Route::post('/keywords/import', [UserDashboardController::class, 'importKeywords'])->name('keywords.import'); + Route::get('/keywords/export', [UserDashboardController::class, 'exportKeywords'])->name('keywords.export'); + + Route::get('/api-keys', [UserDashboardController::class, 'apiKeys'])->name('api-keys'); + Route::post('/api-keys', [UserDashboardController::class, 'createApiKey'])->name('api-keys.create'); + Route::post('/api-keys/{key}/revoke', [UserDashboardController::class, 'revokeApiKey'])->name('api-keys.revoke'); + + Route::get('/billing', [UserDashboardController::class, 'billing'])->name('billing'); + Route::get('/preferences', [UserDashboardController::class, 'preferences'])->name('preferences'); + + Route::middleware('can:admin')->prefix('admin')->name('admin.')->group(function () { + Route::get('/users', [AdminDashboardController::class, 'users'])->name('users'); + Route::get('/users/{user}', [AdminDashboardController::class, 'userDetail'])->name('users.show'); + Route::post('/users/tier', [AdminDashboardController::class, 'updateUserTier'])->name('users.tier'); + Route::post('/users/create', [AdminDashboardController::class, 'createUser'])->name('users.create'); + Route::delete('/users/{user}', [AdminDashboardController::class, 'deleteUser'])->name('users.delete'); + + Route::get('/subscriptions', [AdminDashboardController::class, 'subscriptions'])->name('subscriptions'); + Route::get('/subscriptions/{subscription}', [AdminDashboardController::class, 'subscriptionDetail'])->name('subscriptions.show'); + Route::post('/subscriptions/grant', [AdminDashboardController::class, 'grantSubscription'])->name('subscriptions.grant'); + Route::post('/subscriptions/revoke', [AdminDashboardController::class, 'revokeSubscription'])->name('subscriptions.revoke'); + + Route::get('/pricing', [AdminDashboardController::class, 'pricing'])->name('pricing'); + Route::post('/pricing/update', [AdminDashboardController::class, 'updatePricing'])->name('pricing.update'); + Route::post('/pricing/reset', [AdminDashboardController::class, 'resetPricing'])->name('pricing.reset'); + Route::post('/pricing/snapshot', [AdminDashboardController::class, 'createPricingSnapshot'])->name('pricing.snapshot'); + Route::post('/pricing/paypal-sync', [AdminDashboardController::class, 'syncPaypalPlans'])->name('pricing.paypal_sync'); + + Route::get('/webhooks', [AdminDashboardController::class, 'webhooks'])->name('webhooks'); + Route::post('/webhooks/{id}/replay', [AdminDashboardController::class, 'replayWebhook'])->name('webhooks.replay'); + Route::post('/webhooks/replay-failed', [AdminDashboardController::class, 'replayFailedWebhooks'])->name('webhooks.replay_failed'); + Route::get('/webhooks/{event}', [AdminDashboardController::class, 'webhookDetail'])->name('webhooks.show'); + + Route::get('/settings', [AdminDashboardController::class, 'settings'])->name('settings'); + Route::post('/settings/update', [AdminDashboardController::class, 'updateSettings'])->name('settings.update'); + + Route::get('/export/{type}', [AdminDashboardController::class, 'exportCsv'])->name('export'); + Route::get('/audit-logs', [AdminDashboardController::class, 'auditLogs'])->name('audit_logs'); + }); + }); +}); diff --git a/app/routes/web.php b/app/routes/web.php index fe113f0..56214a0 100644 --- a/app/routes/web.php +++ b/app/routes/web.php @@ -1,6 +1,9 @@ name('home'); @@ -11,14 +14,37 @@ Route::get('/api-docs', [SiteController::class, 'apiDocs'])->name('api-docs'); Route::get('/emoji/{slug}', [SiteController::class, 'emojiDetail'])->name('emoji-detail'); Route::get('/pricing', [SiteController::class, 'pricing'])->name('pricing'); +Route::post('/pricing/currency', [SiteController::class, 'setPricingCurrency'])->name('pricing.currency'); Route::get('/support', [SiteController::class, 'support'])->name('support'); Route::get('/privacy', [SiteController::class, 'privacy'])->name('privacy'); Route::get('/terms', [SiteController::class, 'terms'])->name('terms'); +Route::get('/profile', function () { + return redirect()->route('profile.edit'); +})->middleware('auth'); Route::get('/{categorySlug}', [SiteController::class, 'category']) ->where('categorySlug', 'all|smileys|people|animals|food|travel|activities|objects|symbols|flags') ->name('category'); Route::get('/{categorySlug}/{subcategorySlug}', [SiteController::class, 'categorySubcategory']) ->where('categorySlug', 'all|smileys|people|animals|food|travel|activities|objects|symbols|flags') - ->where('subcategorySlug', '[a-z0-9\-]+') + ->where('subcategorySlug', '[a-z0-9\\-]+') ->name('category-subcategory'); + +Route::middleware('auth')->group(function () { + Route::post('/billing/paypal/create', [PayPalController::class, 'createSubscription']) + ->middleware('verified') + ->name('billing.paypal.create'); + Route::get('/billing/paypal/return', [PayPalController::class, 'return'])->name('billing.paypal.return'); + Route::post('/billing/pakasir/create', [PakasirController::class, 'createTransaction']) + ->middleware('verified') + ->name('billing.pakasir.create'); + Route::post('/billing/pakasir/cancel', [PakasirController::class, 'cancelPending']) + ->middleware('verified') + ->name('billing.pakasir.cancel'); + + Route::get('/dashboard/profile', [ProfileController::class, 'edit'])->name('profile.edit'); + Route::patch('/dashboard/profile', [ProfileController::class, 'update'])->name('profile.update'); + Route::delete('/dashboard/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); +}); + +require __DIR__.'/auth.php'; diff --git a/app/tailwind.config.js b/app/tailwind.config.js new file mode 100644 index 0000000..3174ef2 --- /dev/null +++ b/app/tailwind.config.js @@ -0,0 +1,22 @@ +import defaultTheme from 'tailwindcss/defaultTheme'; +import forms from '@tailwindcss/forms'; + +/** @type {import('tailwindcss').Config} */ +export default { + darkMode: 'class', + content: [ + './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php', + './storage/framework/views/*.php', + './resources/views/**/*.blade.php', + ], + + theme: { + extend: { + fontFamily: { + sans: ['Figtree', ...defaultTheme.fontFamily.sans], + }, + }, + }, + + plugins: [forms], +}; diff --git a/app/tests/Feature/ApiV1EndpointsTest.php b/app/tests/Feature/ApiV1EndpointsTest.php index 4e78403..2a23221 100644 --- a/app/tests/Feature/ApiV1EndpointsTest.php +++ b/app/tests/Feature/ApiV1EndpointsTest.php @@ -2,11 +2,14 @@ namespace Tests\Feature; +use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Http; use Tests\TestCase; class ApiV1EndpointsTest extends TestCase { + use RefreshDatabase; + protected function setUp(): void { parent::setUp(); diff --git a/app/tests/Feature/Auth/AuthenticationTest.php b/app/tests/Feature/Auth/AuthenticationTest.php new file mode 100644 index 0000000..f04b319 --- /dev/null +++ b/app/tests/Feature/Auth/AuthenticationTest.php @@ -0,0 +1,54 @@ +get('/login'); + + $response->assertStatus(200); + } + + public function test_users_can_authenticate_using_the_login_screen(): void + { + $user = User::factory()->create(); + + $response = $this->post('/login', [ + 'email' => $user->email, + 'password' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard.overview', absolute: false)); + } + + public function test_users_can_not_authenticate_with_invalid_password(): void + { + $user = User::factory()->create(); + + $this->post('/login', [ + 'email' => $user->email, + 'password' => 'wrong-password', + ]); + + $this->assertGuest(); + } + + public function test_users_can_logout(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/logout'); + + $this->assertGuest(); + $response->assertRedirect('/'); + } +} diff --git a/app/tests/Feature/Auth/EmailVerificationTest.php b/app/tests/Feature/Auth/EmailVerificationTest.php new file mode 100644 index 0000000..e1ee96e --- /dev/null +++ b/app/tests/Feature/Auth/EmailVerificationTest.php @@ -0,0 +1,58 @@ +unverified()->create(); + + $response = $this->actingAs($user)->get('/verify-email'); + + $response->assertStatus(200); + } + + public function test_email_can_be_verified(): void + { + $user = User::factory()->unverified()->create(); + + Event::fake(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1($user->email)] + ); + + $response = $this->actingAs($user)->get($verificationUrl); + + Event::assertDispatched(Verified::class); + $this->assertTrue($user->fresh()->hasVerifiedEmail()); + $response->assertRedirect(route('dashboard.overview', absolute: false).'?verified=1'); + } + + public function test_email_is_not_verified_with_invalid_hash(): void + { + $user = User::factory()->unverified()->create(); + + $verificationUrl = URL::temporarySignedRoute( + 'verification.verify', + now()->addMinutes(60), + ['id' => $user->id, 'hash' => sha1('wrong-email')] + ); + + $this->actingAs($user)->get($verificationUrl); + + $this->assertFalse($user->fresh()->hasVerifiedEmail()); + } +} diff --git a/app/tests/Feature/Auth/PasswordConfirmationTest.php b/app/tests/Feature/Auth/PasswordConfirmationTest.php new file mode 100644 index 0000000..ff85721 --- /dev/null +++ b/app/tests/Feature/Auth/PasswordConfirmationTest.php @@ -0,0 +1,44 @@ +create(); + + $response = $this->actingAs($user)->get('/confirm-password'); + + $response->assertStatus(200); + } + + public function test_password_can_be_confirmed(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'password', + ]); + + $response->assertRedirect(); + $response->assertSessionHasNoErrors(); + } + + public function test_password_is_not_confirmed_with_invalid_password(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrors(); + } +} diff --git a/app/tests/Feature/Auth/PasswordResetTest.php b/app/tests/Feature/Auth/PasswordResetTest.php new file mode 100644 index 0000000..aa50350 --- /dev/null +++ b/app/tests/Feature/Auth/PasswordResetTest.php @@ -0,0 +1,73 @@ +get('/forgot-password'); + + $response->assertStatus(200); + } + + public function test_reset_password_link_can_be_requested(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class); + } + + public function test_reset_password_screen_can_be_rendered(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get('/reset-password/'.$notification->token); + + $response->assertStatus(200); + + return true; + }); + } + + public function test_password_can_be_reset_with_valid_token(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['email' => $user->email]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->post('/reset-password', [ + 'token' => $notification->token, + 'email' => $user->email, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login')); + + return true; + }); + } +} diff --git a/app/tests/Feature/Auth/PasswordUpdateTest.php b/app/tests/Feature/Auth/PasswordUpdateTest.php new file mode 100644 index 0000000..ca28c6c --- /dev/null +++ b/app/tests/Feature/Auth/PasswordUpdateTest.php @@ -0,0 +1,51 @@ +create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); + } + + public function test_correct_password_must_be_provided_to_update_password(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'wrong-password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasErrorsIn('updatePassword', 'current_password') + ->assertRedirect('/profile'); + } +} diff --git a/app/tests/Feature/Auth/RegistrationTest.php b/app/tests/Feature/Auth/RegistrationTest.php new file mode 100644 index 0000000..c4691a4 --- /dev/null +++ b/app/tests/Feature/Auth/RegistrationTest.php @@ -0,0 +1,31 @@ +get('/register'); + + $response->assertStatus(200); + } + + public function test_new_users_can_register(): void + { + $response = $this->post('/register', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard.overview', absolute: false)); + } +} diff --git a/app/tests/Feature/ProfileTest.php b/app/tests/Feature/ProfileTest.php new file mode 100644 index 0000000..252fdcc --- /dev/null +++ b/app/tests/Feature/ProfileTest.php @@ -0,0 +1,99 @@ +create(); + + $response = $this + ->actingAs($user) + ->get('/profile'); + + $response->assertOk(); + } + + public function test_profile_information_can_be_updated(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $user->refresh(); + + $this->assertSame('Test User', $user->name); + $this->assertSame('test@example.com', $user->email); + $this->assertNull($user->email_verified_at); + } + + public function test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->patch('/profile', [ + 'name' => 'Test User', + 'email' => $user->email, + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertNotNull($user->refresh()->email_verified_at); + } + + public function test_user_can_delete_their_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->delete('/profile', [ + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/'); + + $this->assertGuest(); + $this->assertNull($user->fresh()); + } + + public function test_correct_password_must_be_provided_to_delete_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->delete('/profile', [ + 'password' => 'wrong-password', + ]); + + $response + ->assertSessionHasErrorsIn('userDeletion', 'password') + ->assertRedirect('/profile'); + + $this->assertNotNull($user->fresh()); + } +} diff --git a/app/vite.config.js b/app/vite.config.js index f35b4e7..421b569 100644 --- a/app/vite.config.js +++ b/app/vite.config.js @@ -1,6 +1,5 @@ import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; -import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [ @@ -8,11 +7,5 @@ export default defineConfig({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), - tailwindcss(), ], - server: { - watch: { - ignored: ['**/storage/framework/views/**'], - }, - }, }); diff --git a/community-plan.md b/community-plan.md new file mode 100644 index 0000000..4339d30 --- /dev/null +++ b/community-plan.md @@ -0,0 +1,124 @@ +# Dewemoji Community Plan (Private‑First → Public Consensus) + +This plan matches the core purpose: **help people find emojis with their own words, in any language**, and let the community optionally promote keywords into global search. + +## Core principles + +- **Private first:** users can store any keyword for their own use. +- **Public by choice:** users can propose a keyword to the public pool. +- **Consensus‑based:** public keywords only become searchable after votes. +- **Language‑friendly:** keywords can be in any language/script (not only Latin). +- **Safety‑aware:** moderation applies only to public proposals (not private). + +## Current language reality + +- Today the dataset only includes **EN + ID** keywords for all emojis. +- Community should be designed to add **other languages** over time. + +## Two‑layer keyword model + +### 1) Private keywords (personal) +- Stored per user (or device if not logged in). +- Any term is allowed, even if not “correct.” +- Used only for that user’s search + recall. +- No moderation needed. +- Created and managed in the **user dashboard** (not on emoji detail pages). +- Must be **used locally first** before being eligible for public proposal. + +### 2) Public keywords (community) +- Users can propose **one of their own private keywords** to be public **from the dashboard**. +- Emoji detail pages only **display and vote** on public proposals; no direct proposal UI there. +- Once the proposal passes the threshold, it becomes globally searchable. + +## Public keyword lifecycle + +``` +private → public_pending → public +``` + +Suggested rules: +- **public_pending** shown publicly with vote controls. +- **public** if it reaches **≥ 5 upvotes** (your rule). +- Optional future: auto‑reject with heavy downvotes or time decay. + +## Voting model + +- 1 vote per user per keyword. +- Score = upvotes − downvotes. +- Promotion rule: **>= 5 upvotes** (simple and clear). +- Optional future: trust‑weighted votes. + +## Moderation model + +- Moderation applies only to **public proposals**. +- Private keywords are always allowed. +- Blocking rules: + - disallowed words + - mismatched emoji meaning + - language mismatch (optional) + +## UX flow (simple) + +1) User adds private keyword. +2) User uses it locally (personal search/recall). +3) User clicks “Make Public” from the dashboard. +4) Keyword appears on emoji detail page as pending. +4) Community votes. +5) Reaches 5 upvotes → becomes public search term. + +## API endpoints (clean, minimal set) + +Auth: +- `POST /v1/contrib/auth/request` +- `POST /v1/contrib/auth/verify` + +Keyword actions: +- `POST /v1/contrib/suggest` +- `POST /v1/contrib/make-public` +- `POST /v1/contrib/vote` +- `GET /v1/contrib/list?emoji=...` +- `GET /v1/contrib/search?q=...` + +Moderation: +- `GET /v1/keywords/pending` (admin/moderation) + +## Data model (minimum) + +- `emoji_keywords` (keyword, lang, status, visibility, owner_user_id) +- `keyword_votes` (keyword_id, user_id, vote) +- `moderation_events` +- `users` / `magic_links` + +## Optional recommendations (future‑safe) + +### A) Multilingual expansion +- Encourage new languages by highlighting “empty language slots.” +- Allow region variants (e.g., `en-US` vs `en-GB`). + +### B) Personal dictionary export +- Export private keywords per user. + +### C) Trust tiers +- Contributors with good history can fast‑track proposals. + +### D) Admin review console +- Moderators can approve/reject quickly. + +### E) Abuse prevention +- Rate limit public proposals + voting. +- Use Turnstile only for public actions. + +### F) Search blending +- Private keywords weighted highest for the owner. +- Public keywords weighted lower but global. + +### G) “My Words” UI +- Show user’s private keywords in the **dashboard**. +- One‑tap “Make Public” in the dashboard (not on detail page). + +## Recommended rollout + +1) Private keywords (local only). +2) Public proposals + votes (no AI). +3) Basic moderation + rate limits. +4) AI guard + trust tiers. diff --git a/deployment-notes/deployment-w4gkwgg4ccww8oc4s8w0soog-2026-02-04-14-34-56.txt b/deployment-notes/deployment-w4gkwgg4ccww8oc4s8w0soog-2026-02-04-14-34-56.txt new file mode 100644 index 0000000..993cc75 --- /dev/null +++ b/deployment-notes/deployment-w4gkwgg4ccww8oc4s8w0soog-2026-02-04-14-34-56.txt @@ -0,0 +1,2087 @@ +2026-Feb-04 14:27:08.924098 Starting deployment of Dewemoji to localhost. +2026-Feb-04 14:27:09.861274 Preparing container with helper image: ghcr.io/coollabsio/coolify-helper:1.0.12 +2026-Feb-04 14:27:10.350477 [CMD]: docker stop -t 30 w4gkwgg4ccww8oc4s8w0soog +2026-Feb-04 14:27:10.350477 Error response from daemon: No such container: w4gkwgg4ccww8oc4s8w0soog +2026-Feb-04 14:27:18.646668 [CMD]: docker run -d --network gkkgk00g44wscgk04ow4s808 --name w4gkwgg4ccww8oc4s8w0soog --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-helper:1.0.12 +2026-Feb-04 14:27:18.646668 af1c1aa9a3aac61bf00b8a353847b4dfefe334cdf7df01a384d10aa4c06d8ba6 +2026-Feb-04 14:27:20.662969 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'GIT_SSH_COMMAND="ssh -o ConnectTimeout=30 -p 22 -o Port=22 -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" git ls-remote https://git.backoffice.biz.id/dwindown/dewemoji.git refs/heads/main' +2026-Feb-04 14:27:20.662969 26e5da1b8dbeb3065ab56c09dd586329b30b9ba7 refs/heads/main +2026-Feb-04 14:27:20.681127 ---------------------------------------- +2026-Feb-04 14:27:20.690518 Importing https://git.backoffice.biz.id/dwindown/dewemoji.git:main (commit sha 26e5da1b8dbeb3065ab56c09dd586329b30b9ba7) to /artifacts/w4gkwgg4ccww8oc4s8w0soog. +2026-Feb-04 14:27:21.314142 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'git clone --depth=1 --recurse-submodules --shallow-submodules -b 'main' 'https://git.backoffice.biz.id/dwindown/dewemoji.git' '/artifacts/w4gkwgg4ccww8oc4s8w0soog' && cd '/artifacts/w4gkwgg4ccww8oc4s8w0soog' && if [ -f .gitmodules ]; then sed -i "s#git@\(.*\):#https://\1/#g" '/artifacts/w4gkwgg4ccww8oc4s8w0soog'/.gitmodules || true && git submodule sync && GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" git submodule update --init --recursive --depth=1; fi && cd '/artifacts/w4gkwgg4ccww8oc4s8w0soog' && GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" git lfs pull' +2026-Feb-04 14:27:21.314142 Cloning into '/artifacts/w4gkwgg4ccww8oc4s8w0soog'... +2026-Feb-04 14:27:24.464793 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'cd /artifacts/w4gkwgg4ccww8oc4s8w0soog && git log -1 26e5da1b8dbeb3065ab56c09dd586329b30b9ba7 --pretty=%B' +2026-Feb-04 14:27:24.464793 fix(deploy): make composer stage resilient in docker build +2026-Feb-04 14:27:25.186616 ---------------------------------------- +2026-Feb-04 14:27:25.207444 ⚠️ Build-time environment variable warning: APP_ENV=production +2026-Feb-04 14:27:25.223636 Affects: Laravel/Symfony +2026-Feb-04 14:27:25.236569 Issue: May affect dependency installation and build optimizations +2026-Feb-04 14:27:25.255510 Recommendation: Consider using "local" or "development" for build +2026-Feb-04 14:27:25.267114 +2026-Feb-04 14:27:25.279568 💡 Tips to resolve build issues: +2026-Feb-04 14:27:25.299866 1. Set these variables as "Runtime only" in the environment variables settings +2026-Feb-04 14:27:25.314814 2. Use different values for build-time (e.g., NODE_ENV=development for build) +2026-Feb-04 14:27:25.353283 3. Consider using multi-stage Docker builds to separate build and runtime environments +2026-Feb-04 14:27:29.112972 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'test -f /artifacts/w4gkwgg4ccww8oc4s8w0soog/app/Dockerfile && echo 'exists' || echo 'not found'' +2026-Feb-04 14:27:29.112972 exists +2026-Feb-04 14:27:29.677837 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'cat /artifacts/w4gkwgg4ccww8oc4s8w0soog/app/Dockerfile' +2026-Feb-04 14:27:29.677837 # syntax=docker/dockerfile:1.7 +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 FROM node:22-alpine AS frontend +2026-Feb-04 14:27:29.677837 WORKDIR /var/www/html +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 COPY package.json ./ +2026-Feb-04 14:27:29.677837 RUN npm install +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 COPY resources ./resources +2026-Feb-04 14:27:29.677837 COPY public ./public +2026-Feb-04 14:27:29.677837 COPY vite.config.js ./ +2026-Feb-04 14:27:29.677837 RUN npm run build +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 FROM composer:2 AS vendor +2026-Feb-04 14:27:29.677837 WORKDIR /var/www/html +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 COPY composer.json composer.lock ./ +2026-Feb-04 14:27:29.677837 RUN composer install \ +2026-Feb-04 14:27:29.677837 --no-dev \ +2026-Feb-04 14:27:29.677837 --no-interaction \ +2026-Feb-04 14:27:29.677837 --no-progress \ +2026-Feb-04 14:27:29.677837 --prefer-dist \ +2026-Feb-04 14:27:29.677837 --optimize-autoloader \ +2026-Feb-04 14:27:29.677837 --no-scripts \ +2026-Feb-04 14:27:29.677837 --ignore-platform-reqs +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 FROM php:8.2-apache +2026-Feb-04 14:27:29.677837 WORKDIR /var/www/html +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 RUN apt-get update && apt-get install -y \ +2026-Feb-04 14:27:29.677837 libzip-dev \ +2026-Feb-04 14:27:29.677837 libicu-dev \ +2026-Feb-04 14:27:29.677837 unzip \ +2026-Feb-04 14:27:29.677837 curl \ +2026-Feb-04 14:27:29.677837 default-mysql-client \ +2026-Feb-04 14:27:29.677837 && docker-php-ext-install pdo_mysql bcmath exif intl zip \ +2026-Feb-04 14:27:29.677837 && a2enmod rewrite headers expires \ +2026-Feb-04 14:27:29.677837 && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 COPY . . +2026-Feb-04 14:27:29.677837 COPY --from=vendor /var/www/html/vendor ./vendor +2026-Feb-04 14:27:29.677837 COPY --from=frontend /var/www/html/public/build ./public/build +2026-Feb-04 14:27:29.677837 COPY docker/apache-vhost.conf /etc/apache2/sites-available/000-default.conf +2026-Feb-04 14:27:29.677837 COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 RUN chmod +x /usr/local/bin/entrypoint.sh \ +2026-Feb-04 14:27:29.677837 && chown -R www-data:www-data storage bootstrap/cache \ +2026-Feb-04 14:27:29.677837 && chmod -R ug+rwx storage bootstrap/cache +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 EXPOSE 80 +2026-Feb-04 14:27:29.677837 +2026-Feb-04 14:27:29.677837 ENTRYPOINT ["entrypoint.sh"] +2026-Feb-04 14:27:29.677837 CMD ["apache2-foreground"] +2026-Feb-04 14:27:30.324025 Added 81 ARG declarations to Dockerfile for service app (multi-stage build, added to 3 stages). +2026-Feb-04 14:27:30.335938 Pulling & building required images. +2026-Feb-04 14:27:30.432707 Creating build-time .env file in /artifacts (outside Docker context). +2026-Feb-04 14:27:31.033845 Adding build arguments to Docker Compose build command. +2026-Feb-04 14:27:31.966946 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'COOLIFY_BRANCH=main COOLIFY_RESOURCE_UUID=p4w4csg8kcocs00s480w40cs docker compose --env-file /artifacts/build-time.env --project-name p4w4csg8kcocs00s480w40cs --project-directory /artifacts/w4gkwgg4ccww8oc4s8w0soog -f /artifacts/w4gkwgg4ccww8oc4s8w0soog/docker-compose.yml build --pull --build-arg COOLIFY_URL --build-arg COOLIFY_FQDN --build-arg APP_NAME --build-arg APP_ENV --build-arg APP_DEBUG --build-arg APP_URL --build-arg DB_DATABASE --build-arg DB_USERNAME --build-arg CACHE_STORE --build-arg QUEUE_CONNECTION --build-arg DEWEMOJI_BILLING_MODE --build-arg DEWEMOJI_GUMROAD_ENABLED --build-arg DEWEMOJI_GUMROAD_PRODUCT_IDS --build-arg DEWEMOJI_GUMROAD_TEST_KEYS --build-arg DEWEMOJI_MAYAR_ENABLED --build-arg DEWEMOJI_MAYAR_API_BASE --build-arg SESSION_DRIVER --build-arg DEWEMOJI_MAYAR_API_KEY --build-arg DEWEMOJI_MAYAR_SECRET_KEY --build-arg WAIT_FOR_DB --build-arg SERVICE_URL_APP --build-arg RUN_MIGRATIONS --build-arg DB_ROOT_PASSWORD --build-arg APP_KEY --build-arg SERVICE_FQDN_APP --build-arg DB_PASSWORD --build-arg DEWEMOJI_MAYAR_ENDPOINT_VERIFY --build-arg COOLIFY_BUILD_SECRETS_HASH=b42d944fe14fac01669c573f4231793c6682274480a853ae4ec287bd0f571e94' +2026-Feb-04 14:27:31.966946 #1 [internal] load local bake definitions +2026-Feb-04 14:27:32.118216 #1 reading from stdin 1.72kB done +2026-Feb-04 14:27:32.118216 #1 DONE 0.0s +2026-Feb-04 14:27:32.225035 #2 [internal] load build definition from Dockerfile +2026-Feb-04 14:27:32.225035 #2 transferring dockerfile: 2.98kB done +2026-Feb-04 14:27:32.225035 #2 DONE 0.1s +2026-Feb-04 14:27:32.385137 #3 resolve image config for docker-image://docker.io/docker/dockerfile:1.7 +2026-Feb-04 14:27:33.376189 #3 DONE 1.1s +2026-Feb-04 14:27:33.527962 #4 docker-image://docker.io/docker/dockerfile:1.7@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e +2026-Feb-04 14:27:33.527962 #4 CACHED +2026-Feb-04 14:27:33.557895 #5 [internal] load metadata for docker.io/library/composer:2 +2026-Feb-04 14:27:34.418854 #5 DONE 0.9s +2026-Feb-04 14:27:34.418854 +2026-Feb-04 14:27:34.418854 #6 [internal] load metadata for docker.io/library/node:22-alpine +2026-Feb-04 14:27:34.519762 #6 DONE 0.9s +2026-Feb-04 14:27:34.519762 +2026-Feb-04 14:27:34.519762 #7 [internal] load metadata for docker.io/library/php:8.2-apache +2026-Feb-04 14:27:34.519762 #7 DONE 0.9s +2026-Feb-04 14:27:34.720717 #8 [internal] load .dockerignore +2026-Feb-04 14:27:34.720717 #8 transferring context: 201B done +2026-Feb-04 14:27:34.720717 #8 DONE 0.1s +2026-Feb-04 14:27:34.844975 #9 [frontend 1/8] FROM docker.io/library/node:22-alpine@sha256:e4bf2a82ad0a4037d28035ae71529873c069b13eb0455466ae0bc13363826e34 +2026-Feb-04 14:27:34.844975 #9 DONE 0.0s +2026-Feb-04 14:27:34.844975 +2026-Feb-04 14:27:34.844975 #10 [stage-2 1/9] FROM docker.io/library/php:8.2-apache@sha256:bb72c1c7374fd5d5f3413cad7994854c03b54d121788c5c23771d5d08aaf0cc8 +2026-Feb-04 14:27:34.844975 #10 DONE 0.0s +2026-Feb-04 14:27:34.844975 +2026-Feb-04 14:27:34.844975 #11 [stage-2 2/9] WORKDIR /var/www/html +2026-Feb-04 14:27:34.844975 #11 CACHED +2026-Feb-04 14:27:34.844975 +2026-Feb-04 14:27:34.844975 #12 [vendor 1/4] FROM docker.io/library/composer:2@sha256:e4ff7e012505df43b4404cf73a4590e06a3f752a7f77d9079a89f770d257eb84 +2026-Feb-04 14:27:34.844975 #12 DONE 0.0s +2026-Feb-04 14:27:34.844975 +2026-Feb-04 14:27:34.844975 #13 [internal] load build context +2026-Feb-04 14:27:34.844975 #13 transferring context: 703.18kB 0.1s done +2026-Feb-04 14:27:35.067377 #13 DONE 0.2s +2026-Feb-04 14:27:35.067377 +2026-Feb-04 14:27:35.067377 #14 [frontend 2/8] WORKDIR /var/www/html +2026-Feb-04 14:27:35.067377 #14 CACHED +2026-Feb-04 14:27:35.067377 +2026-Feb-04 14:27:35.067377 #15 [frontend 3/8] COPY package.json ./ +2026-Feb-04 14:27:35.067377 #15 CACHED +2026-Feb-04 14:27:35.067377 +2026-Feb-04 14:27:35.067377 #16 [vendor 2/4] WORKDIR /var/www/html +2026-Feb-04 14:27:35.067377 #16 CACHED +2026-Feb-04 14:27:35.067377 +2026-Feb-04 14:27:35.067377 #17 [vendor 3/4] COPY composer.json composer.lock ./ +2026-Feb-04 14:27:35.067377 #17 CACHED +2026-Feb-04 14:27:35.067377 +2026-Feb-04 14:27:35.067377 #18 [vendor 4/4] RUN composer install --no-dev --no-interaction --no-progress --prefer-dist --optimize-autoloader --no-scripts --ignore-platform-reqs +2026-Feb-04 14:27:36.386901 #18 1.309 Installing dependencies from lock file +2026-Feb-04 14:27:36.386901 #18 1.317 Verifying lock file contents can be installed on current platform. +2026-Feb-04 14:27:36.386901 #18 1.349 Package operations: 76 installs, 0 updates, 0 removals +2026-Feb-04 14:27:36.386901 #18 1.352 - Downloading doctrine/inflector (2.1.0) +2026-Feb-04 14:27:36.386901 #18 1.354 - Downloading doctrine/lexer (3.0.1) +2026-Feb-04 14:27:36.386901 #18 1.355 - Downloading dragonmantank/cron-expression (v3.6.0) +2026-Feb-04 14:27:36.386901 #18 1.355 - Downloading symfony/polyfill-mbstring (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.356 - Downloading symfony/deprecation-contracts (v3.6.0) +2026-Feb-04 14:27:36.386901 #18 1.357 - Downloading symfony/http-foundation (v7.4.5) +2026-Feb-04 14:27:36.386901 #18 1.357 - Downloading fruitcake/php-cors (v1.4.0) +2026-Feb-04 14:27:36.386901 #18 1.358 - Downloading psr/http-message (2.0) +2026-Feb-04 14:27:36.386901 #18 1.359 - Downloading psr/http-client (1.0.3) +2026-Feb-04 14:27:36.386901 #18 1.360 - Downloading ralouphie/getallheaders (3.0.3) +2026-Feb-04 14:27:36.386901 #18 1.360 - Downloading psr/http-factory (1.1.0) +2026-Feb-04 14:27:36.386901 #18 1.361 - Downloading guzzlehttp/psr7 (2.8.0) +2026-Feb-04 14:27:36.386901 #18 1.362 - Downloading guzzlehttp/promises (2.3.0) +2026-Feb-04 14:27:36.386901 #18 1.362 - Downloading guzzlehttp/guzzle (7.10.0) +2026-Feb-04 14:27:36.386901 #18 1.363 - Downloading symfony/polyfill-php80 (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.363 - Downloading guzzlehttp/uri-template (v1.0.5) +2026-Feb-04 14:27:36.386901 #18 1.364 - Downloading symfony/polyfill-intl-normalizer (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.364 - Downloading symfony/polyfill-intl-grapheme (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.365 - Downloading symfony/polyfill-ctype (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.365 - Downloading symfony/string (v8.0.4) +2026-Feb-04 14:27:36.386901 #18 1.366 - Downloading psr/container (2.0.2) +2026-Feb-04 14:27:36.386901 #18 1.366 - Downloading symfony/service-contracts (v3.6.1) +2026-Feb-04 14:27:36.386901 #18 1.366 - Downloading symfony/console (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.367 - Downloading laravel/prompts (v0.3.11) +2026-Feb-04 14:27:36.386901 #18 1.367 - Downloading laravel/serializable-closure (v2.0.8) +2026-Feb-04 14:27:36.386901 #18 1.368 - Downloading symfony/var-dumper (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.368 - Downloading nikic/php-parser (v5.7.0) +2026-Feb-04 14:27:36.386901 #18 1.369 - Downloading psy/psysh (v0.12.19) +2026-Feb-04 14:27:36.386901 #18 1.369 - Downloading voku/portable-ascii (2.0.3) +2026-Feb-04 14:27:36.386901 #18 1.370 - Downloading phpoption/phpoption (1.9.5) +2026-Feb-04 14:27:36.386901 #18 1.370 - Downloading graham-campbell/result-type (v1.1.4) +2026-Feb-04 14:27:36.386901 #18 1.371 - Downloading vlucas/phpdotenv (v5.6.3) +2026-Feb-04 14:27:36.386901 #18 1.371 - Downloading symfony/css-selector (v8.0.0) +2026-Feb-04 14:27:36.386901 #18 1.372 - Downloading tijsverkoyen/css-to-inline-styles (v2.4.0) +2026-Feb-04 14:27:36.386901 #18 1.372 - Downloading symfony/polyfill-uuid (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.373 - Downloading symfony/uid (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.374 - Downloading symfony/routing (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.374 - Downloading symfony/process (v7.4.5) +2026-Feb-04 14:27:36.386901 #18 1.374 - Downloading symfony/polyfill-php85 (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.375 - Downloading symfony/polyfill-php84 (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.375 - Downloading symfony/polyfill-php83 (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.376 - Downloading symfony/polyfill-intl-idn (v1.33.0) +2026-Feb-04 14:27:36.386901 #18 1.376 - Downloading symfony/mime (v7.4.5) +2026-Feb-04 14:27:36.386901 #18 1.376 - Downloading psr/event-dispatcher (1.0.0) +2026-Feb-04 14:27:36.386901 #18 1.377 - Downloading symfony/event-dispatcher-contracts (v3.6.0) +2026-Feb-04 14:27:36.386901 #18 1.377 - Downloading symfony/event-dispatcher (v8.0.4) +2026-Feb-04 14:27:36.386901 #18 1.378 - Downloading psr/log (3.0.2) +2026-Feb-04 14:27:36.386901 #18 1.378 - Downloading egulias/email-validator (4.0.4) +2026-Feb-04 14:27:36.386901 #18 1.379 - Downloading symfony/mailer (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.379 - Downloading symfony/error-handler (v7.4.4) +2026-Feb-04 14:27:36.386901 #18 1.380 - Downloading symfony/http-kernel (v7.4.5) +2026-Feb-04 14:27:36.386901 #18 1.380 - Downloading symfony/finder (v7.4.5) +2026-Feb-04 14:27:36.386901 #18 1.380 - Downloading ramsey/collection (2.1.1) +2026-Feb-04 14:27:36.386901 #18 1.381 - Downloading brick/math (0.14.4) +2026-Feb-04 14:27:36.386901 #18 1.382 - Downloading ramsey/uuid (4.9.2) +2026-Feb-04 14:27:36.386901 #18 1.382 - Downloading psr/simple-cache (3.0.0) +2026-Feb-04 14:27:36.386901 #18 1.383 - Downloading nunomaduro/termwind (v2.3.3) +2026-Feb-04 14:27:36.386901 #18 1.383 - Downloading symfony/translation-contracts (v3.6.1) +2026-Feb-04 14:27:36.386901 #18 1.383 - Downloading symfony/translation (v8.0.4) +2026-Feb-04 14:27:36.386901 #18 1.384 - Downloading psr/clock (1.0.0) +2026-Feb-04 14:27:36.386901 #18 1.384 - Downloading symfony/clock (v8.0.0) +2026-Feb-04 14:27:36.386901 #18 1.385 - Downloading carbonphp/carbon-doctrine-types (3.2.0) +2026-Feb-04 14:27:36.386901 #18 1.386 - Downloading nesbot/carbon (3.11.1) +2026-Feb-04 14:27:36.386901 #18 1.386 - Downloading monolog/monolog (3.10.0) +2026-Feb-04 14:27:36.386901 #18 1.387 - Downloading league/uri-interfaces (7.8.0) +2026-Feb-04 14:27:36.386901 #18 1.388 - Downloading league/uri (7.8.0) +2026-Feb-04 14:27:36.386901 #18 1.389 - Downloading league/mime-type-detection (1.16.0) +2026-Feb-04 14:27:36.386901 #18 1.389 - Downloading league/flysystem-local (3.31.0) +2026-Feb-04 14:27:36.386901 #18 1.390 - Downloading league/flysystem (3.31.0) +2026-Feb-04 14:27:36.386901 #18 1.390 - Downloading nette/utils (v4.1.1) +2026-Feb-04 14:27:36.386901 #18 1.391 - Downloading nette/schema (v1.3.3) +2026-Feb-04 14:27:36.386901 #18 1.391 - Downloading dflydev/dot-access-data (v3.0.3) +2026-Feb-04 14:27:36.386901 #18 1.392 - Downloading league/config (v1.2.0) +2026-Feb-04 14:27:36.386901 #18 1.392 - Downloading league/commonmark (2.8.0) +2026-Feb-04 14:27:36.386901 #18 1.392 - Downloading laravel/framework (v12.49.0) +2026-Feb-04 14:27:36.386901 #18 1.393 - Downloading laravel/tinker (v2.11.0) +2026-Feb-04 14:27:43.715895 #18 8.801 - Installing doctrine/inflector (2.1.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.803 - Installing doctrine/lexer (3.0.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.806 - Installing dragonmantank/cron-expression (v3.6.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.808 - Installing symfony/polyfill-mbstring (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.812 - Installing symfony/deprecation-contracts (v3.6.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.817 - Installing symfony/http-foundation (v7.4.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.820 - Installing fruitcake/php-cors (v1.4.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.822 - Installing psr/http-message (2.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.824 - Installing psr/http-client (1.0.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.829 - Installing ralouphie/getallheaders (3.0.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing psr/http-factory (1.1.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing guzzlehttp/psr7 (2.8.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing guzzlehttp/promises (2.3.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing guzzlehttp/guzzle (7.10.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing symfony/polyfill-php80 (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing guzzlehttp/uri-template (v1.0.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.833 - Installing symfony/polyfill-intl-normalizer (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.834 - Installing symfony/polyfill-intl-grapheme (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.835 - Installing symfony/polyfill-ctype (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.836 - Installing symfony/string (v8.0.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.837 - Installing psr/container (2.0.2): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.838 - Installing symfony/service-contracts (v3.6.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.840 - Installing symfony/console (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.841 - Installing laravel/prompts (v0.3.11): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.842 - Installing laravel/serializable-closure (v2.0.8): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.843 - Installing symfony/var-dumper (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.843 - Installing nikic/php-parser (v5.7.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.844 - Installing psy/psysh (v0.12.19): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.845 - Installing voku/portable-ascii (2.0.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.846 - Installing phpoption/phpoption (1.9.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.846 - Installing graham-campbell/result-type (v1.1.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.847 - Installing vlucas/phpdotenv (v5.6.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.847 - Installing symfony/css-selector (v8.0.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.848 - Installing tijsverkoyen/css-to-inline-styles (v2.4.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.848 - Installing symfony/polyfill-uuid (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.849 - Installing symfony/uid (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.849 - Installing symfony/routing (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.850 - Installing symfony/process (v7.4.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.850 - Installing symfony/polyfill-php85 (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.851 - Installing symfony/polyfill-php84 (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.851 - Installing symfony/polyfill-php83 (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.852 - Installing symfony/polyfill-intl-idn (v1.33.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.852 - Installing symfony/mime (v7.4.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.852 - Installing psr/event-dispatcher (1.0.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.853 - Installing symfony/event-dispatcher-contracts (v3.6.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.853 - Installing symfony/event-dispatcher (v8.0.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.854 - Installing psr/log (3.0.2): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.854 - Installing egulias/email-validator (4.0.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.855 - Installing symfony/mailer (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.855 - Installing symfony/error-handler (v7.4.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.856 - Installing symfony/http-kernel (v7.4.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.856 - Installing symfony/finder (v7.4.5): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.857 - Installing ramsey/collection (2.1.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.857 - Installing brick/math (0.14.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.858 - Installing ramsey/uuid (4.9.2): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.858 - Installing psr/simple-cache (3.0.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.859 - Installing nunomaduro/termwind (v2.3.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.860 - Installing symfony/translation-contracts (v3.6.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.861 - Installing symfony/translation (v8.0.4): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.861 - Installing psr/clock (1.0.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.862 - Installing symfony/clock (v8.0.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.862 - Installing carbonphp/carbon-doctrine-types (3.2.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.863 - Installing nesbot/carbon (3.11.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.863 - Installing monolog/monolog (3.10.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.864 - Installing league/uri-interfaces (7.8.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.864 - Installing league/uri (7.8.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.865 - Installing league/mime-type-detection (1.16.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.865 - Installing league/flysystem-local (3.31.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.865 - Installing league/flysystem (3.31.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.866 - Installing nette/utils (v4.1.1): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.866 - Installing nette/schema (v1.3.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.867 - Installing dflydev/dot-access-data (v3.0.3): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.867 - Installing league/config (v1.2.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.868 - Installing league/commonmark (2.8.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.868 - Installing laravel/framework (v12.49.0): Extracting archive +2026-Feb-04 14:27:43.882396 #18 8.869 - Installing laravel/tinker (v2.11.0): Extracting archive +2026-Feb-04 14:27:44.857683 #18 ... +2026-Feb-04 14:27:44.857683 +2026-Feb-04 14:27:44.857683 #19 [stage-2 3/9] RUN apt-get update && apt-get install -y libzip-dev libicu-dev unzip curl default-mysql-client && docker-php-ext-install pdo_mysql bcmath exif intl zip && a2enmod rewrite headers expires && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:27:44.857683 #19 1.497 Hit:1 http://deb.debian.org/debian trixie InRelease +2026-Feb-04 14:27:44.857683 #19 1.658 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB] +2026-Feb-04 14:27:44.857683 #19 2.010 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB] +2026-Feb-04 14:27:44.857683 #19 2.234 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9670 kB] +2026-Feb-04 14:27:44.857683 #19 3.413 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [5412 B] +2026-Feb-04 14:27:44.857683 #19 3.594 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [98.8 kB] +2026-Feb-04 14:27:44.857683 #19 4.841 Fetched 9865 kB in 4s (2371 kB/s) +2026-Feb-04 14:27:44.857683 #19 4.841 Reading package lists... +2026-Feb-04 14:27:44.857683 #19 6.002 Reading package lists... +2026-Feb-04 14:27:44.857683 #19 7.214 Building dependency tree... +2026-Feb-04 14:27:44.857683 #19 7.485 Reading state information... +2026-Feb-04 14:27:44.857683 #19 7.874 curl is already the newest version (8.14.1-2+deb13u2). +2026-Feb-04 14:27:44.857683 #19 7.874 The following additional packages will be installed: +2026-Feb-04 14:27:44.857683 #19 7.874 icu-devtools libconfig-inifiles-perl libdbd-mariadb-perl libdbi-perl +2026-Feb-04 14:27:44.857683 #19 7.875 libedit2 libgpm2 libicu76 libmariadb3 libncurses6 libpcre2-posix3 +2026-Feb-04 14:27:44.857683 #19 7.875 libterm-readkey-perl liburing2 libzip5 mariadb-client mariadb-client-compat +2026-Feb-04 14:27:44.857683 #19 7.876 mariadb-client-core mariadb-common mysql-common zipcmp zipmerge ziptool +2026-Feb-04 14:27:44.857683 #19 7.876 zlib1g-dev +2026-Feb-04 14:27:44.857683 #19 7.877 Suggested packages: +2026-Feb-04 14:27:44.857683 #19 7.877 libclone-perl libmldbm-perl libnet-daemon-perl libsql-statement-perl gpm +2026-Feb-04 14:27:44.857683 #19 7.877 icu-doc zip +2026-Feb-04 14:27:44.857683 #19 8.160 The following NEW packages will be installed: +2026-Feb-04 14:27:44.857683 #19 8.161 default-mysql-client icu-devtools libconfig-inifiles-perl +2026-Feb-04 14:27:44.857683 #19 8.161 libdbd-mariadb-perl libdbi-perl libedit2 libgpm2 libicu-dev libicu76 +2026-Feb-04 14:27:44.857683 #19 8.162 libmariadb3 libncurses6 libpcre2-posix3 libterm-readkey-perl liburing2 +2026-Feb-04 14:27:44.857683 #19 8.162 libzip-dev libzip5 mariadb-client mariadb-client-compat mariadb-client-core +2026-Feb-04 14:27:44.857683 #19 8.162 mariadb-common mysql-common unzip zipcmp zipmerge ziptool zlib1g-dev +2026-Feb-04 14:27:44.857683 #19 8.798 0 upgraded, 26 newly installed, 0 to remove and 0 not upgraded. +2026-Feb-04 14:27:44.857683 #19 8.798 Need to get 27.8 MB of archives. +2026-Feb-04 14:27:44.857683 #19 8.798 After this operation, 179 MB of additional disk space will be used. +2026-Feb-04 14:27:44.857683 #19 8.798 Get:1 http://deb.debian.org/debian trixie/main amd64 libconfig-inifiles-perl all 3.000003-3 [44.8 kB] +2026-Feb-04 14:27:44.857683 #19 9.163 Get:2 http://deb.debian.org/debian trixie/main amd64 mysql-common all 5.8+1.1.1 [6784 B] +2026-Feb-04 14:27:44.857683 #19 9.396 Get:3 http://deb.debian.org/debian trixie/main amd64 mariadb-common all 1:11.8.3-0+deb13u1 [28.8 kB] +2026-Feb-04 14:27:44.857683 #19 9.576 Get:4 http://deb.debian.org/debian trixie/main amd64 libmariadb3 amd64 1:11.8.3-0+deb13u1 [187 kB] +2026-Feb-04 14:27:44.857683 #19 9.985 Get:5 http://deb.debian.org/debian trixie/main amd64 libedit2 amd64 3.1-20250104-1 [93.8 kB] +2026-Feb-04 14:27:44.891553 #19 10.17 Get:6 http://deb.debian.org/debian trixie/main amd64 libncurses6 amd64 6.5+20250216-2 [105 kB] +2026-Feb-04 14:27:45.039021 #19 ... +2026-Feb-04 14:27:45.039021 +2026-Feb-04 14:27:45.039021 #20 [frontend 4/8] RUN npm install +2026-Feb-04 14:27:45.072896 #20 ... +2026-Feb-04 14:27:45.072896 +2026-Feb-04 14:27:45.072896 #19 [stage-2 3/9] RUN apt-get update && apt-get install -y libzip-dev libicu-dev unzip curl default-mysql-client && docker-php-ext-install pdo_mysql bcmath exif intl zip && a2enmod rewrite headers expires && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:27:45.072896 #19 10.35 Get:7 http://deb.debian.org/debian trixie/main amd64 mariadb-client-core amd64 1:11.8.3-0+deb13u1 [919 kB] +2026-Feb-04 14:27:46.067550 #19 11.34 Get:8 http://deb.debian.org/debian trixie/main amd64 libpcre2-posix3 amd64 10.46-1~deb13u1 [63.9 kB] +2026-Feb-04 14:27:46.250588 #19 11.53 Get:9 http://deb.debian.org/debian trixie/main amd64 liburing2 amd64 2.9-1 [26.4 kB] +2026-Feb-04 14:27:46.436196 #19 11.72 Get:10 http://deb.debian.org/debian trixie/main amd64 mariadb-client amd64 1:11.8.3-0+deb13u1 [3160 kB] +2026-Feb-04 14:27:48.812977 #19 14.09 Get:11 http://deb.debian.org/debian trixie/main amd64 mariadb-client-compat all 1:11.8.3-0+deb13u1 [28.9 kB] +2026-Feb-04 14:27:48.812977 #19 14.09 Get:12 http://deb.debian.org/debian trixie/main amd64 default-mysql-client all 1.1.1 [3028 B] +2026-Feb-04 14:27:48.988501 #19 ... +2026-Feb-04 14:27:48.988501 +2026-Feb-04 14:27:48.988501 #20 [frontend 4/8] RUN npm install +2026-Feb-04 14:27:48.988501 #20 12.96 +2026-Feb-04 14:27:48.988501 #20 12.96 added 82 packages, and audited 83 packages in 12s +2026-Feb-04 14:27:48.988501 #20 12.96 +2026-Feb-04 14:27:48.988501 #20 12.96 21 packages are looking for funding +2026-Feb-04 14:27:48.988501 #20 12.96 run `npm fund` for details +2026-Feb-04 14:27:48.988501 #20 12.96 +2026-Feb-04 14:27:48.988501 #20 12.96 found 0 vulnerabilities +2026-Feb-04 14:27:48.988501 #20 12.97 npm notice +2026-Feb-04 14:27:48.988501 #20 12.97 npm notice New major version of npm available! 10.9.4 -> 11.8.0 +2026-Feb-04 14:27:48.988501 #20 12.97 npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.8.0 +2026-Feb-04 14:27:48.988501 #20 12.97 npm notice To update run: npm install -g npm@11.8.0 +2026-Feb-04 14:27:48.988501 #20 12.97 npm notice +2026-Feb-04 14:27:48.988501 #20 DONE 13.9s +2026-Feb-04 14:27:48.988501 +2026-Feb-04 14:27:48.988501 #18 [vendor 4/4] RUN composer install --no-dev --no-interaction --no-progress --prefer-dist --optimize-autoloader --no-scripts --ignore-platform-reqs +2026-Feb-04 14:27:48.988501 #18 11.70 Generating optimized autoload files +2026-Feb-04 14:27:48.988501 #18 13.52 53 packages you are using are looking for funding. +2026-Feb-04 14:27:48.988501 #18 13.52 Use the `composer fund` command to find out more! +2026-Feb-04 14:27:48.988501 #18 DONE 13.9s +2026-Feb-04 14:27:48.988501 +2026-Feb-04 14:27:48.988501 #19 [stage-2 3/9] RUN apt-get update && apt-get install -y libzip-dev libicu-dev unzip curl default-mysql-client && docker-php-ext-install pdo_mysql bcmath exif intl zip && a2enmod rewrite headers expires && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:27:48.988501 #19 14.27 Get:13 http://deb.debian.org/debian trixie/main amd64 libicu76 amd64 76.1-4 [9722 kB] +2026-Feb-04 14:27:49.161911 #19 ... +2026-Feb-04 14:27:49.161911 +2026-Feb-04 14:27:49.161911 #21 [frontend 5/8] COPY resources ./resources +2026-Feb-04 14:27:49.161911 #21 DONE 0.2s +2026-Feb-04 14:27:49.194752 #22 [frontend 6/8] COPY public ./public +2026-Feb-04 14:27:49.194752 #22 DONE 0.2s +2026-Feb-04 14:27:49.194752 +2026-Feb-04 14:27:49.194752 #19 [stage-2 3/9] RUN apt-get update && apt-get install -y libzip-dev libicu-dev unzip curl default-mysql-client && docker-php-ext-install pdo_mysql bcmath exif intl zip && a2enmod rewrite headers expires && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:27:49.379691 #19 ... +2026-Feb-04 14:27:49.379691 +2026-Feb-04 14:27:49.379691 #23 [frontend 7/8] COPY vite.config.js ./ +2026-Feb-04 14:27:49.379691 #23 DONE 0.2s +2026-Feb-04 14:27:49.551332 #24 [frontend 8/8] RUN npm run build +2026-Feb-04 14:27:50.159881 #24 0.765 +2026-Feb-04 14:27:50.159881 #24 0.765 > build +2026-Feb-04 14:27:50.159881 #24 0.765 > vite build +2026-Feb-04 14:27:50.159881 #24 0.765 +2026-Feb-04 14:27:51.012685 #24 1.617 vite v7.3.1 building client environment for production... +2026-Feb-04 14:27:51.149015 #24 1.754 transforming... +2026-Feb-04 14:27:52.029233 #24 2.630 ✓ 53 modules transformed. +2026-Feb-04 14:27:52.146761 #24 2.752 rendering chunks... +2026-Feb-04 14:27:52.308337 #24 2.766 computing gzip size... +2026-Feb-04 14:27:52.308337 #24 2.772 public/build/manifest.json 0.33 kB │ gzip: 0.17 kB +2026-Feb-04 14:27:52.308337 #24 2.772 public/build/assets/app-CZuyDrlV.css 50.21 kB │ gzip: 10.63 kB +2026-Feb-04 14:27:52.308337 #24 2.772 public/build/assets/app-DIuewKhF.js 36.30 kB │ gzip: 14.65 kB +2026-Feb-04 14:27:52.308337 #24 2.773 ✓ built in 1.07s +2026-Feb-04 14:27:52.308337 #24 DONE 2.9s +2026-Feb-04 14:27:52.308337 +2026-Feb-04 14:27:52.308337 #19 [stage-2 3/9] RUN apt-get update && apt-get install -y libzip-dev libicu-dev unzip curl default-mysql-client && docker-php-ext-install pdo_mysql bcmath exif intl zip && a2enmod rewrite headers expires && rm -rf /var/lib/apt/lists/* +2026-Feb-04 14:28:54.380103 #19 79.66 Get:14 http://deb.debian.org/debian trixie/main amd64 icu-devtools amd64 76.1-4 [215 kB] +2026-Feb-04 14:28:54.950035 #19 80.23 Get:15 http://deb.debian.org/debian trixie/main amd64 libdbi-perl amd64 1.647-1 [861 kB] +2026-Feb-04 14:28:57.875305 #19 83.16 Get:16 http://deb.debian.org/debian trixie/main amd64 libdbd-mariadb-perl amd64 1.22-1+b4 [93.6 kB] +2026-Feb-04 14:28:58.330819 #19 83.61 Get:17 http://deb.debian.org/debian trixie/main amd64 libgpm2 amd64 1.20.7-11+b2 [14.4 kB] +2026-Feb-04 14:28:58.563712 #19 83.69 Get:18 http://deb.debian.org/debian trixie/main amd64 libicu-dev amd64 76.1-4 [10.8 MB] +2026-Feb-04 14:31:01.078825 #19 206.4 Get:19 http://deb.debian.org/debian trixie/main amd64 libterm-readkey-perl amd64 2.38-2+b4 [24.6 kB] +2026-Feb-04 14:31:01.458245 #19 206.7 Get:20 http://deb.debian.org/debian trixie/main amd64 libzip5 amd64 1.11.3-2 [62.6 kB] +2026-Feb-04 14:31:01.817203 #19 207.1 Get:21 http://deb.debian.org/debian trixie/main amd64 zipcmp amd64 1.11.3-2 [19.8 kB] +2026-Feb-04 14:31:02.057299 #19 207.2 Get:22 http://deb.debian.org/debian trixie/main amd64 zipmerge amd64 1.11.3-2 [14.5 kB] +2026-Feb-04 14:31:02.183082 #19 207.5 Get:23 http://deb.debian.org/debian trixie/main amd64 ziptool amd64 1.11.3-2 [22.6 kB] +2026-Feb-04 14:31:02.363240 #19 207.6 Get:24 http://deb.debian.org/debian trixie/main amd64 zlib1g-dev amd64 1:1.3.dfsg+really1.3.1-1+b1 [920 kB] +2026-Feb-04 14:31:06.278986 #19 211.6 Get:25 http://deb.debian.org/debian trixie/main amd64 libzip-dev amd64 1.11.3-2 [181 kB] +2026-Feb-04 14:31:07.278167 #19 212.6 Get:26 http://deb.debian.org/debian trixie/main amd64 unzip amd64 6.0-29 [173 kB] +2026-Feb-04 14:31:08.483552 #19 213.8 debconf: unable to initialize frontend: Dialog +2026-Feb-04 14:31:08.483552 #19 213.8 debconf: (TERM is not set, so the dialog frontend is not usable.) +2026-Feb-04 14:31:08.483552 #19 213.8 debconf: falling back to frontend: Readline +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: unable to initialize frontend: Readline +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: (This frontend requires a controlling tty.) +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: falling back to frontend: Teletype +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: unable to initialize frontend: Teletype +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: (This frontend requires a controlling tty.) +2026-Feb-04 14:31:08.655148 #19 213.8 debconf: falling back to frontend: Noninteractive +2026-Feb-04 14:31:09.615871 #19 214.9 Fetched 27.8 MB in 3min 25s (135 kB/s) +2026-Feb-04 14:31:09.727469 #19 215.0 Selecting previously unselected package libconfig-inifiles-perl. +2026-Feb-04 14:31:09.727469 #19 215.0 (Reading database ... (Reading database ... 5% (Reading database ... 10% (Reading database ... 15% (Reading database ... 20% (Reading database ... 25% (Reading database ... 30% (Reading database ... 35% (Reading database ... 40% (Reading database ... 45% (Reading database ... 50% (Reading database ... 55% (Reading database ... 60% (Reading database ... 65% (Reading database ... 70% (Reading database ... 75% (Reading database ... 80% (Reading database ... 85% (Reading database ... 90% (Reading database ... 95% (Reading database ... 100% (Reading database ... 15584 files and directories currently installed.) +2026-Feb-04 14:31:09.727469 #19 215.0 Preparing to unpack .../00-libconfig-inifiles-perl_3.000003-3_all.deb ... +2026-Feb-04 14:31:09.887427 #19 215.0 Unpacking libconfig-inifiles-perl (3.000003-3) ... +2026-Feb-04 14:31:09.906411 #19 215.2 Selecting previously unselected package mysql-common. +2026-Feb-04 14:31:10.059782 #19 215.2 Preparing to unpack .../01-mysql-common_5.8+1.1.1_all.deb ... +2026-Feb-04 14:31:10.059782 #19 215.2 Unpacking mysql-common (5.8+1.1.1) ... +2026-Feb-04 14:31:10.059782 #19 215.3 Selecting previously unselected package mariadb-common. +2026-Feb-04 14:31:10.191953 #19 215.3 Preparing to unpack .../02-mariadb-common_1%3a11.8.3-0+deb13u1_all.deb ... +2026-Feb-04 14:31:10.191953 #19 215.4 Unpacking mariadb-common (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:10.191953 #19 215.5 Selecting previously unselected package libmariadb3:amd64. +2026-Feb-04 14:31:10.350688 #19 215.5 Preparing to unpack .../03-libmariadb3_1%3a11.8.3-0+deb13u1_amd64.deb ... +2026-Feb-04 14:31:10.350688 #19 215.5 Unpacking libmariadb3:amd64 (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:10.350688 #19 215.6 Selecting previously unselected package libedit2:amd64. +2026-Feb-04 14:31:10.461353 #19 215.6 Preparing to unpack .../04-libedit2_3.1-20250104-1_amd64.deb ... +2026-Feb-04 14:31:10.461353 #19 215.6 Unpacking libedit2:amd64 (3.1-20250104-1) ... +2026-Feb-04 14:31:10.461353 #19 215.7 Selecting previously unselected package libncurses6:amd64. +2026-Feb-04 14:31:10.575112 #19 215.7 Preparing to unpack .../05-libncurses6_6.5+20250216-2_amd64.deb ... +2026-Feb-04 14:31:10.575112 #19 215.8 Unpacking libncurses6:amd64 (6.5+20250216-2) ... +2026-Feb-04 14:31:10.575112 #19 215.9 Selecting previously unselected package mariadb-client-core. +2026-Feb-04 14:31:10.737308 #19 215.9 Preparing to unpack .../06-mariadb-client-core_1%3a11.8.3-0+deb13u1_amd64.deb ... +2026-Feb-04 14:31:10.737308 #19 215.9 Unpacking mariadb-client-core (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:10.808551 #19 216.1 Selecting previously unselected package libpcre2-posix3:amd64. +2026-Feb-04 14:31:10.916478 #19 216.1 Preparing to unpack .../07-libpcre2-posix3_10.46-1~deb13u1_amd64.deb ... +2026-Feb-04 14:31:10.916478 #19 216.1 Unpacking libpcre2-posix3:amd64 (10.46-1~deb13u1) ... +2026-Feb-04 14:31:10.916478 #19 216.2 Selecting previously unselected package liburing2:amd64. +2026-Feb-04 14:31:11.037808 #19 216.2 Preparing to unpack .../08-liburing2_2.9-1_amd64.deb ... +2026-Feb-04 14:31:11.037808 #19 216.2 Unpacking liburing2:amd64 (2.9-1) ... +2026-Feb-04 14:31:11.037808 #19 216.3 Selecting previously unselected package mariadb-client. +2026-Feb-04 14:31:11.211923 #19 216.3 Preparing to unpack .../09-mariadb-client_1%3a11.8.3-0+deb13u1_amd64.deb ... +2026-Feb-04 14:31:11.211923 #19 216.3 Unpacking mariadb-client (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:11.486666 #19 216.8 Selecting previously unselected package mariadb-client-compat. +2026-Feb-04 14:31:11.611450 #19 216.8 Preparing to unpack .../10-mariadb-client-compat_1%3a11.8.3-0+deb13u1_all.deb ... +2026-Feb-04 14:31:11.611450 #19 216.8 Unpacking mariadb-client-compat (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:11.611450 #19 216.9 Selecting previously unselected package default-mysql-client. +2026-Feb-04 14:31:11.754868 #19 216.9 Preparing to unpack .../11-default-mysql-client_1.1.1_all.deb ... +2026-Feb-04 14:31:11.754868 #19 216.9 Unpacking default-mysql-client (1.1.1) ... +2026-Feb-04 14:31:11.754868 #19 217.0 Selecting previously unselected package libicu76:amd64. +2026-Feb-04 14:31:11.936838 #19 217.0 Preparing to unpack .../12-libicu76_76.1-4_amd64.deb ... +2026-Feb-04 14:31:11.936838 #19 217.1 Unpacking libicu76:amd64 (76.1-4) ... +2026-Feb-04 14:31:12.450447 #19 217.7 Selecting previously unselected package icu-devtools. +2026-Feb-04 14:31:12.558285 #19 217.7 Preparing to unpack .../13-icu-devtools_76.1-4_amd64.deb ... +2026-Feb-04 14:31:12.558285 #19 217.7 Unpacking icu-devtools (76.1-4) ... +2026-Feb-04 14:31:12.558285 #19 217.8 Selecting previously unselected package libdbi-perl:amd64. +2026-Feb-04 14:31:12.699634 #19 217.8 Preparing to unpack .../14-libdbi-perl_1.647-1_amd64.deb ... +2026-Feb-04 14:31:12.699634 #19 217.9 Unpacking libdbi-perl:amd64 (1.647-1) ... +2026-Feb-04 14:31:12.699634 #19 218.0 Selecting previously unselected package libdbd-mariadb-perl. +2026-Feb-04 14:31:12.811315 #19 218.0 Preparing to unpack .../15-libdbd-mariadb-perl_1.22-1+b4_amd64.deb ... +2026-Feb-04 14:31:12.811315 #19 218.0 Unpacking libdbd-mariadb-perl (1.22-1+b4) ... +2026-Feb-04 14:31:12.811315 #19 218.1 Selecting previously unselected package libgpm2:amd64. +2026-Feb-04 14:31:12.920686 #19 218.1 Preparing to unpack .../16-libgpm2_1.20.7-11+b2_amd64.deb ... +2026-Feb-04 14:31:12.920686 #19 218.1 Unpacking libgpm2:amd64 (1.20.7-11+b2) ... +2026-Feb-04 14:31:12.920686 #19 218.2 Selecting previously unselected package libicu-dev:amd64. +2026-Feb-04 14:31:12.920686 #19 218.2 Preparing to unpack .../17-libicu-dev_76.1-4_amd64.deb ... +2026-Feb-04 14:31:12.920686 #19 218.2 Unpacking libicu-dev:amd64 (76.1-4) ... +2026-Feb-04 14:31:13.610837 #19 218.9 Selecting previously unselected package libterm-readkey-perl. +2026-Feb-04 14:31:13.726615 #19 218.9 Preparing to unpack .../18-libterm-readkey-perl_2.38-2+b4_amd64.deb ... +2026-Feb-04 14:31:13.726615 #19 218.9 Unpacking libterm-readkey-perl (2.38-2+b4) ... +2026-Feb-04 14:31:13.726615 #19 219.0 Selecting previously unselected package libzip5:amd64. +2026-Feb-04 14:31:13.829157 #19 219.0 Preparing to unpack .../19-libzip5_1.11.3-2_amd64.deb ... +2026-Feb-04 14:31:13.829157 #19 219.0 Unpacking libzip5:amd64 (1.11.3-2) ... +2026-Feb-04 14:31:13.829157 #19 219.1 Selecting previously unselected package zipcmp. +2026-Feb-04 14:31:13.941655 #19 219.1 Preparing to unpack .../20-zipcmp_1.11.3-2_amd64.deb ... +2026-Feb-04 14:31:13.941655 #19 219.1 Unpacking zipcmp (1.11.3-2) ... +2026-Feb-04 14:31:13.941655 #19 219.2 Selecting previously unselected package zipmerge. +2026-Feb-04 14:31:13.941655 #19 219.2 Preparing to unpack .../21-zipmerge_1.11.3-2_amd64.deb ... +2026-Feb-04 14:31:13.941655 #19 219.2 Unpacking zipmerge (1.11.3-2) ... +2026-Feb-04 14:31:14.129067 #19 219.3 Selecting previously unselected package ziptool. +2026-Feb-04 14:31:14.129067 #19 219.3 Preparing to unpack .../22-ziptool_1.11.3-2_amd64.deb ... +2026-Feb-04 14:31:14.129067 #19 219.3 Unpacking ziptool (1.11.3-2) ... +2026-Feb-04 14:31:14.129067 #19 219.4 Selecting previously unselected package zlib1g-dev:amd64. +2026-Feb-04 14:31:14.244085 #19 219.4 Preparing to unpack .../23-zlib1g-dev_1%3a1.3.dfsg+really1.3.1-1+b1_amd64.deb ... +2026-Feb-04 14:31:14.244085 #19 219.4 Unpacking zlib1g-dev:amd64 (1:1.3.dfsg+really1.3.1-1+b1) ... +2026-Feb-04 14:31:14.244085 #19 219.5 Selecting previously unselected package libzip-dev:amd64. +2026-Feb-04 14:31:14.383762 #19 219.5 Preparing to unpack .../24-libzip-dev_1.11.3-2_amd64.deb ... +2026-Feb-04 14:31:14.383762 #19 219.5 Unpacking libzip-dev:amd64 (1.11.3-2) ... +2026-Feb-04 14:31:14.383762 #19 219.7 Selecting previously unselected package unzip. +2026-Feb-04 14:31:14.502515 #19 219.7 Preparing to unpack .../25-unzip_6.0-29_amd64.deb ... +2026-Feb-04 14:31:14.502515 #19 219.7 Unpacking unzip (6.0-29) ... +2026-Feb-04 14:31:14.502515 #19 219.8 Setting up libconfig-inifiles-perl (3.000003-3) ... +2026-Feb-04 14:31:14.615421 #19 219.8 Setting up mysql-common (5.8+1.1.1) ... +2026-Feb-04 14:31:14.615421 #19 219.9 update-alternatives: using /etc/mysql/my.cnf.fallback to provide /etc/mysql/my.cnf (my.cnf) in auto mode +2026-Feb-04 14:31:14.715829 #19 219.9 Setting up libgpm2:amd64 (1.20.7-11+b2) ... +2026-Feb-04 14:31:14.715829 #19 220.0 Setting up libzip5:amd64 (1.11.3-2) ... +2026-Feb-04 14:31:14.715829 #19 220.0 Setting up unzip (6.0-29) ... +2026-Feb-04 14:31:14.824056 #19 220.0 Setting up libedit2:amd64 (3.1-20250104-1) ... +2026-Feb-04 14:31:14.824056 #19 220.1 Setting up zipmerge (1.11.3-2) ... +2026-Feb-04 14:31:14.824056 #19 220.1 Setting up mariadb-common (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:14.957021 #19 220.1 update-alternatives: using /etc/mysql/mariadb.cnf to provide /etc/mysql/my.cnf (my.cnf) in auto mode +2026-Feb-04 14:31:14.957021 #19 220.2 Setting up libncurses6:amd64 (6.5+20250216-2) ... +2026-Feb-04 14:31:14.957021 #19 220.2 Setting up libmariadb3:amd64 (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:14.957021 #19 220.2 Setting up zlib1g-dev:amd64 (1:1.3.dfsg+really1.3.1-1+b1) ... +2026-Feb-04 14:31:15.066094 #19 220.3 Setting up libpcre2-posix3:amd64 (10.46-1~deb13u1) ... +2026-Feb-04 14:31:15.066094 #19 220.3 Setting up zipcmp (1.11.3-2) ... +2026-Feb-04 14:31:15.193047 #19 220.4 Setting up libicu76:amd64 (76.1-4) ... +2026-Feb-04 14:31:15.193047 #19 220.4 Setting up libterm-readkey-perl (2.38-2+b4) ... +2026-Feb-04 14:31:15.193047 #19 220.4 Setting up liburing2:amd64 (2.9-1) ... +2026-Feb-04 14:31:15.193047 #19 220.5 Setting up ziptool (1.11.3-2) ... +2026-Feb-04 14:31:15.336668 #19 220.5 Setting up libdbi-perl:amd64 (1.647-1) ... +2026-Feb-04 14:31:15.336668 #19 220.6 Setting up libzip-dev:amd64 (1.11.3-2) ... +2026-Feb-04 14:31:15.446633 #19 220.7 Setting up mariadb-client-core (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:15.446633 #19 220.7 Setting up libdbd-mariadb-perl (1.22-1+b4) ... +2026-Feb-04 14:31:15.446633 #19 220.7 Setting up icu-devtools (76.1-4) ... +2026-Feb-04 14:31:15.583909 #19 220.8 Setting up libicu-dev:amd64 (76.1-4) ... +2026-Feb-04 14:31:15.583909 #19 220.8 Setting up mariadb-client (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:15.583909 #19 220.9 Setting up mariadb-client-compat (1:11.8.3-0+deb13u1) ... +2026-Feb-04 14:31:15.801593 #19 220.9 Setting up default-mysql-client (1.1.1) ... +2026-Feb-04 14:31:15.801593 #19 220.9 Processing triggers for libc-bin (2.41-12+deb13u1) ... +2026-Feb-04 14:31:19.437935 #19 224.7 Configuring for: +2026-Feb-04 14:31:19.437935 #19 224.7 PHP Api Version: 20220829 +2026-Feb-04 14:31:19.437935 #19 224.7 Zend Module Api No: 20220829 +2026-Feb-04 14:31:19.437935 #19 224.7 Zend Extension Api No: 420220829 +2026-Feb-04 14:31:20.706188 #19 226.0 checking for grep that handles long lines and -e... +2026-Feb-04 14:31:20.829134 /usr/bin/grep +2026-Feb-04 14:31:20.829134 #19 226.0 checking for egrep... /usr/bin/grep -E +2026-Feb-04 14:31:20.829134 #19 226.0 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:20.829134 #19 226.0 checking for pkg-config... /usr/bin/pkg-config +2026-Feb-04 14:31:20.829134 #19 226.0 checking pkg-config is at least version 0.9.0... yes +2026-Feb-04 14:31:20.829134 #19 226.1 checking for cc... cc +2026-Feb-04 14:31:20.829134 #19 226.1 checking whether the C compiler works... +2026-Feb-04 14:31:20.981359 yes +2026-Feb-04 14:31:20.981359 #19 226.2 checking for C compiler default output file name... a.out +2026-Feb-04 14:31:20.981359 #19 226.2 checking for suffix of executables... +2026-Feb-04 14:31:21.095929 #19 226.3 checking whether we are cross compiling... no +2026-Feb-04 14:31:21.095929 #19 226.3 checking for suffix of object files... o +2026-Feb-04 14:31:21.095929 #19 226.4 checking whether the compiler supports GNU C... +2026-Feb-04 14:31:21.256220 yes +2026-Feb-04 14:31:21.256220 #19 226.4 checking whether cc accepts -g... yes +2026-Feb-04 14:31:21.256220 #19 226.4 checking for cc option to enable C11 features... none needed +2026-Feb-04 14:31:21.367712 #19 226.5 checking how to run the C preprocessor... cc -E +2026-Feb-04 14:31:21.367712 #19 226.6 checking for egrep -e... +2026-Feb-04 14:31:21.479796 (cached) /usr/bin/grep -E +2026-Feb-04 14:31:21.479796 #19 226.6 checking for icc... no +2026-Feb-04 14:31:21.479796 #19 226.7 checking for suncc... no +2026-Feb-04 14:31:21.479796 #19 226.7 checking for system library directory... lib +2026-Feb-04 14:31:21.479796 #19 226.7 checking if compiler supports -Wl,-rpath,... yes +2026-Feb-04 14:31:21.580506 #19 226.8 checking build system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:21.580506 #19 226.8 checking host system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:21.580506 #19 226.8 checking target system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:21.580506 #19 226.9 checking for PHP prefix... /usr/local +2026-Feb-04 14:31:21.580506 #19 226.9 checking for PHP includes... -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib +2026-Feb-04 14:31:21.684719 #19 226.9 checking for PHP extension directory... /usr/local/lib/php/extensions/no-debug-non-zts-20220829 +2026-Feb-04 14:31:21.684719 #19 226.9 checking for PHP installed headers prefix... /usr/local/include/php +2026-Feb-04 14:31:21.684719 #19 226.9 checking if debug is enabled... no +2026-Feb-04 14:31:21.684719 #19 226.9 checking if zts is enabled... no +2026-Feb-04 14:31:21.684719 #19 226.9 checking for gawk... no +2026-Feb-04 14:31:21.684719 #19 226.9 checking for nawk... nawk +2026-Feb-04 14:31:21.684719 #19 226.9 checking if nawk is broken... no +2026-Feb-04 14:31:21.684719 #19 226.9 checking for MySQL support for PDO... yes, shared +2026-Feb-04 14:31:21.684719 #19 226.9 checking for the location of libz... no +2026-Feb-04 14:31:21.684719 #19 226.9 checking for MySQL UNIX socket location... +2026-Feb-04 14:31:21.684719 #19 226.9 checking for PDO includes... /usr/local/include/php/ext +2026-Feb-04 14:31:21.684719 #19 226.9 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:21.684719 #19 227.0 checking for ld used by cc... /usr/bin/ld +2026-Feb-04 14:31:21.684719 #19 227.0 checking if the linker (/usr/bin/ld) is GNU ld... +2026-Feb-04 14:31:21.814194 yes +2026-Feb-04 14:31:21.814194 #19 227.0 checking for /usr/bin/ld option to reload object files... -r +2026-Feb-04 14:31:21.814194 #19 227.0 checking for BSD-compatible nm... /usr/bin/nm -B +2026-Feb-04 14:31:21.814194 #19 227.0 checking whether ln -s works... yes +2026-Feb-04 14:31:21.814194 #19 227.0 checking how to recognize dependent libraries... pass_all +2026-Feb-04 14:31:21.814194 #19 227.0 checking for stdio.h... yes +2026-Feb-04 14:31:21.814194 #19 227.0 checking for stdlib.h... yes +2026-Feb-04 14:31:21.928600 #19 227.1 checking for string.h... yes +2026-Feb-04 14:31:21.928600 #19 227.1 checking for inttypes.h... yes +2026-Feb-04 14:31:22.076302 #19 227.2 checking for stdint.h... yes +2026-Feb-04 14:31:22.076302 #19 227.3 checking for strings.h... yes +2026-Feb-04 14:31:22.076302 #19 227.3 checking for sys/stat.h... yes +2026-Feb-04 14:31:22.180701 #19 227.4 checking for sys/types.h... yes +2026-Feb-04 14:31:22.180701 #19 227.4 checking for unistd.h... yes +2026-Feb-04 14:31:22.396307 #19 227.5 checking for dlfcn.h... yes +2026-Feb-04 14:31:22.396307 #19 227.5 checking the maximum length of command line arguments... 1572864 +2026-Feb-04 14:31:22.396307 #19 227.5 checking command to parse /usr/bin/nm -B output from cc object... +2026-Feb-04 14:31:22.407841 ok +2026-Feb-04 14:31:22.540857 #19 227.7 checking for objdir... .libs +2026-Feb-04 14:31:22.540857 #19 227.7 checking for ar... ar +2026-Feb-04 14:31:22.540857 #19 227.7 checking for ranlib... ranlib +2026-Feb-04 14:31:22.540857 #19 227.7 checking for strip... strip +2026-Feb-04 14:31:22.540857 #19 227.8 checking if cc supports -fno-rtti -fno-exceptions... +2026-Feb-04 14:31:22.760647 no +2026-Feb-04 14:31:22.760647 #19 227.9 checking for cc option to produce PIC... -fPIC +2026-Feb-04 14:31:22.760647 #19 227.9 checking if cc PIC flag -fPIC works... yes +2026-Feb-04 14:31:22.760647 #19 227.9 checking if cc static flag -static works... yes +2026-Feb-04 14:31:22.893213 #19 228.0 checking if cc supports -c -o file.o... yes +2026-Feb-04 14:31:22.893213 #19 228.1 checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:22.893213 #19 228.1 checking whether -lc should be explicitly linked in... no +2026-Feb-04 14:31:23.083331 #19 228.2 checking dynamic linker characteristics... GNU/Linux ld.so +2026-Feb-04 14:31:23.083331 #19 228.2 checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:31:23.083331 #19 228.2 checking whether stripping libraries is possible... yes +2026-Feb-04 14:31:23.083331 #19 228.2 checking if libtool supports shared libraries... yes +2026-Feb-04 14:31:23.083331 #19 228.2 checking whether to build shared libraries... yes +2026-Feb-04 14:31:23.083331 #19 228.2 checking whether to build static libraries... no +2026-Feb-04 14:31:23.259379 #19 228.5 +2026-Feb-04 14:31:23.445207 #19 228.5 creating libtool +2026-Feb-04 14:31:23.445207 #19 228.6 appending configuration tag "CXX" to libtool +2026-Feb-04 14:31:23.475314 #19 228.8 configure: patching config.h.in +2026-Feb-04 14:31:23.588104 #19 228.8 configure: creating ./config.status +2026-Feb-04 14:31:23.588104 #19 228.9 config.status: creating config.h +2026-Feb-04 14:31:23.814921 #19 228.9 /bin/bash /usr/src/php/ext/pdo_mysql/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/pdo_mysql.c -o pdo_mysql.lo -MMD -MF pdo_mysql.dep -MT pdo_mysql.lo +2026-Feb-04 14:31:23.942349 #19 229.2 mkdir .libs +2026-Feb-04 14:31:24.098218 #19 229.2 cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/pdo_mysql.c -MMD -MF pdo_mysql.dep -MT pdo_mysql.lo -fPIC -DPIC -o .libs/pdo_mysql.o +2026-Feb-04 14:31:24.207848 #19 229.5 /bin/bash /usr/src/php/ext/pdo_mysql/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/mysql_driver.c -o mysql_driver.lo -MMD -MF mysql_driver.dep -MT mysql_driver.lo +2026-Feb-04 14:31:24.426581 #19 229.7 cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/mysql_driver.c -MMD -MF mysql_driver.dep -MT mysql_driver.lo -fPIC -DPIC -o .libs/mysql_driver.o +2026-Feb-04 14:31:25.074190 #19 230.4 /bin/bash /usr/src/php/ext/pdo_mysql/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/mysql_statement.c -o mysql_statement.lo -MMD -MF mysql_statement.dep -MT mysql_statement.lo +2026-Feb-04 14:31:25.287003 #19 230.6 cc -I. -I/usr/src/php/ext/pdo_mysql -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/local/include/php/ext -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/pdo_mysql/mysql_statement.c -MMD -MF mysql_statement.dep -MT mysql_statement.lo -fPIC -DPIC -o .libs/mysql_statement.o +2026-Feb-04 14:31:25.691500 #19 231.0 /bin/bash /usr/src/php/ext/pdo_mysql/libtool --tag=CC --mode=link cc -shared -I/usr/src/php/ext/pdo_mysql/include -I/usr/src/php/ext/pdo_mysql/main -I/usr/src/php/ext/pdo_mysql -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wl,-O1 -pie -o pdo_mysql.la -export-dynamic -avoid-version -prefer-pic -module -rpath /usr/src/php/ext/pdo_mysql/modules pdo_mysql.lo mysql_driver.lo mysql_statement.lo +2026-Feb-04 14:31:25.887639 #19 231.2 cc -shared .libs/pdo_mysql.o .libs/mysql_driver.o .libs/mysql_statement.o -Wl,-O1 -Wl,-soname -Wl,pdo_mysql.so -o .libs/pdo_mysql.so +2026-Feb-04 14:31:25.994667 #19 231.2 creating pdo_mysql.la +2026-Feb-04 14:31:25.994667 #19 231.2 (cd .libs && rm -f pdo_mysql.la && ln -s ../pdo_mysql.la pdo_mysql.la) +2026-Feb-04 14:31:25.994667 #19 231.2 /bin/bash /usr/src/php/ext/pdo_mysql/libtool --tag=CC --mode=install cp ./pdo_mysql.la /usr/src/php/ext/pdo_mysql/modules +2026-Feb-04 14:31:25.994667 #19 231.3 cp ./.libs/pdo_mysql.so /usr/src/php/ext/pdo_mysql/modules/pdo_mysql.so +2026-Feb-04 14:31:26.143404 #19 231.3 cp ./.libs/pdo_mysql.lai /usr/src/php/ext/pdo_mysql/modules/pdo_mysql.la +2026-Feb-04 14:31:26.143404 #19 231.3 PATH="$PATH:/sbin" ldconfig -n /usr/src/php/ext/pdo_mysql/modules +2026-Feb-04 14:31:26.143404 #19 231.3 ---------------------------------------------------------------------- +2026-Feb-04 14:31:26.143404 #19 231.3 Libraries have been installed in: +2026-Feb-04 14:31:26.143404 #19 231.3 /usr/src/php/ext/pdo_mysql/modules +2026-Feb-04 14:31:26.143404 #19 231.3 +2026-Feb-04 14:31:26.143404 #19 231.3 If you ever happen to want to link against installed libraries +2026-Feb-04 14:31:26.143404 #19 231.3 in a given directory, LIBDIR, you must either use libtool, and +2026-Feb-04 14:31:26.143404 #19 231.3 specify the full pathname of the library, or use the `-LLIBDIR' +2026-Feb-04 14:31:26.143404 #19 231.3 flag during linking and do at least one of the following: +2026-Feb-04 14:31:26.143404 #19 231.3 - add LIBDIR to the `LD_LIBRARY_PATH' environment variable +2026-Feb-04 14:31:26.143404 #19 231.3 during execution +2026-Feb-04 14:31:26.143404 #19 231.3 - add LIBDIR to the `LD_RUN_PATH' environment variable +2026-Feb-04 14:31:26.143404 #19 231.3 during linking +2026-Feb-04 14:31:26.143404 #19 231.3 - use the `-Wl,--rpath -Wl,LIBDIR' linker flag +2026-Feb-04 14:31:26.143404 #19 231.3 - have your system administrator add LIBDIR to `/etc/ld.so.conf' +2026-Feb-04 14:31:26.143404 #19 231.3 +2026-Feb-04 14:31:26.143404 #19 231.3 See any operating system documentation about shared libraries for +2026-Feb-04 14:31:26.143404 #19 231.3 more information, such as the ld(1) and ld.so(8) manual pages. +2026-Feb-04 14:31:26.143404 #19 231.3 ---------------------------------------------------------------------- +2026-Feb-04 14:31:26.143404 #19 231.3 +2026-Feb-04 14:31:26.143404 #19 231.3 Build complete. +2026-Feb-04 14:31:26.143404 #19 231.3 Don't forget to run 'make test'. +2026-Feb-04 14:31:26.143404 #19 231.3 +2026-Feb-04 14:31:26.143404 #19 231.4 + strip --strip-all modules/pdo_mysql.so +2026-Feb-04 14:31:26.143404 #19 231.4 Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20220829/ +2026-Feb-04 14:31:26.290362 #19 231.6 find . -name \*.gcno -o -name \*.gcda | xargs rm -f +2026-Feb-04 14:31:26.391189 #19 231.6 find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f +2026-Feb-04 14:31:26.391189 #19 231.6 find . -name \*.la -o -name \*.a | xargs rm -f +2026-Feb-04 14:31:26.391189 #19 231.6 find . -name \*.so | xargs rm -f +2026-Feb-04 14:31:26.391189 #19 231.6 find . -name .libs -a -type d|xargs rm -rf +2026-Feb-04 14:31:26.391189 #19 231.6 rm -f libphp.la modules/* libs/* +2026-Feb-04 14:31:26.391189 #19 231.6 rm -f ext/opcache/jit/zend_jit_x86.c +2026-Feb-04 14:31:26.391189 #19 231.6 rm -f ext/opcache/jit/zend_jit_arm64.c +2026-Feb-04 14:31:26.391189 #19 231.6 rm -f ext/opcache/minilua +2026-Feb-04 14:31:26.391189 #19 231.7 Configuring for: +2026-Feb-04 14:31:26.391189 #19 231.7 PHP Api Version: 20220829 +2026-Feb-04 14:31:26.391189 #19 231.7 Zend Module Api No: 20220829 +2026-Feb-04 14:31:26.391189 #19 231.7 Zend Extension Api No: 420220829 +2026-Feb-04 14:31:27.682609 #19 233.0 checking for grep that handles long lines and -e... +2026-Feb-04 14:31:27.802615 /usr/bin/grep +2026-Feb-04 14:31:27.802615 #19 233.0 checking for egrep... /usr/bin/grep -E +2026-Feb-04 14:31:27.802615 #19 233.0 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:27.802615 #19 233.0 checking for pkg-config... /usr/bin/pkg-config +2026-Feb-04 14:31:27.802615 #19 233.0 checking pkg-config is at least version 0.9.0... yes +2026-Feb-04 14:31:27.802615 #19 233.0 checking for cc... cc +2026-Feb-04 14:31:27.802615 #19 233.1 checking whether the C compiler works... +2026-Feb-04 14:31:27.942791 yes +2026-Feb-04 14:31:27.942791 #19 233.2 checking for C compiler default output file name... a.out +2026-Feb-04 14:31:27.942791 #19 233.2 checking for suffix of executables... +2026-Feb-04 14:31:28.070711 #19 233.2 checking whether we are cross compiling... no +2026-Feb-04 14:31:28.070711 #19 233.3 checking for suffix of object files... o +2026-Feb-04 14:31:28.070711 #19 233.4 checking whether the compiler supports GNU C... +2026-Feb-04 14:31:28.242993 yes +2026-Feb-04 14:31:28.242993 #19 233.4 checking whether cc accepts -g... yes +2026-Feb-04 14:31:28.242993 #19 233.4 checking for cc option to enable C11 features... none needed +2026-Feb-04 14:31:28.343320 #19 233.5 checking how to run the C preprocessor... cc -E +2026-Feb-04 14:31:28.343320 #19 233.6 checking for egrep -e... +2026-Feb-04 14:31:28.477354 (cached) /usr/bin/grep -E +2026-Feb-04 14:31:28.477354 #19 233.6 checking for icc... no +2026-Feb-04 14:31:28.477354 #19 233.6 checking for suncc... no +2026-Feb-04 14:31:28.477354 #19 233.7 checking for system library directory... lib +2026-Feb-04 14:31:28.477354 #19 233.7 checking if compiler supports -Wl,-rpath,... yes +2026-Feb-04 14:31:28.605562 #19 233.8 checking build system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:28.605562 #19 233.8 checking host system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:28.605562 #19 233.8 checking target system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:28.605562 #19 233.9 checking for PHP prefix... /usr/local +2026-Feb-04 14:31:28.605562 #19 233.9 checking for PHP includes... -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib +2026-Feb-04 14:31:28.605562 #19 233.9 checking for PHP extension directory... /usr/local/lib/php/extensions/no-debug-non-zts-20220829 +2026-Feb-04 14:31:28.605562 #19 233.9 checking for PHP installed headers prefix... /usr/local/include/php +2026-Feb-04 14:31:28.605562 #19 233.9 checking if debug is enabled... no +2026-Feb-04 14:31:28.708799 #19 233.9 checking if zts is enabled... no +2026-Feb-04 14:31:28.708799 #19 233.9 checking for gawk... no +2026-Feb-04 14:31:28.708799 #19 233.9 checking for nawk... nawk +2026-Feb-04 14:31:28.708799 #19 233.9 checking if nawk is broken... no +2026-Feb-04 14:31:28.708799 #19 233.9 checking whether to enable bc style precision math functions... yes, shared +2026-Feb-04 14:31:28.708799 #19 234.0 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:28.810788 #19 234.0 checking for ld used by cc... /usr/bin/ld +2026-Feb-04 14:31:28.810788 #19 234.0 checking if the linker (/usr/bin/ld) is GNU ld... yes +2026-Feb-04 14:31:28.810788 #19 234.0 checking for /usr/bin/ld option to reload object files... -r +2026-Feb-04 14:31:28.810788 #19 234.0 checking for BSD-compatible nm... /usr/bin/nm -B +2026-Feb-04 14:31:28.810788 #19 234.0 checking whether ln -s works... yes +2026-Feb-04 14:31:28.810788 #19 234.0 checking how to recognize dependent libraries... pass_all +2026-Feb-04 14:31:28.810788 #19 234.0 checking for stdio.h... yes +2026-Feb-04 14:31:28.953205 #19 234.1 checking for stdlib.h... yes +2026-Feb-04 14:31:28.953205 #19 234.1 checking for string.h... yes +2026-Feb-04 14:31:28.953205 #19 234.2 checking for inttypes.h... yes +2026-Feb-04 14:31:29.053939 #19 234.2 checking for stdint.h... yes +2026-Feb-04 14:31:29.053939 #19 234.3 checking for strings.h... yes +2026-Feb-04 14:31:29.053939 #19 234.3 checking for sys/stat.h... +2026-Feb-04 14:31:29.182843 yes +2026-Feb-04 14:31:29.182843 #19 234.4 checking for sys/types.h... yes +2026-Feb-04 14:31:29.290009 #19 234.5 checking for unistd.h... yes +2026-Feb-04 14:31:29.290009 #19 234.5 checking for dlfcn.h... yes +2026-Feb-04 14:31:29.290009 #19 234.6 checking the maximum length of command line arguments... 1572864 +2026-Feb-04 14:31:29.440945 #19 234.6 checking command to parse /usr/bin/nm -B output from cc object... +2026-Feb-04 14:31:29.487446 ok +2026-Feb-04 14:31:29.487446 #19 234.7 checking for objdir... +2026-Feb-04 14:31:29.602819 .libs +2026-Feb-04 14:31:29.602819 #19 234.8 checking for ar... ar +2026-Feb-04 14:31:29.602819 #19 234.8 checking for ranlib... ranlib +2026-Feb-04 14:31:29.602819 #19 234.8 checking for strip... strip +2026-Feb-04 14:31:29.602819 #19 234.9 checking if cc supports -fno-rtti -fno-exceptions... +2026-Feb-04 14:31:29.768946 no +2026-Feb-04 14:31:29.768946 #19 234.9 checking for cc option to produce PIC... -fPIC +2026-Feb-04 14:31:29.768946 #19 234.9 checking if cc PIC flag -fPIC works... yes +2026-Feb-04 14:31:29.768946 #19 235.0 checking if cc static flag -static works... +2026-Feb-04 14:31:29.908461 yes +2026-Feb-04 14:31:30.035482 #19 235.2 checking if cc supports -c -o file.o... yes +2026-Feb-04 14:31:30.035482 #19 235.2 checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:30.035482 #19 235.3 checking whether -lc should be explicitly linked in... no +2026-Feb-04 14:31:30.221238 #19 235.3 checking dynamic linker characteristics... GNU/Linux ld.so +2026-Feb-04 14:31:30.221238 #19 235.3 checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:31:30.221238 #19 235.3 checking whether stripping libraries is possible... yes +2026-Feb-04 14:31:30.221238 #19 235.4 checking if libtool supports shared libraries... yes +2026-Feb-04 14:31:30.221238 #19 235.4 checking whether to build shared libraries... yes +2026-Feb-04 14:31:30.221238 #19 235.4 checking whether to build static libraries... no +2026-Feb-04 14:31:30.439805 #19 235.7 +2026-Feb-04 14:31:30.439805 #19 235.7 creating libtool +2026-Feb-04 14:31:30.596145 #19 235.8 appending configuration tag "CXX" to libtool +2026-Feb-04 14:31:30.596145 #19 235.9 configure: patching config.h.in +2026-Feb-04 14:31:30.778075 #19 235.9 configure: creating ./config.status +2026-Feb-04 14:31:30.778075 #19 236.0 config.status: creating config.h +2026-Feb-04 14:31:30.778075 #19 236.1 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/bcmath.c -o bcmath.lo -MMD -MF bcmath.dep -MT bcmath.lo +2026-Feb-04 14:31:30.996601 #19 236.3 mkdir .libs +2026-Feb-04 14:31:31.152245 #19 236.3 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/bcmath.c -MMD -MF bcmath.dep -MT bcmath.lo -fPIC -DPIC -o .libs/bcmath.o +2026-Feb-04 14:31:31.490243 #19 236.8 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/add.c -o libbcmath/src/add.lo -MMD -MF libbcmath/src/add.dep -MT libbcmath/src/add.lo +2026-Feb-04 14:31:31.693579 #19 237.0 mkdir libbcmath/src/.libs +2026-Feb-04 14:31:31.850168 #19 237.0 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/add.c -MMD -MF libbcmath/src/add.dep -MT libbcmath/src/add.lo -fPIC -DPIC -o libbcmath/src/.libs/add.o +2026-Feb-04 14:31:31.932783 #19 237.2 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/div.c -o libbcmath/src/div.lo -MMD -MF libbcmath/src/div.dep -MT libbcmath/src/div.lo +2026-Feb-04 14:31:32.151323 #19 237.4 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/div.c -MMD -MF libbcmath/src/div.dep -MT libbcmath/src/div.lo -fPIC -DPIC -o libbcmath/src/.libs/div.o +2026-Feb-04 14:31:32.458640 #19 237.7 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/init.c -o libbcmath/src/init.lo -MMD -MF libbcmath/src/init.dep -MT libbcmath/src/init.lo +2026-Feb-04 14:31:32.732827 #19 238.0 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/init.c -MMD -MF libbcmath/src/init.dep -MT libbcmath/src/init.lo -fPIC -DPIC -o libbcmath/src/.libs/init.o +2026-Feb-04 14:31:32.972640 #19 238.3 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/neg.c -o libbcmath/src/neg.lo -MMD -MF libbcmath/src/neg.dep -MT libbcmath/src/neg.lo +2026-Feb-04 14:31:33.191018 #19 238.5 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/neg.c -MMD -MF libbcmath/src/neg.dep -MT libbcmath/src/neg.lo -fPIC -DPIC -o libbcmath/src/.libs/neg.o +2026-Feb-04 14:31:33.453373 #19 238.7 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/raisemod.c -o libbcmath/src/raisemod.lo -MMD -MF libbcmath/src/raisemod.dep -MT libbcmath/src/raisemod.lo +2026-Feb-04 14:31:33.689952 #19 239.0 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/raisemod.c -MMD -MF libbcmath/src/raisemod.dep -MT libbcmath/src/raisemod.lo -fPIC -DPIC -o libbcmath/src/.libs/raisemod.o +2026-Feb-04 14:31:33.921113 #19 239.2 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/sub.c -o libbcmath/src/sub.lo -MMD -MF libbcmath/src/sub.dep -MT libbcmath/src/sub.lo +2026-Feb-04 14:31:34.137253 #19 239.4 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/sub.c -MMD -MF libbcmath/src/sub.dep -MT libbcmath/src/sub.lo -fPIC -DPIC -o libbcmath/src/.libs/sub.o +2026-Feb-04 14:31:34.348131 #19 239.6 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/compare.c -o libbcmath/src/compare.lo -MMD -MF libbcmath/src/compare.dep -MT libbcmath/src/compare.lo +2026-Feb-04 14:31:34.564345 #19 239.8 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/compare.c -MMD -MF libbcmath/src/compare.dep -MT libbcmath/src/compare.lo -fPIC -DPIC -o libbcmath/src/.libs/compare.o +2026-Feb-04 14:31:34.790780 #19 240.1 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/divmod.c -o libbcmath/src/divmod.lo -MMD -MF libbcmath/src/divmod.dep -MT libbcmath/src/divmod.lo +2026-Feb-04 14:31:34.992594 #19 240.3 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/divmod.c -MMD -MF libbcmath/src/divmod.dep -MT libbcmath/src/divmod.lo -fPIC -DPIC -o libbcmath/src/.libs/divmod.o +2026-Feb-04 14:31:35.205153 #19 240.5 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/int2num.c -o libbcmath/src/int2num.lo -MMD -MF libbcmath/src/int2num.dep -MT libbcmath/src/int2num.lo +2026-Feb-04 14:31:35.443509 #19 240.7 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/int2num.c -MMD -MF libbcmath/src/int2num.dep -MT libbcmath/src/int2num.lo -fPIC -DPIC -o libbcmath/src/.libs/int2num.o +2026-Feb-04 14:31:35.658006 #19 240.9 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/num2long.c -o libbcmath/src/num2long.lo -MMD -MF libbcmath/src/num2long.dep -MT libbcmath/src/num2long.lo +2026-Feb-04 14:31:35.863121 #19 241.1 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/num2long.c -MMD -MF libbcmath/src/num2long.dep -MT libbcmath/src/num2long.lo -fPIC -DPIC -o libbcmath/src/.libs/num2long.o +2026-Feb-04 14:31:36.041043 #19 241.3 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/output.c -o libbcmath/src/output.lo -MMD -MF libbcmath/src/output.dep -MT libbcmath/src/output.lo +2026-Feb-04 14:31:36.235996 #19 241.5 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/output.c -MMD -MF libbcmath/src/output.dep -MT libbcmath/src/output.lo -fPIC -DPIC -o libbcmath/src/.libs/output.o +2026-Feb-04 14:31:36.504817 #19 241.8 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/recmul.c -o libbcmath/src/recmul.lo -MMD -MF libbcmath/src/recmul.dep -MT libbcmath/src/recmul.lo +2026-Feb-04 14:31:36.714848 #19 242.0 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/recmul.c -MMD -MF libbcmath/src/recmul.dep -MT libbcmath/src/recmul.lo -fPIC -DPIC -o libbcmath/src/.libs/recmul.o +2026-Feb-04 14:31:37.028729 #19 242.3 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/sqrt.c -o libbcmath/src/sqrt.lo -MMD -MF libbcmath/src/sqrt.dep -MT libbcmath/src/sqrt.lo +2026-Feb-04 14:31:37.256452 #19 242.5 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/sqrt.c -MMD -MF libbcmath/src/sqrt.dep -MT libbcmath/src/sqrt.lo -fPIC -DPIC -o libbcmath/src/.libs/sqrt.o +2026-Feb-04 14:31:37.499087 #19 242.8 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/zero.c -o libbcmath/src/zero.lo -MMD -MF libbcmath/src/zero.dep -MT libbcmath/src/zero.lo +2026-Feb-04 14:31:37.715807 #19 243.0 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/zero.c -MMD -MF libbcmath/src/zero.dep -MT libbcmath/src/zero.lo -fPIC -DPIC -o libbcmath/src/.libs/zero.o +2026-Feb-04 14:31:37.935966 #19 243.2 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/debug.c -o libbcmath/src/debug.lo -MMD -MF libbcmath/src/debug.dep -MT libbcmath/src/debug.lo +2026-Feb-04 14:31:38.170585 #19 243.5 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/debug.c -MMD -MF libbcmath/src/debug.dep -MT libbcmath/src/debug.lo -fPIC -DPIC -o libbcmath/src/.libs/debug.o +2026-Feb-04 14:31:38.387741 #19 243.7 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/doaddsub.c -o libbcmath/src/doaddsub.lo -MMD -MF libbcmath/src/doaddsub.dep -MT libbcmath/src/doaddsub.lo +2026-Feb-04 14:31:38.602402 #19 243.9 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/doaddsub.c -MMD -MF libbcmath/src/doaddsub.dep -MT libbcmath/src/doaddsub.lo -fPIC -DPIC -o libbcmath/src/.libs/doaddsub.o +2026-Feb-04 14:31:38.894710 #19 244.2 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/nearzero.c -o libbcmath/src/nearzero.lo -MMD -MF libbcmath/src/nearzero.dep -MT libbcmath/src/nearzero.lo +2026-Feb-04 14:31:39.094001 #19 244.4 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/nearzero.c -MMD -MF libbcmath/src/nearzero.dep -MT libbcmath/src/nearzero.lo -fPIC -DPIC -o libbcmath/src/.libs/nearzero.o +2026-Feb-04 14:31:39.328339 #19 244.6 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/num2str.c -o libbcmath/src/num2str.lo -MMD -MF libbcmath/src/num2str.dep -MT libbcmath/src/num2str.lo +2026-Feb-04 14:31:39.529350 #19 244.8 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/num2str.c -MMD -MF libbcmath/src/num2str.dep -MT libbcmath/src/num2str.lo -fPIC -DPIC -o libbcmath/src/.libs/num2str.o +2026-Feb-04 14:31:39.847512 #19 245.1 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/raise.c -o libbcmath/src/raise.lo -MMD -MF libbcmath/src/raise.dep -MT libbcmath/src/raise.lo +2026-Feb-04 14:31:40.053433 #19 245.3 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/raise.c -MMD -MF libbcmath/src/raise.dep -MT libbcmath/src/raise.lo -fPIC -DPIC -o libbcmath/src/.libs/raise.o +2026-Feb-04 14:31:40.322835 #19 245.6 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/rmzero.c -o libbcmath/src/rmzero.lo -MMD -MF libbcmath/src/rmzero.dep -MT libbcmath/src/rmzero.lo +2026-Feb-04 14:31:40.562871 #19 245.8 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/rmzero.c -MMD -MF libbcmath/src/rmzero.dep -MT libbcmath/src/rmzero.lo -fPIC -DPIC -o libbcmath/src/.libs/rmzero.o +2026-Feb-04 14:31:40.786332 #19 246.1 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/str2num.c -o libbcmath/src/str2num.lo -MMD -MF libbcmath/src/str2num.dep -MT libbcmath/src/str2num.lo +2026-Feb-04 14:31:40.992356 #19 246.3 cc -I. -I/usr/src/php/ext/bcmath -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -I/usr/src/php/ext/bcmath/libbcmath/src -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/bcmath/libbcmath/src/str2num.c -MMD -MF libbcmath/src/str2num.dep -MT libbcmath/src/str2num.lo -fPIC -DPIC -o libbcmath/src/.libs/str2num.o +2026-Feb-04 14:31:41.256452 #19 246.5 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=link cc -shared -I/usr/src/php/ext/bcmath/include -I/usr/src/php/ext/bcmath/main -I/usr/src/php/ext/bcmath -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wl,-O1 -pie -o bcmath.la -export-dynamic -avoid-version -prefer-pic -module -rpath /usr/src/php/ext/bcmath/modules bcmath.lo libbcmath/src/add.lo libbcmath/src/div.lo libbcmath/src/init.lo libbcmath/src/neg.lo libbcmath/src/raisemod.lo libbcmath/src/sub.lo libbcmath/src/compare.lo libbcmath/src/divmod.lo libbcmath/src/int2num.lo libbcmath/src/num2long.lo libbcmath/src/output.lo libbcmath/src/recmul.lo libbcmath/src/sqrt.lo libbcmath/src/zero.lo libbcmath/src/debug.lo libbcmath/src/doaddsub.lo libbcmath/src/nearzero.lo libbcmath/src/num2str.lo libbcmath/src/raise.lo libbcmath/src/rmzero.lo libbcmath/src/str2num.lo +2026-Feb-04 14:31:41.644926 #19 246.9 cc -shared .libs/bcmath.o libbcmath/src/.libs/add.o libbcmath/src/.libs/div.o libbcmath/src/.libs/init.o libbcmath/src/.libs/neg.o libbcmath/src/.libs/raisemod.o libbcmath/src/.libs/sub.o libbcmath/src/.libs/compare.o libbcmath/src/.libs/divmod.o libbcmath/src/.libs/int2num.o libbcmath/src/.libs/num2long.o libbcmath/src/.libs/output.o libbcmath/src/.libs/recmul.o libbcmath/src/.libs/sqrt.o libbcmath/src/.libs/zero.o libbcmath/src/.libs/debug.o libbcmath/src/.libs/doaddsub.o libbcmath/src/.libs/nearzero.o libbcmath/src/.libs/num2str.o libbcmath/src/.libs/raise.o libbcmath/src/.libs/rmzero.o libbcmath/src/.libs/str2num.o -Wl,-O1 -Wl,-soname -Wl,bcmath.so -o .libs/bcmath.so +2026-Feb-04 14:31:41.777054 #19 247.0 creating bcmath.la +2026-Feb-04 14:31:41.777054 #19 247.0 (cd .libs && rm -f bcmath.la && ln -s ../bcmath.la bcmath.la) +2026-Feb-04 14:31:41.777054 #19 247.0 /bin/bash /usr/src/php/ext/bcmath/libtool --tag=CC --mode=install cp ./bcmath.la /usr/src/php/ext/bcmath/modules +2026-Feb-04 14:31:41.777054 #19 247.1 cp ./.libs/bcmath.so /usr/src/php/ext/bcmath/modules/bcmath.so +2026-Feb-04 14:31:41.933488 #19 247.1 cp ./.libs/bcmath.lai /usr/src/php/ext/bcmath/modules/bcmath.la +2026-Feb-04 14:31:41.933488 #19 247.1 PATH="$PATH:/sbin" ldconfig -n /usr/src/php/ext/bcmath/modules +2026-Feb-04 14:31:41.933488 #19 247.1 ---------------------------------------------------------------------- +2026-Feb-04 14:31:41.933488 #19 247.1 Libraries have been installed in: +2026-Feb-04 14:31:41.933488 #19 247.1 /usr/src/php/ext/bcmath/modules +2026-Feb-04 14:31:41.933488 #19 247.1 +2026-Feb-04 14:31:41.933488 #19 247.1 If you ever happen to want to link against installed libraries +2026-Feb-04 14:31:41.933488 #19 247.1 in a given directory, LIBDIR, you must either use libtool, and +2026-Feb-04 14:31:41.933488 #19 247.1 specify the full pathname of the library, or use the `-LLIBDIR' +2026-Feb-04 14:31:41.933488 #19 247.1 flag during linking and do at least one of the following: +2026-Feb-04 14:31:41.933488 #19 247.1 - add LIBDIR to the `LD_LIBRARY_PATH' environment variable +2026-Feb-04 14:31:41.933488 #19 247.1 during execution +2026-Feb-04 14:31:41.933488 #19 247.1 - add LIBDIR to the `LD_RUN_PATH' environment variable +2026-Feb-04 14:31:41.933488 #19 247.1 during linking +2026-Feb-04 14:31:41.933488 #19 247.1 - use the `-Wl,--rpath -Wl,LIBDIR' linker flag +2026-Feb-04 14:31:41.933488 #19 247.1 - have your system administrator add LIBDIR to `/etc/ld.so.conf' +2026-Feb-04 14:31:41.933488 #19 247.1 +2026-Feb-04 14:31:41.933488 #19 247.1 See any operating system documentation about shared libraries for +2026-Feb-04 14:31:41.933488 #19 247.1 more information, such as the ld(1) and ld.so(8) manual pages. +2026-Feb-04 14:31:41.933488 #19 247.1 ---------------------------------------------------------------------- +2026-Feb-04 14:31:41.933488 #19 247.1 +2026-Feb-04 14:31:41.933488 #19 247.1 Build complete. +2026-Feb-04 14:31:41.933488 #19 247.1 Don't forget to run 'make test'. +2026-Feb-04 14:31:41.933488 #19 247.1 +2026-Feb-04 14:31:41.933488 #19 247.1 + strip --strip-all modules/bcmath.so +2026-Feb-04 14:31:41.933488 #19 247.2 Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20220829/ +2026-Feb-04 14:31:42.145681 #19 247.4 find . -name \*.gcno -o -name \*.gcda | xargs rm -f +2026-Feb-04 14:31:42.394741 #19 247.4 find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f +2026-Feb-04 14:31:42.394741 #19 247.4 find . -name \*.la -o -name \*.a | xargs rm -f +2026-Feb-04 14:31:42.394741 #19 247.4 find . -name \*.so | xargs rm -f +2026-Feb-04 14:31:42.394741 #19 247.5 find . -name .libs -a -type d|xargs rm -rf +2026-Feb-04 14:31:42.394741 #19 247.5 rm -f libphp.la modules/* libs/* +2026-Feb-04 14:31:42.394741 #19 247.5 rm -f ext/opcache/jit/zend_jit_x86.c +2026-Feb-04 14:31:42.394741 #19 247.5 rm -f ext/opcache/jit/zend_jit_arm64.c +2026-Feb-04 14:31:42.394741 #19 247.5 rm -f ext/opcache/minilua +2026-Feb-04 14:31:42.394741 #19 247.5 Configuring for: +2026-Feb-04 14:31:42.394741 #19 247.5 PHP Api Version: 20220829 +2026-Feb-04 14:31:42.394741 #19 247.5 Zend Module Api No: 20220829 +2026-Feb-04 14:31:42.394741 #19 247.5 Zend Extension Api No: 420220829 +2026-Feb-04 14:31:43.508649 #19 248.8 checking for grep that handles long lines and -e... +2026-Feb-04 14:31:43.632809 /usr/bin/grep +2026-Feb-04 14:31:43.632809 #19 248.8 checking for egrep... /usr/bin/grep -E +2026-Feb-04 14:31:43.632809 #19 248.8 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:43.632809 #19 248.9 checking for pkg-config... /usr/bin/pkg-config +2026-Feb-04 14:31:43.632809 #19 248.9 checking pkg-config is at least version 0.9.0... yes +2026-Feb-04 14:31:43.632809 #19 248.9 checking for cc... cc +2026-Feb-04 14:31:43.632809 #19 248.9 checking whether the C compiler works... +2026-Feb-04 14:31:43.741235 yes +2026-Feb-04 14:31:43.741235 #19 249.0 checking for C compiler default output file name... a.out +2026-Feb-04 14:31:43.881489 #19 249.0 checking for suffix of executables... +2026-Feb-04 14:31:43.881489 #19 249.1 checking whether we are cross compiling... no +2026-Feb-04 14:31:43.994787 #19 249.2 checking for suffix of object files... o +2026-Feb-04 14:31:43.994787 #19 249.2 checking whether the compiler supports GNU C... yes +2026-Feb-04 14:31:43.994787 #19 249.2 checking whether cc accepts -g... yes +2026-Feb-04 14:31:44.135030 #19 249.3 checking for cc option to enable C11 features... none needed +2026-Feb-04 14:31:44.135030 #19 249.4 checking how to run the C preprocessor... cc -E +2026-Feb-04 14:31:44.290684 #19 249.5 checking for egrep -e... (cached) /usr/bin/grep -E +2026-Feb-04 14:31:44.290684 #19 249.5 checking for icc... no +2026-Feb-04 14:31:44.290684 #19 249.5 checking for suncc... no +2026-Feb-04 14:31:44.290684 #19 249.5 checking for system library directory... lib +2026-Feb-04 14:31:44.290684 #19 249.5 checking if compiler supports -Wl,-rpath,... yes +2026-Feb-04 14:31:44.394808 #19 249.6 checking build system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:44.394808 #19 249.6 checking host system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:44.394808 #19 249.6 checking target system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:44.394808 #19 249.7 checking for PHP prefix... /usr/local +2026-Feb-04 14:31:44.499485 #19 249.7 checking for PHP includes... -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib +2026-Feb-04 14:31:44.499485 #19 249.7 checking for PHP extension directory... /usr/local/lib/php/extensions/no-debug-non-zts-20220829 +2026-Feb-04 14:31:44.499485 #19 249.7 checking for PHP installed headers prefix... /usr/local/include/php +2026-Feb-04 14:31:44.499485 #19 249.7 checking if debug is enabled... no +2026-Feb-04 14:31:44.499485 #19 249.7 checking if zts is enabled... no +2026-Feb-04 14:31:44.499485 #19 249.7 checking for gawk... no +2026-Feb-04 14:31:44.499485 #19 249.7 checking for nawk... nawk +2026-Feb-04 14:31:44.499485 #19 249.7 checking if nawk is broken... no +2026-Feb-04 14:31:44.499485 #19 249.7 checking whether to enable EXIF (metadata from images) support... yes, shared +2026-Feb-04 14:31:44.499485 #19 249.8 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:44.499485 #19 249.8 checking for ld used by cc... /usr/bin/ld +2026-Feb-04 14:31:44.499485 #19 249.8 checking if the linker (/usr/bin/ld) is GNU ld... yes +2026-Feb-04 14:31:44.499485 #19 249.8 checking for /usr/bin/ld option to reload object files... -r +2026-Feb-04 14:31:44.499485 #19 249.8 checking for BSD-compatible nm... /usr/bin/nm -B +2026-Feb-04 14:31:44.628350 #19 249.8 checking whether ln -s works... yes +2026-Feb-04 14:31:44.628350 #19 249.8 checking how to recognize dependent libraries... pass_all +2026-Feb-04 14:31:44.628350 #19 249.8 checking for stdio.h... yes +2026-Feb-04 14:31:44.628350 #19 249.8 checking for stdlib.h... yes +2026-Feb-04 14:31:44.763960 #19 249.9 checking for string.h... yes +2026-Feb-04 14:31:44.763960 #19 249.9 checking for inttypes.h... yes +2026-Feb-04 14:31:44.763960 #19 250.0 checking for stdint.h... yes +2026-Feb-04 14:31:44.763960 #19 250.0 checking for strings.h... +2026-Feb-04 14:31:44.865320 yes +2026-Feb-04 14:31:44.865320 #19 250.1 checking for sys/stat.h... yes +2026-Feb-04 14:31:44.984361 #19 250.1 checking for sys/types.h... yes +2026-Feb-04 14:31:44.984361 #19 250.2 checking for unistd.h... yes +2026-Feb-04 14:31:45.188707 #19 250.3 checking for dlfcn.h... yes +2026-Feb-04 14:31:45.188707 #19 250.3 checking the maximum length of command line arguments... 1572864 +2026-Feb-04 14:31:45.188707 #19 250.3 checking command to parse /usr/bin/nm -B output from cc object... ok +2026-Feb-04 14:31:45.303075 #19 250.5 checking for objdir... .libs +2026-Feb-04 14:31:45.303075 #19 250.5 checking for ar... ar +2026-Feb-04 14:31:45.303075 #19 250.5 checking for ranlib... ranlib +2026-Feb-04 14:31:45.303075 #19 250.5 checking for strip... strip +2026-Feb-04 14:31:45.303075 #19 250.6 checking if cc supports -fno-rtti -fno-exceptions... +2026-Feb-04 14:31:45.509065 no +2026-Feb-04 14:31:45.509065 #19 250.6 checking for cc option to produce PIC... -fPIC +2026-Feb-04 14:31:45.509065 #19 250.6 checking if cc PIC flag -fPIC works... yes +2026-Feb-04 14:31:45.509065 #19 250.7 checking if cc static flag -static works... yes +2026-Feb-04 14:31:45.509065 #19 250.8 checking if cc supports -c -o file.o... +2026-Feb-04 14:31:45.651527 yes +2026-Feb-04 14:31:45.651527 #19 250.8 checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:45.651527 #19 250.9 checking whether -lc should be explicitly linked in... no +2026-Feb-04 14:31:45.836756 #19 250.9 checking dynamic linker characteristics... GNU/Linux ld.so +2026-Feb-04 14:31:45.836756 #19 251.0 checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:31:45.836756 #19 251.0 checking whether stripping libraries is possible... yes +2026-Feb-04 14:31:45.836756 #19 251.0 checking if libtool supports shared libraries... yes +2026-Feb-04 14:31:45.836756 #19 251.0 checking whether to build shared libraries... yes +2026-Feb-04 14:31:45.836756 #19 251.0 checking whether to build static libraries... no +2026-Feb-04 14:31:45.987326 #19 251.3 +2026-Feb-04 14:31:46.157189 #19 251.3 creating libtool +2026-Feb-04 14:31:46.157189 #19 251.3 appending configuration tag "CXX" to libtool +2026-Feb-04 14:31:46.157189 #19 251.4 configure: patching config.h.in +2026-Feb-04 14:31:46.279312 #19 251.4 configure: creating ./config.status +2026-Feb-04 14:31:46.279312 #19 251.6 config.status: creating config.h +2026-Feb-04 14:31:46.496236 #19 251.6 /bin/bash /usr/src/php/ext/exif/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/exif -I/usr/src/php/ext/exif/include -I/usr/src/php/ext/exif/main -I/usr/src/php/ext/exif -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/exif/exif.c -o exif.lo -MMD -MF exif.dep -MT exif.lo +2026-Feb-04 14:31:46.544959 #19 251.8 mkdir .libs +2026-Feb-04 14:31:46.698170 #19 251.8 cc -I. -I/usr/src/php/ext/exif -I/usr/src/php/ext/exif/include -I/usr/src/php/ext/exif/main -I/usr/src/php/ext/exif -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/exif/exif.c -MMD -MF exif.dep -MT exif.lo -fPIC -DPIC -o .libs/exif.o +2026-Feb-04 14:31:48.021141 #19 253.3 /bin/bash /usr/src/php/ext/exif/libtool --tag=CC --mode=link cc -shared -I/usr/src/php/ext/exif/include -I/usr/src/php/ext/exif/main -I/usr/src/php/ext/exif -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wl,-O1 -pie -o exif.la -export-dynamic -avoid-version -prefer-pic -module -rpath /usr/src/php/ext/exif/modules exif.lo +2026-Feb-04 14:31:48.217268 #19 253.5 cc -shared .libs/exif.o -Wl,-O1 -Wl,-soname -Wl,exif.so -o .libs/exif.so +2026-Feb-04 14:31:48.339311 #19 253.5 creating exif.la +2026-Feb-04 14:31:48.339311 #19 253.5 (cd .libs && rm -f exif.la && ln -s ../exif.la exif.la) +2026-Feb-04 14:31:48.339311 #19 253.6 /bin/bash /usr/src/php/ext/exif/libtool --tag=CC --mode=install cp ./exif.la /usr/src/php/ext/exif/modules +2026-Feb-04 14:31:48.339311 #19 253.6 cp ./.libs/exif.so /usr/src/php/ext/exif/modules/exif.so +2026-Feb-04 14:31:48.508876 #19 253.6 cp ./.libs/exif.lai /usr/src/php/ext/exif/modules/exif.la +2026-Feb-04 14:31:48.508876 #19 253.7 PATH="$PATH:/sbin" ldconfig -n /usr/src/php/ext/exif/modules +2026-Feb-04 14:31:48.508876 #19 253.7 ---------------------------------------------------------------------- +2026-Feb-04 14:31:48.508876 #19 253.7 Libraries have been installed in: +2026-Feb-04 14:31:48.508876 #19 253.7 /usr/src/php/ext/exif/modules +2026-Feb-04 14:31:48.508876 #19 253.7 +2026-Feb-04 14:31:48.508876 #19 253.7 If you ever happen to want to link against installed libraries +2026-Feb-04 14:31:48.508876 #19 253.7 in a given directory, LIBDIR, you must either use libtool, and +2026-Feb-04 14:31:48.508876 #19 253.7 specify the full pathname of the library, or use the `-LLIBDIR' +2026-Feb-04 14:31:48.508876 #19 253.7 flag during linking and do at least one of the following: +2026-Feb-04 14:31:48.508876 #19 253.7 - add LIBDIR to the `LD_LIBRARY_PATH' environment variable +2026-Feb-04 14:31:48.508876 #19 253.7 during execution +2026-Feb-04 14:31:48.508876 #19 253.7 - add LIBDIR to the `LD_RUN_PATH' environment variable +2026-Feb-04 14:31:48.508876 #19 253.7 during linking +2026-Feb-04 14:31:48.508876 #19 253.7 - use the `-Wl,--rpath -Wl,LIBDIR' linker flag +2026-Feb-04 14:31:48.508876 #19 253.7 - have your system administrator add LIBDIR to `/etc/ld.so.conf' +2026-Feb-04 14:31:48.508876 #19 253.7 +2026-Feb-04 14:31:48.508876 #19 253.7 See any operating system documentation about shared libraries for +2026-Feb-04 14:31:48.508876 #19 253.7 more information, such as the ld(1) and ld.so(8) manual pages. +2026-Feb-04 14:31:48.508876 #19 253.7 ---------------------------------------------------------------------- +2026-Feb-04 14:31:48.508876 #19 253.7 +2026-Feb-04 14:31:48.508876 #19 253.7 Build complete. +2026-Feb-04 14:31:48.508876 #19 253.7 Don't forget to run 'make test'. +2026-Feb-04 14:31:48.508876 #19 253.7 +2026-Feb-04 14:31:48.508876 #19 253.7 + strip --strip-all modules/exif.so +2026-Feb-04 14:31:48.508876 #19 253.8 Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20220829/ +2026-Feb-04 14:31:48.651283 #19 253.9 find . -name \*.gcno -o -name \*.gcda | xargs rm -f +2026-Feb-04 14:31:48.897256 #19 253.9 find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f +2026-Feb-04 14:31:48.897256 #19 253.9 find . -name \*.la -o -name \*.a | xargs rm -f +2026-Feb-04 14:31:48.897256 #19 254.0 find . -name \*.so | xargs rm -f +2026-Feb-04 14:31:48.897256 #19 254.0 find . -name .libs -a -type d|xargs rm -rf +2026-Feb-04 14:31:48.897256 #19 254.0 rm -f libphp.la modules/* libs/* +2026-Feb-04 14:31:48.897256 #19 254.0 rm -f ext/opcache/jit/zend_jit_x86.c +2026-Feb-04 14:31:48.897256 #19 254.0 rm -f ext/opcache/jit/zend_jit_arm64.c +2026-Feb-04 14:31:48.897256 #19 254.0 rm -f ext/opcache/minilua +2026-Feb-04 14:31:48.897256 #19 254.0 Configuring for: +2026-Feb-04 14:31:48.897256 #19 254.0 PHP Api Version: 20220829 +2026-Feb-04 14:31:48.897256 #19 254.0 Zend Module Api No: 20220829 +2026-Feb-04 14:31:48.897256 #19 254.0 Zend Extension Api No: 420220829 +2026-Feb-04 14:31:50.120034 #19 255.4 checking for grep that handles long lines and -e... +2026-Feb-04 14:31:50.240951 /usr/bin/grep +2026-Feb-04 14:31:50.240951 #19 255.4 checking for egrep... /usr/bin/grep -E +2026-Feb-04 14:31:50.240951 #19 255.4 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:50.240951 #19 255.5 checking for pkg-config... /usr/bin/pkg-config +2026-Feb-04 14:31:50.240951 #19 255.5 checking pkg-config is at least version 0.9.0... yes +2026-Feb-04 14:31:50.240951 #19 255.5 checking for cc... cc +2026-Feb-04 14:31:50.240951 #19 255.5 checking whether the C compiler works... +2026-Feb-04 14:31:50.370016 yes +2026-Feb-04 14:31:50.370016 #19 255.6 checking for C compiler default output file name... a.out +2026-Feb-04 14:31:50.370016 #19 255.6 checking for suffix of executables... +2026-Feb-04 14:31:50.480875 #19 255.7 checking whether we are cross compiling... no +2026-Feb-04 14:31:50.480875 #19 255.7 checking for suffix of object files... o +2026-Feb-04 14:31:50.653267 #19 255.8 checking whether the compiler supports GNU C... yes +2026-Feb-04 14:31:50.653267 #19 255.8 checking whether cc accepts -g... yes +2026-Feb-04 14:31:50.653267 #19 255.8 checking for cc option to enable C11 features... none needed +2026-Feb-04 14:31:50.653267 #19 255.9 checking how to run the C preprocessor... +2026-Feb-04 14:31:50.773130 cc -E +2026-Feb-04 14:31:50.773130 #19 256.1 checking for egrep -e... +2026-Feb-04 14:31:50.878278 (cached) /usr/bin/grep -E +2026-Feb-04 14:31:50.878278 #19 256.1 checking for icc... no +2026-Feb-04 14:31:50.878278 #19 256.1 checking for suncc... no +2026-Feb-04 14:31:50.878278 #19 256.1 checking for system library directory... lib +2026-Feb-04 14:31:50.878278 #19 256.1 checking if compiler supports -Wl,-rpath,... yes +2026-Feb-04 14:31:50.878278 #19 256.2 checking build system type... +2026-Feb-04 14:31:50.984150 x86_64-pc-linux-gnu +2026-Feb-04 14:31:50.984150 #19 256.2 checking host system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:50.984150 #19 256.2 checking target system type... x86_64-pc-linux-gnu +2026-Feb-04 14:31:50.984150 #19 256.2 checking for PHP prefix... /usr/local +2026-Feb-04 14:31:50.984150 #19 256.2 checking for PHP includes... -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib +2026-Feb-04 14:31:50.984150 #19 256.2 checking for PHP extension directory... /usr/local/lib/php/extensions/no-debug-non-zts-20220829 +2026-Feb-04 14:31:50.984150 #19 256.2 checking for PHP installed headers prefix... /usr/local/include/php +2026-Feb-04 14:31:50.984150 #19 256.2 checking if debug is enabled... no +2026-Feb-04 14:31:51.158123 #19 256.3 checking if zts is enabled... no +2026-Feb-04 14:31:51.158123 #19 256.3 checking for gawk... no +2026-Feb-04 14:31:51.158123 #19 256.3 checking for nawk... nawk +2026-Feb-04 14:31:51.158123 #19 256.3 checking if nawk is broken... no +2026-Feb-04 14:31:51.158123 #19 256.3 checking whether to enable internationalization support... yes, shared +2026-Feb-04 14:31:51.158123 #19 256.3 checking for icu-uc >= 50.1 icu-io icu-i18n... yes +2026-Feb-04 14:31:51.158123 #19 256.4 checking for g++... +2026-Feb-04 14:31:51.301924 g++ +2026-Feb-04 14:31:51.301924 #19 256.5 checking whether the compiler supports GNU C++... yes +2026-Feb-04 14:31:51.301924 #19 256.5 checking whether g++ accepts -g... yes +2026-Feb-04 14:31:51.452847 #19 256.6 checking for g++ option to enable C++11 features... +2026-Feb-04 14:31:51.474880 none needed +2026-Feb-04 14:31:51.577925 #19 256.8 checking how to run the C++ preprocessor... g++ -E +2026-Feb-04 14:31:51.577925 #19 256.9 checking if intl requires -std=gnu++17... yes +2026-Feb-04 14:31:51.577925 #19 256.9 checking whether g++ supports C++17 features with -std=c++17... +2026-Feb-04 14:31:51.783757 yes +2026-Feb-04 14:31:51.894379 #19 257.1 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:31:51.894379 #19 257.1 checking for ld used by cc... /usr/bin/ld +2026-Feb-04 14:31:51.894379 #19 257.1 checking if the linker (/usr/bin/ld) is GNU ld... yes +2026-Feb-04 14:31:51.894379 #19 257.1 checking for /usr/bin/ld option to reload object files... -r +2026-Feb-04 14:31:51.894379 #19 257.1 checking for BSD-compatible nm... /usr/bin/nm -B +2026-Feb-04 14:31:51.894379 #19 257.1 checking whether ln -s works... yes +2026-Feb-04 14:31:51.894379 #19 257.1 checking how to recognize dependent libraries... pass_all +2026-Feb-04 14:31:51.894379 #19 257.2 checking for stdio.h... +2026-Feb-04 14:31:52.020764 yes +2026-Feb-04 14:31:52.020764 #19 257.2 checking for stdlib.h... yes +2026-Feb-04 14:31:52.020764 #19 257.3 checking for string.h... yes +2026-Feb-04 14:31:52.161207 #19 257.3 checking for inttypes.h... yes +2026-Feb-04 14:31:52.161207 #19 257.4 checking for stdint.h... yes +2026-Feb-04 14:31:52.161207 #19 257.4 checking for strings.h... +2026-Feb-04 14:31:52.304651 yes +2026-Feb-04 14:31:52.304651 #19 257.5 checking for sys/stat.h... yes +2026-Feb-04 14:31:52.304651 #19 257.5 checking for sys/types.h... yes +2026-Feb-04 14:31:52.418872 #19 257.6 checking for unistd.h... yes +2026-Feb-04 14:31:52.418872 #19 257.6 checking for dlfcn.h... yes +2026-Feb-04 14:31:52.533122 #19 257.7 checking how to run the C++ preprocessor... g++ -E +2026-Feb-04 14:31:52.533122 #19 257.8 checking the maximum length of command line arguments... +2026-Feb-04 14:31:52.693023 1572864 +2026-Feb-04 14:31:52.693023 #19 257.8 checking command to parse /usr/bin/nm -B output from cc object... +2026-Feb-04 14:31:52.747398 ok +2026-Feb-04 14:31:52.747398 #19 258.0 checking for objdir... +2026-Feb-04 14:31:52.909689 .libs +2026-Feb-04 14:31:52.909689 #19 258.0 checking for ar... ar +2026-Feb-04 14:31:52.909689 #19 258.0 checking for ranlib... ranlib +2026-Feb-04 14:31:52.909689 #19 258.0 checking for strip... strip +2026-Feb-04 14:31:52.946532 #19 258.2 checking if cc supports -fno-rtti -fno-exceptions... +2026-Feb-04 14:31:53.129712 no +2026-Feb-04 14:31:53.129712 #19 258.2 checking for cc option to produce PIC... -fPIC +2026-Feb-04 14:31:53.129712 #19 258.2 checking if cc PIC flag -fPIC works... yes +2026-Feb-04 14:31:53.129712 #19 258.3 checking if cc static flag -static works... yes +2026-Feb-04 14:31:53.129712 #19 258.4 checking if cc supports -c -o file.o... +2026-Feb-04 14:31:53.274534 yes +2026-Feb-04 14:31:53.274534 #19 258.5 checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:53.274534 #19 258.5 checking whether -lc should be explicitly linked in... no +2026-Feb-04 14:31:53.274534 #19 258.6 checking dynamic linker characteristics... +2026-Feb-04 14:31:53.459660 GNU/Linux ld.so +2026-Feb-04 14:31:53.459660 #19 258.6 checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:31:53.459660 #19 258.6 checking whether stripping libraries is possible... yes +2026-Feb-04 14:31:53.459660 #19 258.6 checking if libtool supports shared libraries... yes +2026-Feb-04 14:31:53.459660 #19 258.6 checking whether to build shared libraries... yes +2026-Feb-04 14:31:53.459660 #19 258.6 checking whether to build static libraries... no +2026-Feb-04 14:31:53.684993 #19 259.0 +2026-Feb-04 14:31:53.684993 #19 259.0 creating libtool +2026-Feb-04 14:31:53.870993 #19 259.0 appending configuration tag "CXX" to libtool +2026-Feb-04 14:31:53.870993 #19 259.1 checking for ld used by g++... +2026-Feb-04 14:31:54.044583 /usr/bin/ld -m elf_x86_64 +2026-Feb-04 14:31:54.044583 #19 259.2 checking if the linker (/usr/bin/ld -m elf_x86_64) is GNU ld... yes +2026-Feb-04 14:31:54.044583 #19 259.2 checking whether the g++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:54.044583 #19 259.3 checking for g++ option to produce PIC... +2026-Feb-04 14:31:54.233898 -fPIC +2026-Feb-04 14:31:54.233898 #19 259.3 checking if g++ PIC flag -fPIC works... yes +2026-Feb-04 14:31:54.233898 #19 259.4 checking if g++ static flag -static works... +2026-Feb-04 14:31:54.268211 yes +2026-Feb-04 14:31:54.506109 #19 259.5 checking if g++ supports -c -o file.o... yes +2026-Feb-04 14:31:54.506109 #19 259.6 checking whether the g++ linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:31:54.506109 #19 259.6 checking dynamic linker characteristics... GNU/Linux ld.so +2026-Feb-04 14:31:54.506109 #19 259.6 (cached) (cached) checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:31:54.916740 #19 260.2 configure: patching config.h.in +2026-Feb-04 14:31:55.077284 #19 260.2 configure: creating ./config.status +2026-Feb-04 14:31:55.099334 #19 260.4 config.status: creating config.h +2026-Feb-04 14:31:55.190692 #19 260.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/php_intl.c -o php_intl.lo -MMD -MF php_intl.dep -MT php_intl.lo +2026-Feb-04 14:31:55.416356 #19 260.7 mkdir .libs +2026-Feb-04 14:31:55.571159 #19 260.7 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/php_intl.c -MMD -MF php_intl.dep -MT php_intl.lo -fPIC -DPIC -o .libs/php_intl.o +2026-Feb-04 14:31:55.751920 #19 261.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/intl_error.c -o intl_error.lo -MMD -MF intl_error.dep -MT intl_error.lo +2026-Feb-04 14:31:56.010814 #19 261.3 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/intl_error.c -MMD -MF intl_error.dep -MT intl_error.lo -fPIC -DPIC -o .libs/intl_error.o +2026-Feb-04 14:31:56.434990 #19 261.7 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/intl_convert.c -o intl_convert.lo -MMD -MF intl_convert.dep -MT intl_convert.lo +2026-Feb-04 14:31:56.698686 #19 262.0 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/intl_convert.c -MMD -MF intl_convert.dep -MT intl_convert.lo -fPIC -DPIC -o .libs/intl_convert.o +2026-Feb-04 14:31:56.953028 #19 262.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_class.c -o collator/collator_class.lo -MMD -MF collator/collator_class.dep -MT collator/collator_class.lo +2026-Feb-04 14:31:57.187036 #19 262.5 mkdir collator/.libs +2026-Feb-04 14:31:57.342332 #19 262.5 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_class.c -MMD -MF collator/collator_class.dep -MT collator/collator_class.lo -fPIC -DPIC -o collator/.libs/collator_class.o +2026-Feb-04 14:31:57.609121 #19 262.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_sort.c -o collator/collator_sort.lo -MMD -MF collator/collator_sort.dep -MT collator/collator_sort.lo +2026-Feb-04 14:31:57.859948 #19 263.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_sort.c -MMD -MF collator/collator_sort.dep -MT collator/collator_sort.lo -fPIC -DPIC -o collator/.libs/collator_sort.o +2026-Feb-04 14:31:58.261675 #19 263.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_convert.c -o collator/collator_convert.lo -MMD -MF collator/collator_convert.dep -MT collator/collator_convert.lo +2026-Feb-04 14:31:58.512117 #19 263.8 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_convert.c -MMD -MF collator/collator_convert.dep -MT collator/collator_convert.lo -fPIC -DPIC -o collator/.libs/collator_convert.o +2026-Feb-04 14:31:58.919515 #19 264.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_locale.c -o collator/collator_locale.lo -MMD -MF collator/collator_locale.dep -MT collator/collator_locale.lo +2026-Feb-04 14:31:59.203850 #19 264.5 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_locale.c -MMD -MF collator/collator_locale.dep -MT collator/collator_locale.lo -fPIC -DPIC -o collator/.libs/collator_locale.o +2026-Feb-04 14:31:59.508668 #19 264.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_compare.c -o collator/collator_compare.lo -MMD -MF collator/collator_compare.dep -MT collator/collator_compare.lo +2026-Feb-04 14:31:59.839308 #19 265.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_compare.c -MMD -MF collator/collator_compare.dep -MT collator/collator_compare.lo -fPIC -DPIC -o collator/.libs/collator_compare.o +2026-Feb-04 14:32:00.117296 #19 265.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_attr.c -o collator/collator_attr.lo -MMD -MF collator/collator_attr.dep -MT collator/collator_attr.lo +2026-Feb-04 14:32:00.334963 #19 265.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_attr.c -MMD -MF collator/collator_attr.dep -MT collator/collator_attr.lo -fPIC -DPIC -o collator/.libs/collator_attr.o +2026-Feb-04 14:32:00.600382 #19 265.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_create.c -o collator/collator_create.lo -MMD -MF collator/collator_create.dep -MT collator/collator_create.lo +2026-Feb-04 14:32:00.836489 #19 266.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_create.c -MMD -MF collator/collator_create.dep -MT collator/collator_create.lo -fPIC -DPIC -o collator/.libs/collator_create.o +2026-Feb-04 14:32:01.129856 #19 266.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_is_numeric.c -o collator/collator_is_numeric.lo -MMD -MF collator/collator_is_numeric.dep -MT collator/collator_is_numeric.lo +2026-Feb-04 14:32:01.361908 #19 266.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_is_numeric.c -MMD -MF collator/collator_is_numeric.dep -MT collator/collator_is_numeric.lo -fPIC -DPIC -o collator/.libs/collator_is_numeric.o +2026-Feb-04 14:32:01.794872 #19 267.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_error.c -o collator/collator_error.lo -MMD -MF collator/collator_error.dep -MT collator/collator_error.lo +2026-Feb-04 14:32:02.028349 #19 267.3 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/collator/collator_error.c -MMD -MF collator/collator_error.dep -MT collator/collator_error.lo -fPIC -DPIC -o collator/.libs/collator_error.o +2026-Feb-04 14:32:02.344288 #19 267.6 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/common/common_error.c -o common/common_error.lo -MMD -MF common/common_error.dep -MT common/common_error.lo +2026-Feb-04 14:32:02.610590 #19 267.9 mkdir common/.libs +2026-Feb-04 14:32:02.767878 #19 267.9 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/common/common_error.c -MMD -MF common/common_error.dep -MT common/common_error.lo -fPIC -DPIC -o common/.libs/common_error.o +2026-Feb-04 14:32:02.913189 #19 268.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/converter/converter.c -o converter/converter.lo -MMD -MF converter/converter.dep -MT converter/converter.lo +2026-Feb-04 14:32:03.135491 #19 268.4 mkdir converter/.libs +2026-Feb-04 14:32:03.291486 #19 268.4 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/converter/converter.c -MMD -MF converter/converter.dep -MT converter/converter.lo -fPIC -DPIC -o converter/.libs/converter.o +2026-Feb-04 14:32:03.944726 #19 269.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_main.c -o formatter/formatter_main.lo -MMD -MF formatter/formatter_main.dep -MT formatter/formatter_main.lo +2026-Feb-04 14:32:04.257108 #19 269.5 mkdir formatter/.libs +2026-Feb-04 14:32:04.432765 #19 269.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_main.c -MMD -MF formatter/formatter_main.dep -MT formatter/formatter_main.lo -fPIC -DPIC -o formatter/.libs/formatter_main.o +2026-Feb-04 14:32:04.583037 #19 269.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_class.c -o formatter/formatter_class.lo -MMD -MF formatter/formatter_class.dep -MT formatter/formatter_class.lo +2026-Feb-04 14:32:04.800540 #19 270.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_class.c -MMD -MF formatter/formatter_class.dep -MT formatter/formatter_class.lo -fPIC -DPIC -o formatter/.libs/formatter_class.o +2026-Feb-04 14:32:05.454535 #19 270.7 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_attr.c -o formatter/formatter_attr.lo -MMD -MF formatter/formatter_attr.dep -MT formatter/formatter_attr.lo +2026-Feb-04 14:32:05.676998 #19 271.0 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_attr.c -MMD -MF formatter/formatter_attr.dep -MT formatter/formatter_attr.lo -fPIC -DPIC -o formatter/.libs/formatter_attr.o +2026-Feb-04 14:32:06.117331 #19 271.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_data.c -o formatter/formatter_data.lo -MMD -MF formatter/formatter_data.dep -MT formatter/formatter_data.lo +2026-Feb-04 14:32:06.333133 #19 271.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_data.c -MMD -MF formatter/formatter_data.dep -MT formatter/formatter_data.lo -fPIC -DPIC -o formatter/.libs/formatter_data.o +2026-Feb-04 14:32:06.602621 #19 271.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_format.c -o formatter/formatter_format.lo -MMD -MF formatter/formatter_format.dep -MT formatter/formatter_format.lo +2026-Feb-04 14:32:06.828051 #19 272.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_format.c -MMD -MF formatter/formatter_format.dep -MT formatter/formatter_format.lo -fPIC -DPIC -o formatter/.libs/formatter_format.o +2026-Feb-04 14:32:07.117273 #19 272.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_parse.c -o formatter/formatter_parse.lo -MMD -MF formatter/formatter_parse.dep -MT formatter/formatter_parse.lo +2026-Feb-04 14:32:07.338572 #19 272.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/formatter/formatter_parse.c -MMD -MF formatter/formatter_parse.dep -MT formatter/formatter_parse.lo -fPIC -DPIC -o formatter/.libs/formatter_parse.o +2026-Feb-04 14:32:07.626889 #19 272.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/normalizer/normalizer_class.c -o normalizer/normalizer_class.lo -MMD -MF normalizer/normalizer_class.dep -MT normalizer/normalizer_class.lo +2026-Feb-04 14:32:07.910388 #19 273.2 mkdir normalizer/.libs +2026-Feb-04 14:32:08.066277 #19 273.2 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/normalizer/normalizer_class.c -MMD -MF normalizer/normalizer_class.dep -MT normalizer/normalizer_class.lo -fPIC -DPIC -o normalizer/.libs/normalizer_class.o +2026-Feb-04 14:32:08.219857 #19 273.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/normalizer/normalizer_normalize.c -o normalizer/normalizer_normalize.lo -MMD -MF normalizer/normalizer_normalize.dep -MT normalizer/normalizer_normalize.lo +2026-Feb-04 14:32:08.438056 #19 273.7 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/normalizer/normalizer_normalize.c -MMD -MF normalizer/normalizer_normalize.dep -MT normalizer/normalizer_normalize.lo -fPIC -DPIC -o normalizer/.libs/normalizer_normalize.o +2026-Feb-04 14:32:08.754833 #19 274.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale.c -o locale/locale.lo -MMD -MF locale/locale.dep -MT locale/locale.lo +2026-Feb-04 14:32:09.020275 #19 274.3 mkdir locale/.libs +2026-Feb-04 14:32:09.174263 #19 274.3 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale.c -MMD -MF locale/locale.dep -MT locale/locale.lo -fPIC -DPIC -o locale/.libs/locale.o +2026-Feb-04 14:32:09.237386 #19 274.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale_class.c -o locale/locale_class.lo -MMD -MF locale/locale_class.dep -MT locale/locale_class.lo +2026-Feb-04 14:32:09.526214 #19 274.8 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale_class.c -MMD -MF locale/locale_class.dep -MT locale/locale_class.lo -fPIC -DPIC -o locale/.libs/locale_class.o +2026-Feb-04 14:32:09.868304 #19 275.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale_methods.c -o locale/locale_methods.lo -MMD -MF locale/locale_methods.dep -MT locale/locale_methods.lo +2026-Feb-04 14:32:10.210100 #19 275.5 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/locale/locale_methods.c -MMD -MF locale/locale_methods.dep -MT locale/locale_methods.lo -fPIC -DPIC -o locale/.libs/locale_methods.o +2026-Feb-04 14:32:11.242670 #19 276.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat.c -o dateformat/dateformat.lo -MMD -MF dateformat/dateformat.dep -MT dateformat/dateformat.lo +2026-Feb-04 14:32:11.456866 #19 276.7 mkdir dateformat/.libs +2026-Feb-04 14:32:11.612216 #19 276.7 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat.c -MMD -MF dateformat/dateformat.dep -MT dateformat/dateformat.lo -fPIC -DPIC -o dateformat/.libs/dateformat.o +2026-Feb-04 14:32:11.727237 #19 277.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_class.c -o dateformat/dateformat_class.lo -MMD -MF dateformat/dateformat_class.dep -MT dateformat/dateformat_class.lo +2026-Feb-04 14:32:11.949652 #19 277.2 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_class.c -MMD -MF dateformat/dateformat_class.dep -MT dateformat/dateformat_class.lo -fPIC -DPIC -o dateformat/.libs/dateformat_class.o +2026-Feb-04 14:32:12.288297 #19 277.6 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_attr.c -o dateformat/dateformat_attr.lo -MMD -MF dateformat/dateformat_attr.dep -MT dateformat/dateformat_attr.lo +2026-Feb-04 14:32:12.507699 #19 277.8 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_attr.c -MMD -MF dateformat/dateformat_attr.dep -MT dateformat/dateformat_attr.lo -fPIC -DPIC -o dateformat/.libs/dateformat_attr.o +2026-Feb-04 14:32:12.799157 #19 278.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_data.c -o dateformat/dateformat_data.lo -MMD -MF dateformat/dateformat_data.dep -MT dateformat/dateformat_data.lo +2026-Feb-04 14:32:13.053591 #19 278.3 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_data.c -MMD -MF dateformat/dateformat_data.dep -MT dateformat/dateformat_data.lo -fPIC -DPIC -o dateformat/.libs/dateformat_data.o +2026-Feb-04 14:32:13.284552 #19 278.6 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_format.c -o dateformat/dateformat_format.lo -MMD -MF dateformat/dateformat_format.dep -MT dateformat/dateformat_format.lo +2026-Feb-04 14:32:13.507675 #19 278.8 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_format.c -MMD -MF dateformat/dateformat_format.dep -MT dateformat/dateformat_format.lo -fPIC -DPIC -o dateformat/.libs/dateformat_format.o +2026-Feb-04 14:32:13.850518 #19 279.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_parse.c -o dateformat/dateformat_parse.lo -MMD -MF dateformat/dateformat_parse.dep -MT dateformat/dateformat_parse.lo +2026-Feb-04 14:32:14.137746 #19 279.4 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/dateformat/dateformat_parse.c -MMD -MF dateformat/dateformat_parse.dep -MT dateformat/dateformat_parse.lo -fPIC -DPIC -o dateformat/.libs/dateformat_parse.o +2026-Feb-04 14:32:14.469972 #19 279.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat.c -o msgformat/msgformat.lo -MMD -MF msgformat/msgformat.dep -MT msgformat/msgformat.lo +2026-Feb-04 14:32:14.736630 #19 280.0 mkdir msgformat/.libs +2026-Feb-04 14:32:14.892088 #19 280.0 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat.c -MMD -MF msgformat/msgformat.dep -MT msgformat/msgformat.lo -fPIC -DPIC -o msgformat/.libs/msgformat.o +2026-Feb-04 14:32:15.030733 #19 280.3 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_attr.c -o msgformat/msgformat_attr.lo -MMD -MF msgformat/msgformat_attr.dep -MT msgformat/msgformat_attr.lo +2026-Feb-04 14:32:15.307326 #19 280.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_attr.c -MMD -MF msgformat/msgformat_attr.dep -MT msgformat/msgformat_attr.lo -fPIC -DPIC -o msgformat/.libs/msgformat_attr.o +2026-Feb-04 14:32:15.615771 #19 280.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_class.c -o msgformat/msgformat_class.lo -MMD -MF msgformat/msgformat_class.dep -MT msgformat/msgformat_class.lo +2026-Feb-04 14:32:15.839156 #19 281.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_class.c -MMD -MF msgformat/msgformat_class.dep -MT msgformat/msgformat_class.lo -fPIC -DPIC -o msgformat/.libs/msgformat_class.o +2026-Feb-04 14:32:16.198304 #19 281.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_data.c -o msgformat/msgformat_data.lo -MMD -MF msgformat/msgformat_data.dep -MT msgformat/msgformat_data.lo +2026-Feb-04 14:32:16.423687 #19 281.7 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_data.c -MMD -MF msgformat/msgformat_data.dep -MT msgformat/msgformat_data.lo -fPIC -DPIC -o msgformat/.libs/msgformat_data.o +2026-Feb-04 14:32:16.670630 #19 282.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_format.c -o msgformat/msgformat_format.lo -MMD -MF msgformat/msgformat_format.dep -MT msgformat/msgformat_format.lo +2026-Feb-04 14:32:16.915147 #19 282.2 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_format.c -MMD -MF msgformat/msgformat_format.dep -MT msgformat/msgformat_format.lo -fPIC -DPIC -o msgformat/.libs/msgformat_format.o +2026-Feb-04 14:32:17.189197 #19 282.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_parse.c -o msgformat/msgformat_parse.lo -MMD -MF msgformat/msgformat_parse.dep -MT msgformat/msgformat_parse.lo +2026-Feb-04 14:32:17.524969 #19 282.8 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/msgformat/msgformat_parse.c -MMD -MF msgformat/msgformat_parse.dep -MT msgformat/msgformat_parse.lo -fPIC -DPIC -o msgformat/.libs/msgformat_parse.o +2026-Feb-04 14:32:17.800732 #19 283.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/grapheme/grapheme_string.c -o grapheme/grapheme_string.lo -MMD -MF grapheme/grapheme_string.dep -MT grapheme/grapheme_string.lo +2026-Feb-04 14:32:18.287360 #19 283.6 mkdir grapheme/.libs +2026-Feb-04 14:32:18.439186 #19 283.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/grapheme/grapheme_string.c -MMD -MF grapheme/grapheme_string.dep -MT grapheme/grapheme_string.lo -fPIC -DPIC -o grapheme/.libs/grapheme_string.o +2026-Feb-04 14:32:18.954173 #19 284.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/grapheme/grapheme_util.c -o grapheme/grapheme_util.lo -MMD -MF grapheme/grapheme_util.dep -MT grapheme/grapheme_util.lo +2026-Feb-04 14:32:19.280833 #19 284.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/grapheme/grapheme_util.c -MMD -MF grapheme/grapheme_util.dep -MT grapheme/grapheme_util.lo -fPIC -DPIC -o grapheme/.libs/grapheme_util.o +2026-Feb-04 14:32:19.648007 #19 284.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle.c -o resourcebundle/resourcebundle.lo -MMD -MF resourcebundle/resourcebundle.dep -MT resourcebundle/resourcebundle.lo +2026-Feb-04 14:32:19.902369 #19 285.2 mkdir resourcebundle/.libs +2026-Feb-04 14:32:20.057157 #19 285.2 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle.c -MMD -MF resourcebundle/resourcebundle.dep -MT resourcebundle/resourcebundle.lo -fPIC -DPIC -o resourcebundle/.libs/resourcebundle.o +2026-Feb-04 14:32:20.183292 #19 285.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle_class.c -o resourcebundle/resourcebundle_class.lo -MMD -MF resourcebundle/resourcebundle_class.dep -MT resourcebundle/resourcebundle_class.lo +2026-Feb-04 14:32:20.575212 #19 285.9 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle_class.c -MMD -MF resourcebundle/resourcebundle_class.dep -MT resourcebundle/resourcebundle_class.lo -fPIC -DPIC -o resourcebundle/.libs/resourcebundle_class.o +2026-Feb-04 14:32:20.965389 #19 286.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle_iterator.c -o resourcebundle/resourcebundle_iterator.lo -MMD -MF resourcebundle/resourcebundle_iterator.dep -MT resourcebundle/resourcebundle_iterator.lo +2026-Feb-04 14:32:21.225889 #19 286.5 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/resourcebundle/resourcebundle_iterator.c -MMD -MF resourcebundle/resourcebundle_iterator.dep -MT resourcebundle/resourcebundle_iterator.lo -fPIC -DPIC -o resourcebundle/.libs/resourcebundle_iterator.o +2026-Feb-04 14:32:21.516967 #19 286.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/transliterator/transliterator_class.c -o transliterator/transliterator_class.lo -MMD -MF transliterator/transliterator_class.dep -MT transliterator/transliterator_class.lo +2026-Feb-04 14:32:21.729058 #19 287.0 mkdir transliterator/.libs +2026-Feb-04 14:32:21.886841 #19 287.0 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/transliterator/transliterator_class.c -MMD -MF transliterator/transliterator_class.dep -MT transliterator/transliterator_class.lo -fPIC -DPIC -o transliterator/.libs/transliterator_class.o +2026-Feb-04 14:32:22.040985 #19 287.3 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/transliterator/transliterator_methods.c -o transliterator/transliterator_methods.lo -MMD -MF transliterator/transliterator_methods.dep -MT transliterator/transliterator_methods.lo +2026-Feb-04 14:32:22.270985 #19 287.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/transliterator/transliterator_methods.c -MMD -MF transliterator/transliterator_methods.dep -MT transliterator/transliterator_methods.lo -fPIC -DPIC -o transliterator/.libs/transliterator_methods.o +2026-Feb-04 14:32:22.764072 #19 288.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/uchar/uchar.c -o uchar/uchar.lo -MMD -MF uchar/uchar.dep -MT uchar/uchar.lo +2026-Feb-04 14:32:23.003133 #19 288.3 mkdir uchar/.libs +2026-Feb-04 14:32:23.157265 #19 288.3 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/uchar/uchar.c -MMD -MF uchar/uchar.dep -MT uchar/uchar.lo -fPIC -DPIC -o uchar/.libs/uchar.o +2026-Feb-04 14:32:31.020525 #19 296.3 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/idn/idn.c -o idn/idn.lo -MMD -MF idn/idn.dep -MT idn/idn.lo +2026-Feb-04 14:32:31.246295 #19 296.5 mkdir idn/.libs +2026-Feb-04 14:32:31.401988 #19 296.5 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/idn/idn.c -MMD -MF idn/idn.dep -MT idn/idn.lo -fPIC -DPIC -o idn/.libs/idn.o +2026-Feb-04 14:32:31.558115 #19 296.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_class.c -o spoofchecker/spoofchecker_class.lo -MMD -MF spoofchecker/spoofchecker_class.dep -MT spoofchecker/spoofchecker_class.lo +2026-Feb-04 14:32:31.797482 #19 297.1 mkdir spoofchecker/.libs +2026-Feb-04 14:32:31.952319 #19 297.1 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_class.c -MMD -MF spoofchecker/spoofchecker_class.dep -MT spoofchecker/spoofchecker_class.lo -fPIC -DPIC -o spoofchecker/.libs/spoofchecker_class.o +2026-Feb-04 14:32:32.123990 #19 297.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_create.c -o spoofchecker/spoofchecker_create.lo -MMD -MF spoofchecker/spoofchecker_create.dep -MT spoofchecker/spoofchecker_create.lo +2026-Feb-04 14:32:32.359601 #19 297.6 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_create.c -MMD -MF spoofchecker/spoofchecker_create.dep -MT spoofchecker/spoofchecker_create.lo -fPIC -DPIC -o spoofchecker/.libs/spoofchecker_create.o +2026-Feb-04 14:32:32.646005 #19 297.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_main.c -o spoofchecker/spoofchecker_main.lo -MMD -MF spoofchecker/spoofchecker_main.dep -MT spoofchecker/spoofchecker_main.lo +2026-Feb-04 14:32:32.884964 #19 298.2 cc -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/intl/spoofchecker/spoofchecker_main.c -MMD -MF spoofchecker/spoofchecker_main.dep -MT spoofchecker/spoofchecker_main.lo -fPIC -DPIC -o spoofchecker/.libs/spoofchecker_main.o +2026-Feb-04 14:32:33.175890 #19 298.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/intl_convertcpp.cpp -o intl_convertcpp.lo -MMD -MF intl_convertcpp.dep -MT intl_convertcpp.lo +2026-Feb-04 14:32:33.423640 #19 298.7 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/intl_convertcpp.cpp -MMD -MF intl_convertcpp.dep -MT intl_convertcpp.lo -fPIC -DPIC -o .libs/intl_convertcpp.o +2026-Feb-04 14:32:34.277132 #19 299.6 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/common/common_enum.cpp -o common/common_enum.lo -MMD -MF common/common_enum.dep -MT common/common_enum.lo +2026-Feb-04 14:32:34.538684 #19 299.8 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/common/common_enum.cpp -MMD -MF common/common_enum.dep -MT common/common_enum.lo -fPIC -DPIC -o common/.libs/common_enum.o +2026-Feb-04 14:32:35.506148 #19 300.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/common/common_date.cpp -o common/common_date.lo -MMD -MF common/common_date.dep -MT common/common_date.lo +2026-Feb-04 14:32:35.851476 #19 301.1 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/common/common_date.cpp -MMD -MF common/common_date.dep -MT common/common_date.lo -fPIC -DPIC -o common/.libs/common_date.o +2026-Feb-04 14:32:36.835707 #19 302.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_format_object.cpp -o dateformat/dateformat_format_object.lo -MMD -MF dateformat/dateformat_format_object.dep -MT dateformat/dateformat_format_object.lo +2026-Feb-04 14:32:37.062237 #19 302.3 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_format_object.cpp -MMD -MF dateformat/dateformat_format_object.dep -MT dateformat/dateformat_format_object.lo -fPIC -DPIC -o dateformat/.libs/dateformat_format_object.o +2026-Feb-04 14:32:38.176029 #19 303.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_create.cpp -o dateformat/dateformat_create.lo -MMD -MF dateformat/dateformat_create.dep -MT dateformat/dateformat_create.lo +2026-Feb-04 14:32:38.424169 #19 303.7 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_create.cpp -MMD -MF dateformat/dateformat_create.dep -MT dateformat/dateformat_create.lo -fPIC -DPIC -o dateformat/.libs/dateformat_create.o +2026-Feb-04 14:32:39.647081 #19 304.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_attrcpp.cpp -o dateformat/dateformat_attrcpp.lo -MMD -MF dateformat/dateformat_attrcpp.dep -MT dateformat/dateformat_attrcpp.lo +2026-Feb-04 14:32:39.874948 #19 305.2 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_attrcpp.cpp -MMD -MF dateformat/dateformat_attrcpp.dep -MT dateformat/dateformat_attrcpp.lo -fPIC -DPIC -o dateformat/.libs/dateformat_attrcpp.o +2026-Feb-04 14:32:41.093570 #19 306.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_helpers.cpp -o dateformat/dateformat_helpers.lo -MMD -MF dateformat/dateformat_helpers.dep -MT dateformat/dateformat_helpers.lo +2026-Feb-04 14:32:41.329394 #19 306.6 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/dateformat_helpers.cpp -MMD -MF dateformat/dateformat_helpers.dep -MT dateformat/dateformat_helpers.lo -fPIC -DPIC -o dateformat/.libs/dateformat_helpers.o +2026-Feb-04 14:32:42.216729 #19 307.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/datepatterngenerator_class.cpp -o dateformat/datepatterngenerator_class.lo -MMD -MF dateformat/datepatterngenerator_class.dep -MT dateformat/datepatterngenerator_class.lo +2026-Feb-04 14:32:42.452053 #19 307.7 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/datepatterngenerator_class.cpp -MMD -MF dateformat/datepatterngenerator_class.dep -MT dateformat/datepatterngenerator_class.lo -fPIC -DPIC -o dateformat/.libs/datepatterngenerator_class.o +2026-Feb-04 14:32:43.490822 #19 308.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/datepatterngenerator_methods.cpp -o dateformat/datepatterngenerator_methods.lo -MMD -MF dateformat/datepatterngenerator_methods.dep -MT dateformat/datepatterngenerator_methods.lo +2026-Feb-04 14:32:43.714103 #19 309.0 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/dateformat/datepatterngenerator_methods.cpp -MMD -MF dateformat/datepatterngenerator_methods.dep -MT dateformat/datepatterngenerator_methods.lo -fPIC -DPIC -o dateformat/.libs/datepatterngenerator_methods.o +2026-Feb-04 14:32:44.970785 #19 310.3 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/msgformat/msgformat_helpers.cpp -o msgformat/msgformat_helpers.lo -MMD -MF msgformat/msgformat_helpers.dep -MT msgformat/msgformat_helpers.lo +2026-Feb-04 14:32:45.222533 #19 310.5 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/msgformat/msgformat_helpers.cpp -MMD -MF msgformat/msgformat_helpers.dep -MT msgformat/msgformat_helpers.lo -fPIC -DPIC -o msgformat/.libs/msgformat_helpers.o +2026-Feb-04 14:32:47.022621 #19 312.3 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/timezone/timezone_class.cpp -o timezone/timezone_class.lo -MMD -MF timezone/timezone_class.dep -MT timezone/timezone_class.lo +2026-Feb-04 14:32:47.254540 #19 312.5 mkdir timezone/.libs +2026-Feb-04 14:32:47.408465 #19 312.5 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/timezone/timezone_class.cpp -MMD -MF timezone/timezone_class.dep -MT timezone/timezone_class.lo -fPIC -DPIC -o timezone/.libs/timezone_class.o +2026-Feb-04 14:32:48.392567 #19 313.7 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/timezone/timezone_methods.cpp -o timezone/timezone_methods.lo -MMD -MF timezone/timezone_methods.dep -MT timezone/timezone_methods.lo +2026-Feb-04 14:32:48.630186 #19 313.9 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/timezone/timezone_methods.cpp -MMD -MF timezone/timezone_methods.dep -MT timezone/timezone_methods.lo -fPIC -DPIC -o timezone/.libs/timezone_methods.o +2026-Feb-04 14:32:49.831967 #19 315.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/calendar_class.cpp -o calendar/calendar_class.lo -MMD -MF calendar/calendar_class.dep -MT calendar/calendar_class.lo +2026-Feb-04 14:32:50.148870 #19 315.4 mkdir calendar/.libs +2026-Feb-04 14:32:50.302153 #19 315.4 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/calendar_class.cpp -MMD -MF calendar/calendar_class.dep -MT calendar/calendar_class.lo -fPIC -DPIC -o calendar/.libs/calendar_class.o +2026-Feb-04 14:32:51.484841 #19 316.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/calendar_methods.cpp -o calendar/calendar_methods.lo -MMD -MF calendar/calendar_methods.dep -MT calendar/calendar_methods.lo +2026-Feb-04 14:32:51.716362 #19 317.0 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/calendar_methods.cpp -MMD -MF calendar/calendar_methods.dep -MT calendar/calendar_methods.lo -fPIC -DPIC -o calendar/.libs/calendar_methods.o +2026-Feb-04 14:32:53.451199 #19 318.7 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/gregoriancalendar_methods.cpp -o calendar/gregoriancalendar_methods.lo -MMD -MF calendar/gregoriancalendar_methods.dep -MT calendar/gregoriancalendar_methods.lo +2026-Feb-04 14:32:53.699304 #19 319.0 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/calendar/gregoriancalendar_methods.cpp -MMD -MF calendar/gregoriancalendar_methods.dep -MT calendar/gregoriancalendar_methods.lo -fPIC -DPIC -o calendar/.libs/gregoriancalendar_methods.o +2026-Feb-04 14:32:54.809336 #19 320.1 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_class.cpp -o breakiterator/breakiterator_class.lo -MMD -MF breakiterator/breakiterator_class.dep -MT breakiterator/breakiterator_class.lo +2026-Feb-04 14:32:55.071537 #19 320.4 mkdir breakiterator/.libs +2026-Feb-04 14:32:55.225750 #19 320.4 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_class.cpp -MMD -MF breakiterator/breakiterator_class.dep -MT breakiterator/breakiterator_class.lo -fPIC -DPIC -o breakiterator/.libs/breakiterator_class.o +2026-Feb-04 14:32:56.175127 #19 321.5 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_iterators.cpp -o breakiterator/breakiterator_iterators.lo -MMD -MF breakiterator/breakiterator_iterators.dep -MT breakiterator/breakiterator_iterators.lo +2026-Feb-04 14:32:56.426288 #19 321.7 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_iterators.cpp -MMD -MF breakiterator/breakiterator_iterators.dep -MT breakiterator/breakiterator_iterators.lo -fPIC -DPIC -o breakiterator/.libs/breakiterator_iterators.o +2026-Feb-04 14:32:57.453622 #19 322.7 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_methods.cpp -o breakiterator/breakiterator_methods.lo -MMD -MF breakiterator/breakiterator_methods.dep -MT breakiterator/breakiterator_methods.lo +2026-Feb-04 14:32:57.684080 #19 323.0 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/breakiterator_methods.cpp -MMD -MF breakiterator/breakiterator_methods.dep -MT breakiterator/breakiterator_methods.lo -fPIC -DPIC -o breakiterator/.libs/breakiterator_methods.o +2026-Feb-04 14:32:58.714379 #19 324.0 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp -o breakiterator/rulebasedbreakiterator_methods.lo -MMD -MF breakiterator/rulebasedbreakiterator_methods.dep -MT breakiterator/rulebasedbreakiterator_methods.lo +2026-Feb-04 14:32:58.966248 #19 324.2 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/rulebasedbreakiterator_methods.cpp -MMD -MF breakiterator/rulebasedbreakiterator_methods.dep -MT breakiterator/rulebasedbreakiterator_methods.lo -fPIC -DPIC -o breakiterator/.libs/rulebasedbreakiterator_methods.o +2026-Feb-04 14:33:00.114557 #19 325.4 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/codepointiterator_internal.cpp -o breakiterator/codepointiterator_internal.lo -MMD -MF breakiterator/codepointiterator_internal.dep -MT breakiterator/codepointiterator_internal.lo +2026-Feb-04 14:33:00.422876 #19 325.7 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/codepointiterator_internal.cpp -MMD -MF breakiterator/codepointiterator_internal.dep -MT breakiterator/codepointiterator_internal.lo -fPIC -DPIC -o breakiterator/.libs/codepointiterator_internal.o +2026-Feb-04 14:33:01.522011 #19 326.8 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=compile g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/codepointiterator_methods.cpp -o breakiterator/codepointiterator_methods.lo -MMD -MF breakiterator/codepointiterator_methods.dep -MT breakiterator/codepointiterator_methods.lo +2026-Feb-04 14:33:01.737585 #19 327.0 g++ -I. -I/usr/src/php/ext/intl -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -g -O2 -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -DU_HIDE_OBSOLETE_UTF_OLD_H=1 -Wno-write-strings -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -std=c++17 -DUNISTR_FROM_CHAR_EXPLICIT=explicit -DUNISTR_FROM_STRING_EXPLICIT=explicit -c /usr/src/php/ext/intl/breakiterator/codepointiterator_methods.cpp -MMD -MF breakiterator/codepointiterator_methods.dep -MT breakiterator/codepointiterator_methods.lo -fPIC -DPIC -o breakiterator/.libs/codepointiterator_methods.o +2026-Feb-04 14:33:02.598012 #19 327.9 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=link g++ -shared -I/usr/src/php/ext/intl/include -I/usr/src/php/ext/intl/main -I/usr/src/php/ext/intl -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wl,-O1 -pie -o intl.la -export-dynamic -avoid-version -prefer-pic -module -rpath /usr/src/php/ext/intl/modules php_intl.lo intl_error.lo intl_convert.lo collator/collator_class.lo collator/collator_sort.lo collator/collator_convert.lo collator/collator_locale.lo collator/collator_compare.lo collator/collator_attr.lo collator/collator_create.lo collator/collator_is_numeric.lo collator/collator_error.lo common/common_error.lo converter/converter.lo formatter/formatter_main.lo formatter/formatter_class.lo formatter/formatter_attr.lo formatter/formatter_data.lo formatter/formatter_format.lo formatter/formatter_parse.lo normalizer/normalizer_class.lo normalizer/normalizer_normalize.lo locale/locale.lo locale/locale_class.lo locale/locale_methods.lo dateformat/dateformat.lo dateformat/dateformat_class.lo dateformat/dateformat_attr.lo dateformat/dateformat_data.lo dateformat/dateformat_format.lo dateformat/dateformat_parse.lo msgformat/msgformat.lo msgformat/msgformat_attr.lo msgformat/msgformat_class.lo msgformat/msgformat_data.lo msgformat/msgformat_format.lo msgformat/msgformat_parse.lo grapheme/grapheme_string.lo grapheme/grapheme_util.lo resourcebundle/resourcebundle.lo resourcebundle/resourcebundle_class.lo resourcebundle/resourcebundle_iterator.lo transliterator/transliterator_class.lo transliterator/transliterator_methods.lo uchar/uchar.lo idn/idn.lo spoofchecker/spoofchecker_class.lo spoofchecker/spoofchecker_create.lo spoofchecker/spoofchecker_main.lo intl_convertcpp.lo common/common_enum.lo common/common_date.lo dateformat/dateformat_format_object.lo dateformat/dateformat_create.lo dateformat/dateformat_attrcpp.lo dateformat/dateformat_helpers.lo dateformat/datepatterngenerator_class.lo dateformat/datepatterngenerator_methods.lo msgformat/msgformat_helpers.lo timezone/timezone_class.lo timezone/timezone_methods.lo calendar/calendar_class.lo calendar/calendar_methods.lo calendar/gregoriancalendar_methods.lo breakiterator/breakiterator_class.lo breakiterator/breakiterator_iterators.lo breakiterator/breakiterator_methods.lo breakiterator/rulebasedbreakiterator_methods.lo breakiterator/codepointiterator_internal.lo breakiterator/codepointiterator_methods.lo -licuio -licui18n -licuuc -licudata +2026-Feb-04 14:33:03.652812 #19 328.9 g++ -shared -nostdlib /usr/lib/gcc/x86_64-linux-gnu/14/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/14/crtbeginS.o .libs/php_intl.o .libs/intl_error.o .libs/intl_convert.o collator/.libs/collator_class.o collator/.libs/collator_sort.o collator/.libs/collator_convert.o collator/.libs/collator_locale.o collator/.libs/collator_compare.o collator/.libs/collator_attr.o collator/.libs/collator_create.o collator/.libs/collator_is_numeric.o collator/.libs/collator_error.o common/.libs/common_error.o converter/.libs/converter.o formatter/.libs/formatter_main.o formatter/.libs/formatter_class.o formatter/.libs/formatter_attr.o formatter/.libs/formatter_data.o formatter/.libs/formatter_format.o formatter/.libs/formatter_parse.o normalizer/.libs/normalizer_class.o normalizer/.libs/normalizer_normalize.o locale/.libs/locale.o locale/.libs/locale_class.o locale/.libs/locale_methods.o dateformat/.libs/dateformat.o dateformat/.libs/dateformat_class.o dateformat/.libs/dateformat_attr.o dateformat/.libs/dateformat_data.o dateformat/.libs/dateformat_format.o dateformat/.libs/dateformat_parse.o msgformat/.libs/msgformat.o msgformat/.libs/msgformat_attr.o msgformat/.libs/msgformat_class.o msgformat/.libs/msgformat_data.o msgformat/.libs/msgformat_format.o msgformat/.libs/msgformat_parse.o grapheme/.libs/grapheme_string.o grapheme/.libs/grapheme_util.o resourcebundle/.libs/resourcebundle.o resourcebundle/.libs/resourcebundle_class.o resourcebundle/.libs/resourcebundle_iterator.o transliterator/.libs/transliterator_class.o transliterator/.libs/transliterator_methods.o uchar/.libs/uchar.o idn/.libs/idn.o spoofchecker/.libs/spoofchecker_class.o spoofchecker/.libs/spoofchecker_create.o spoofchecker/.libs/spoofchecker_main.o .libs/intl_convertcpp.o common/.libs/common_enum.o common/.libs/common_date.o dateformat/.libs/dateformat_format_object.o dateformat/.libs/dateformat_create.o dateformat/.libs/dateformat_attrcpp.o dateformat/.libs/dateformat_helpers.o dateformat/.libs/datepatterngenerator_class.o dateformat/.libs/datepatterngenerator_methods.o msgformat/.libs/msgformat_helpers.o timezone/.libs/timezone_class.o timezone/.libs/timezone_methods.o calendar/.libs/calendar_class.o calendar/.libs/calendar_methods.o calendar/.libs/gregoriancalendar_methods.o breakiterator/.libs/breakiterator_class.o breakiterator/.libs/breakiterator_iterators.o breakiterator/.libs/breakiterator_methods.o breakiterator/.libs/rulebasedbreakiterator_methods.o breakiterator/.libs/codepointiterator_internal.o breakiterator/.libs/codepointiterator_methods.o -licuio -licui18n -licuuc -licudata -L/usr/lib/gcc/x86_64-linux-gnu/14 -L/usr/lib/gcc/x86_64-linux-gnu/14/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/14/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/14/../../.. -lstdc++ -lm -lc -lgcc_s /usr/lib/gcc/x86_64-linux-gnu/14/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/14/../../../x86_64-linux-gnu/crtn.o -Wl,-O1 -Wl,-soname -Wl,intl.so -o .libs/intl.so +2026-Feb-04 14:33:03.878335 #19 329.2 creating intl.la +2026-Feb-04 14:33:03.984586 #19 329.2 (cd .libs && rm -f intl.la && ln -s ../intl.la intl.la) +2026-Feb-04 14:33:03.984586 #19 329.2 /bin/bash /usr/src/php/ext/intl/libtool --tag=CXX --mode=install cp ./intl.la /usr/src/php/ext/intl/modules +2026-Feb-04 14:33:03.984586 #19 329.3 cp ./.libs/intl.so /usr/src/php/ext/intl/modules/intl.so +2026-Feb-04 14:33:03.984586 #19 329.3 cp ./.libs/intl.lai /usr/src/php/ext/intl/modules/intl.la +2026-Feb-04 14:33:04.122748 #19 329.3 PATH="$PATH:/sbin" ldconfig -n /usr/src/php/ext/intl/modules +2026-Feb-04 14:33:04.122748 #19 329.3 ---------------------------------------------------------------------- +2026-Feb-04 14:33:04.122748 #19 329.3 Libraries have been installed in: +2026-Feb-04 14:33:04.122748 #19 329.3 /usr/src/php/ext/intl/modules +2026-Feb-04 14:33:04.122748 #19 329.3 +2026-Feb-04 14:33:04.122748 #19 329.3 If you ever happen to want to link against installed libraries +2026-Feb-04 14:33:04.122748 #19 329.3 in a given directory, LIBDIR, you must either use libtool, and +2026-Feb-04 14:33:04.122748 #19 329.3 specify the full pathname of the library, or use the `-LLIBDIR' +2026-Feb-04 14:33:04.122748 #19 329.3 flag during linking and do at least one of the following: +2026-Feb-04 14:33:04.122748 #19 329.3 - add LIBDIR to the `LD_LIBRARY_PATH' environment variable +2026-Feb-04 14:33:04.122748 #19 329.3 during execution +2026-Feb-04 14:33:04.122748 #19 329.3 - add LIBDIR to the `LD_RUN_PATH' environment variable +2026-Feb-04 14:33:04.122748 #19 329.3 during linking +2026-Feb-04 14:33:04.122748 #19 329.3 - use the `-Wl,--rpath -Wl,LIBDIR' linker flag +2026-Feb-04 14:33:04.122748 #19 329.3 - have your system administrator add LIBDIR to `/etc/ld.so.conf' +2026-Feb-04 14:33:04.122748 #19 329.3 +2026-Feb-04 14:33:04.122748 #19 329.3 See any operating system documentation about shared libraries for +2026-Feb-04 14:33:04.122748 #19 329.3 more information, such as the ld(1) and ld.so(8) manual pages. +2026-Feb-04 14:33:04.122748 #19 329.3 ---------------------------------------------------------------------- +2026-Feb-04 14:33:04.122748 #19 329.3 +2026-Feb-04 14:33:04.122748 #19 329.4 Build complete. +2026-Feb-04 14:33:04.122748 #19 329.4 Don't forget to run 'make test'. +2026-Feb-04 14:33:04.122748 #19 329.4 +2026-Feb-04 14:33:04.122748 #19 329.4 + strip --strip-all modules/intl.so +2026-Feb-04 14:33:04.367863 #19 329.5 Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20220829/ +2026-Feb-04 14:33:04.414981 #19 329.7 find . -name \*.gcno -o -name \*.gcda | xargs rm -f +2026-Feb-04 14:33:04.578608 #19 329.7 find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f +2026-Feb-04 14:33:04.578608 #19 329.7 find . -name \*.la -o -name \*.a | xargs rm -f +2026-Feb-04 14:33:04.578608 #19 329.7 find . -name \*.so | xargs rm -f +2026-Feb-04 14:33:04.578608 #19 329.8 find . -name .libs -a -type d|xargs rm -rf +2026-Feb-04 14:33:04.578608 #19 329.8 rm -f libphp.la modules/* libs/* +2026-Feb-04 14:33:04.578608 #19 329.8 rm -f ext/opcache/jit/zend_jit_x86.c +2026-Feb-04 14:33:04.578608 #19 329.8 rm -f ext/opcache/jit/zend_jit_arm64.c +2026-Feb-04 14:33:04.578608 #19 329.8 rm -f ext/opcache/minilua +2026-Feb-04 14:33:04.578608 #19 329.9 Configuring for: +2026-Feb-04 14:33:04.578608 #19 329.9 PHP Api Version: 20220829 +2026-Feb-04 14:33:04.578608 #19 329.9 Zend Module Api No: 20220829 +2026-Feb-04 14:33:04.578608 #19 329.9 Zend Extension Api No: 420220829 +2026-Feb-04 14:33:05.980125 #19 331.3 checking for grep that handles long lines and -e... +2026-Feb-04 14:33:06.103668 /usr/bin/grep +2026-Feb-04 14:33:06.103668 #19 331.3 checking for egrep... /usr/bin/grep -E +2026-Feb-04 14:33:06.103668 #19 331.3 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:33:06.103668 #19 331.3 checking for pkg-config... /usr/bin/pkg-config +2026-Feb-04 14:33:06.103668 #19 331.3 checking pkg-config is at least version 0.9.0... yes +2026-Feb-04 14:33:06.103668 #19 331.3 checking for cc... cc +2026-Feb-04 14:33:06.103668 #19 331.4 checking whether the C compiler works... +2026-Feb-04 14:33:06.259702 yes +2026-Feb-04 14:33:06.259702 #19 331.5 checking for C compiler default output file name... a.out +2026-Feb-04 14:33:06.259702 #19 331.5 checking for suffix of executables... +2026-Feb-04 14:33:06.383758 #19 331.5 checking whether we are cross compiling... no +2026-Feb-04 14:33:06.383758 #19 331.6 checking for suffix of object files... o +2026-Feb-04 14:33:06.544928 #19 331.7 checking whether the compiler supports GNU C... yes +2026-Feb-04 14:33:06.544928 #19 331.7 checking whether cc accepts -g... yes +2026-Feb-04 14:33:06.544928 #19 331.7 checking for cc option to enable C11 features... none needed +2026-Feb-04 14:33:06.658085 #19 331.8 checking how to run the C preprocessor... cc -E +2026-Feb-04 14:33:06.658085 #19 331.9 checking for egrep -e... (cached) /usr/bin/grep -E +2026-Feb-04 14:33:06.658085 #19 331.9 checking for icc... no +2026-Feb-04 14:33:06.759686 #19 331.9 checking for suncc... no +2026-Feb-04 14:33:06.759686 #19 332.0 checking for system library directory... lib +2026-Feb-04 14:33:06.759686 #19 332.0 checking if compiler supports -Wl,-rpath,... yes +2026-Feb-04 14:33:06.759686 #19 332.0 checking build system type... x86_64-pc-linux-gnu +2026-Feb-04 14:33:06.759686 #19 332.0 checking host system type... x86_64-pc-linux-gnu +2026-Feb-04 14:33:06.884702 #19 332.0 checking target system type... x86_64-pc-linux-gnu +2026-Feb-04 14:33:06.884702 #19 332.1 checking for PHP prefix... /usr/local +2026-Feb-04 14:33:06.884702 #19 332.1 checking for PHP includes... -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib +2026-Feb-04 14:33:06.884702 #19 332.1 checking for PHP extension directory... /usr/local/lib/php/extensions/no-debug-non-zts-20220829 +2026-Feb-04 14:33:06.884702 #19 332.1 checking for PHP installed headers prefix... /usr/local/include/php +2026-Feb-04 14:33:06.884702 #19 332.1 checking if debug is enabled... no +2026-Feb-04 14:33:06.884702 #19 332.1 checking if zts is enabled... no +2026-Feb-04 14:33:07.007172 #19 332.2 checking for gawk... no +2026-Feb-04 14:33:07.007172 #19 332.2 checking for nawk... nawk +2026-Feb-04 14:33:07.007172 #19 332.2 checking if nawk is broken... no +2026-Feb-04 14:33:07.007172 #19 332.2 checking for zip archive read/write support... yes, shared +2026-Feb-04 14:33:07.007172 #19 332.2 checking for libzip >= 0.11 libzip != 1.3.1 libzip != 1.7.0... yes +2026-Feb-04 14:33:07.007172 #19 332.2 checking for zip_file_set_mtime in -lzip... yes +2026-Feb-04 14:33:07.126736 #19 332.3 checking for zip_file_set_encryption in -lzip... yes +2026-Feb-04 14:33:07.249609 #19 332.4 checking for zip_libzip_version in -lzip... yes +2026-Feb-04 14:33:07.356440 #19 332.5 checking for zip_register_progress_callback_with_state in -lzip... yes +2026-Feb-04 14:33:07.475504 #19 332.6 checking for zip_register_cancel_callback_with_state in -lzip... yes +2026-Feb-04 14:33:07.587489 #19 332.8 checking for zip_compression_method_supported in -lzip... yes +2026-Feb-04 14:33:07.728995 #19 332.9 checking for a sed that does not truncate output... /usr/bin/sed +2026-Feb-04 14:33:07.728995 #19 332.9 checking for ld used by cc... /usr/bin/ld +2026-Feb-04 14:33:07.728995 #19 332.9 checking if the linker (/usr/bin/ld) is GNU ld... yes +2026-Feb-04 14:33:07.728995 #19 332.9 checking for /usr/bin/ld option to reload object files... -r +2026-Feb-04 14:33:07.728995 #19 332.9 checking for BSD-compatible nm... /usr/bin/nm -B +2026-Feb-04 14:33:07.728995 #19 332.9 checking whether ln -s works... yes +2026-Feb-04 14:33:07.728995 #19 332.9 checking how to recognize dependent libraries... pass_all +2026-Feb-04 14:33:07.728995 #19 332.9 checking for stdio.h... yes +2026-Feb-04 14:33:07.728995 #19 333.0 checking for stdlib.h... yes +2026-Feb-04 14:33:07.728995 #19 333.0 checking for string.h... +2026-Feb-04 14:33:07.859066 yes +2026-Feb-04 14:33:07.859066 #19 333.1 checking for inttypes.h... yes +2026-Feb-04 14:33:07.859066 #19 333.1 checking for stdint.h... yes +2026-Feb-04 14:33:08.004013 #19 333.1 checking for strings.h... yes +2026-Feb-04 14:33:08.004013 #19 333.2 checking for sys/stat.h... yes +2026-Feb-04 14:33:08.004013 #19 333.2 checking for sys/types.h... yes +2026-Feb-04 14:33:08.109601 #19 333.3 checking for unistd.h... yes +2026-Feb-04 14:33:08.109601 #19 333.3 checking for dlfcn.h... yes +2026-Feb-04 14:33:08.253588 #19 333.4 checking the maximum length of command line arguments... 1572864 +2026-Feb-04 14:33:08.253588 #19 333.4 checking command to parse /usr/bin/nm -B output from cc object... ok +2026-Feb-04 14:33:08.253588 #19 333.5 checking for objdir... +2026-Feb-04 14:33:08.378065 .libs +2026-Feb-04 14:33:08.378065 #19 333.5 checking for ar... ar +2026-Feb-04 14:33:08.378065 #19 333.5 checking for ranlib... ranlib +2026-Feb-04 14:33:08.378065 #19 333.5 checking for strip... strip +2026-Feb-04 14:33:08.378065 #19 333.7 checking if cc supports -fno-rtti -fno-exceptions... +2026-Feb-04 14:33:08.596258 no +2026-Feb-04 14:33:08.596258 #19 333.7 checking for cc option to produce PIC... -fPIC +2026-Feb-04 14:33:08.596258 #19 333.7 checking if cc PIC flag -fPIC works... yes +2026-Feb-04 14:33:08.596258 #19 333.7 checking if cc static flag -static works... yes +2026-Feb-04 14:33:08.596258 #19 333.9 checking if cc supports -c -o file.o... +2026-Feb-04 14:33:08.730191 yes +2026-Feb-04 14:33:08.730191 #19 333.9 checking whether the cc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes +2026-Feb-04 14:33:08.730191 #19 334.0 checking whether -lc should be explicitly linked in... no +2026-Feb-04 14:33:08.935254 #19 334.0 checking dynamic linker characteristics... GNU/Linux ld.so +2026-Feb-04 14:33:08.935254 #19 334.0 checking how to hardcode library paths into programs... immediate +2026-Feb-04 14:33:08.935254 #19 334.0 checking whether stripping libraries is possible... yes +2026-Feb-04 14:33:08.935254 #19 334.1 checking if libtool supports shared libraries... yes +2026-Feb-04 14:33:08.935254 #19 334.1 checking whether to build shared libraries... yes +2026-Feb-04 14:33:08.935254 #19 334.1 checking whether to build static libraries... no +2026-Feb-04 14:33:09.156659 #19 334.4 +2026-Feb-04 14:33:09.324311 #19 334.4 creating libtool +2026-Feb-04 14:33:09.324311 #19 334.5 appending configuration tag "CXX" to libtool +2026-Feb-04 14:33:09.324311 #19 334.6 configure: patching config.h.in +2026-Feb-04 14:33:09.447739 #19 334.6 configure: creating ./config.status +2026-Feb-04 14:33:09.447739 #19 334.7 config.status: creating config.h +2026-Feb-04 14:33:09.569627 #19 334.8 /bin/bash /usr/src/php/ext/zip/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/zip -I/usr/src/php/ext/zip/include -I/usr/src/php/ext/zip/main -I/usr/src/php/ext/zip -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/zip/php_zip.c -o php_zip.lo -MMD -MF php_zip.dep -MT php_zip.lo +2026-Feb-04 14:33:09.825103 #19 335.1 mkdir .libs +2026-Feb-04 14:33:09.979584 #19 335.1 cc -I. -I/usr/src/php/ext/zip -I/usr/src/php/ext/zip/include -I/usr/src/php/ext/zip/main -I/usr/src/php/ext/zip -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/zip/php_zip.c -MMD -MF php_zip.dep -MT php_zip.lo -fPIC -DPIC -o .libs/php_zip.o +2026-Feb-04 14:33:11.693238 #19 337.0 /bin/bash /usr/src/php/ext/zip/libtool --tag=CC --mode=compile cc -I. -I/usr/src/php/ext/zip -I/usr/src/php/ext/zip/include -I/usr/src/php/ext/zip/main -I/usr/src/php/ext/zip -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/zip/zip_stream.c -o zip_stream.lo -MMD -MF zip_stream.dep -MT zip_stream.lo +2026-Feb-04 14:33:11.907262 #19 337.2 cc -I. -I/usr/src/php/ext/zip -I/usr/src/php/ext/zip/include -I/usr/src/php/ext/zip/main -I/usr/src/php/ext/zip -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -DZEND_COMPILE_DL_EXT=1 -c /usr/src/php/ext/zip/zip_stream.c -MMD -MF zip_stream.dep -MT zip_stream.lo -fPIC -DPIC -o .libs/zip_stream.o +2026-Feb-04 14:33:12.357243 #19 337.6 /bin/bash /usr/src/php/ext/zip/libtool --tag=CC --mode=link cc -shared -I/usr/src/php/ext/zip/include -I/usr/src/php/ext/zip/main -I/usr/src/php/ext/zip -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DHAVE_CONFIG_H -fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wl,-O1 -pie -o zip.la -export-dynamic -avoid-version -prefer-pic -module -rpath /usr/src/php/ext/zip/modules php_zip.lo zip_stream.lo -lzip +2026-Feb-04 14:33:12.554713 #19 337.8 cc -shared .libs/php_zip.o .libs/zip_stream.o -lzip -Wl,-O1 -Wl,-soname -Wl,zip.so -o .libs/zip.so +2026-Feb-04 14:33:12.668015 #19 337.9 creating zip.la +2026-Feb-04 14:33:12.668015 #19 337.9 (cd .libs && rm -f zip.la && ln -s ../zip.la zip.la) +2026-Feb-04 14:33:12.668015 #19 337.9 /bin/bash /usr/src/php/ext/zip/libtool --tag=CC --mode=install cp ./zip.la /usr/src/php/ext/zip/modules +2026-Feb-04 14:33:12.668015 #19 337.9 cp ./.libs/zip.so /usr/src/php/ext/zip/modules/zip.so +2026-Feb-04 14:33:12.775743 #19 338.0 cp ./.libs/zip.lai /usr/src/php/ext/zip/modules/zip.la +2026-Feb-04 14:33:12.775743 #19 338.0 PATH="$PATH:/sbin" ldconfig -n /usr/src/php/ext/zip/modules +2026-Feb-04 14:33:12.775743 #19 338.0 ---------------------------------------------------------------------- +2026-Feb-04 14:33:12.775743 #19 338.0 Libraries have been installed in: +2026-Feb-04 14:33:12.775743 #19 338.0 /usr/src/php/ext/zip/modules +2026-Feb-04 14:33:12.775743 #19 338.0 +2026-Feb-04 14:33:12.775743 #19 338.0 If you ever happen to want to link against installed libraries +2026-Feb-04 14:33:12.775743 #19 338.0 in a given directory, LIBDIR, you must either use libtool, and +2026-Feb-04 14:33:12.775743 #19 338.0 specify the full pathname of the library, or use the `-LLIBDIR' +2026-Feb-04 14:33:12.775743 #19 338.0 flag during linking and do at least one of the following: +2026-Feb-04 14:33:12.775743 #19 338.0 - add LIBDIR to the `LD_LIBRARY_PATH' environment variable +2026-Feb-04 14:33:12.775743 #19 338.0 during execution +2026-Feb-04 14:33:12.775743 #19 338.0 - add LIBDIR to the `LD_RUN_PATH' environment variable +2026-Feb-04 14:33:12.775743 #19 338.0 during linking +2026-Feb-04 14:33:12.775743 #19 338.0 - use the `-Wl,--rpath -Wl,LIBDIR' linker flag +2026-Feb-04 14:33:12.775743 #19 338.0 - have your system administrator add LIBDIR to `/etc/ld.so.conf' +2026-Feb-04 14:33:12.775743 #19 338.0 +2026-Feb-04 14:33:12.775743 #19 338.0 See any operating system documentation about shared libraries for +2026-Feb-04 14:33:12.775743 #19 338.0 more information, such as the ld(1) and ld.so(8) manual pages. +2026-Feb-04 14:33:12.775743 #19 338.0 ---------------------------------------------------------------------- +2026-Feb-04 14:33:12.775743 #19 338.0 +2026-Feb-04 14:33:12.775743 #19 338.0 Build complete. +2026-Feb-04 14:33:12.775743 #19 338.0 Don't forget to run 'make test'. +2026-Feb-04 14:33:12.775743 #19 338.0 +2026-Feb-04 14:33:12.775743 #19 338.1 + strip --strip-all modules/zip.so +2026-Feb-04 14:33:12.966276 #19 338.1 Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20220829/ +2026-Feb-04 14:33:12.966276 #19 338.2 find . -name \*.gcno -o -name \*.gcda | xargs rm -f +2026-Feb-04 14:33:13.167236 #19 338.3 find . -name \*.lo -o -name \*.o -o -name \*.dep | xargs rm -f +2026-Feb-04 14:33:13.167236 #19 338.3 find . -name \*.la -o -name \*.a | xargs rm -f +2026-Feb-04 14:33:13.167236 #19 338.3 find . -name \*.so | xargs rm -f +2026-Feb-04 14:33:13.167236 #19 338.3 find . -name .libs -a -type d|xargs rm -rf +2026-Feb-04 14:33:13.167236 #19 338.3 rm -f libphp.la modules/* libs/* +2026-Feb-04 14:33:13.167236 #19 338.3 rm -f ext/opcache/jit/zend_jit_x86.c +2026-Feb-04 14:33:13.167236 #19 338.3 rm -f ext/opcache/jit/zend_jit_arm64.c +2026-Feb-04 14:33:13.167236 #19 338.3 rm -f ext/opcache/minilua +2026-Feb-04 14:33:14.000785 #19 339.3 Enabling module rewrite. +2026-Feb-04 14:33:14.174994 #19 339.3 Enabling module headers. +2026-Feb-04 14:33:14.174994 #19 339.3 Enabling module expires. +2026-Feb-04 14:33:14.174994 #19 339.3 To activate the new configuration, you need to run: +2026-Feb-04 14:33:14.174994 #19 339.3 service apache2 restart +2026-Feb-04 14:33:14.248696 #19 DONE 339.5s +2026-Feb-04 14:33:14.406785 #25 [stage-2 4/9] COPY . . +2026-Feb-04 14:33:14.461904 #25 DONE 0.2s +2026-Feb-04 14:33:14.622637 #26 [stage-2 5/9] COPY --from=vendor /var/www/html/vendor ./vendor +2026-Feb-04 14:33:16.497557 #26 DONE 2.0s +2026-Feb-04 14:33:16.658502 #27 [stage-2 6/9] COPY --from=frontend /var/www/html/public/build ./public/build +2026-Feb-04 14:33:16.694691 #27 DONE 0.2s +2026-Feb-04 14:33:16.824954 #28 [stage-2 7/9] COPY docker/apache-vhost.conf /etc/apache2/sites-available/000-default.conf +2026-Feb-04 14:33:16.863241 #28 DONE 0.2s +2026-Feb-04 14:33:16.961686 #29 [stage-2 8/9] COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh +2026-Feb-04 14:33:16.961686 #29 DONE 0.1s +2026-Feb-04 14:33:17.123160 #30 [stage-2 9/9] RUN chmod +x /usr/local/bin/entrypoint.sh && chown -R www-data:www-data storage bootstrap/cache && chmod -R ug+rwx storage bootstrap/cache +2026-Feb-04 14:33:17.568726 #30 DONE 0.6s +2026-Feb-04 14:33:17.722889 #31 exporting to image +2026-Feb-04 14:33:17.722889 #31 exporting layers +2026-Feb-04 14:33:19.621254 #31 exporting layers 2.0s done +2026-Feb-04 14:33:19.846183 #31 writing image sha256:4da632206346e2c290d48bc292e3c9c69b94bb3e917db285bf1a2cf2e088075b done +2026-Feb-04 14:33:19.846183 #31 naming to docker.io/library/p4w4csg8kcocs00s480w40cs_app:26e5da1b8dbeb3065ab56c09dd586329b30b9ba7 0.0s done +2026-Feb-04 14:33:19.846183 #31 DONE 2.1s +2026-Feb-04 14:33:19.880769 #32 resolving provenance for metadata file +2026-Feb-04 14:33:19.919464 #32 DONE 0.0s +2026-Feb-04 14:33:19.953865 app Built +2026-Feb-04 14:33:20.094889 Creating .env file with runtime variables for container. +2026-Feb-04 14:33:21.376994 Removing old containers. +2026-Feb-04 14:33:21.919209 Starting new application. +2026-Feb-04 14:33:24.127080 [CMD]: docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'COOLIFY_BRANCH=main COOLIFY_RESOURCE_UUID=p4w4csg8kcocs00s480w40cs docker compose --env-file /artifacts/w4gkwgg4ccww8oc4s8w0soog/.env --project-name p4w4csg8kcocs00s480w40cs --project-directory /artifacts/w4gkwgg4ccww8oc4s8w0soog -f /artifacts/w4gkwgg4ccww8oc4s8w0soog/docker-compose.yml up -d' +2026-Feb-04 14:33:24.127080 mysql Pulling +2026-Feb-04 14:33:28.625602 c21bb7e51cd3 Pulling fs layer +2026-Feb-04 14:33:28.625602 d9bba75f9c49 Pulling fs layer +2026-Feb-04 14:33:28.625602 d7842cc74782 Pulling fs layer +2026-Feb-04 14:33:28.625602 ce1944d72bca Pulling fs layer +2026-Feb-04 14:33:28.625602 c21ebd7bbded Pulling fs layer +2026-Feb-04 14:33:28.625602 142c5fc9ea8a Pulling fs layer +2026-Feb-04 14:33:28.625602 526dbe6f3591 Pulling fs layer +2026-Feb-04 14:33:28.625602 b05b17de9630 Pulling fs layer +2026-Feb-04 14:33:28.625602 3145e04eb470 Pulling fs layer +2026-Feb-04 14:33:28.625602 f79b7cf07833 Pulling fs layer +2026-Feb-04 14:33:28.625602 b4f9f94601d6 Pulling fs layer +2026-Feb-04 14:33:28.625602 526dbe6f3591 Waiting +2026-Feb-04 14:33:28.678214 b05b17de9630 Waiting +2026-Feb-04 14:33:28.678214 3145e04eb470 Waiting +2026-Feb-04 14:33:28.678214 f79b7cf07833 Waiting +2026-Feb-04 14:33:28.678214 b4f9f94601d6 Waiting +2026-Feb-04 14:33:28.678214 ce1944d72bca Waiting +2026-Feb-04 14:33:28.678214 c21ebd7bbded Waiting +2026-Feb-04 14:33:28.678214 142c5fc9ea8a Waiting +2026-Feb-04 14:33:29.919710 d7842cc74782 Downloading [> ] 9.165kB/783.6kB +2026-Feb-04 14:33:29.957317 d7842cc74782 Verifying Checksum +2026-Feb-04 14:33:29.957317 d7842cc74782 Download complete +2026-Feb-04 14:33:30.025152 d9bba75f9c49 Downloading [==================================================>] 884B/884B +2026-Feb-04 14:33:30.058115 d9bba75f9c49 Verifying Checksum +2026-Feb-04 14:33:30.058115 d9bba75f9c49 Download complete +2026-Feb-04 14:33:30.410695 c21bb7e51cd3 Downloading [> ] 475.1kB/47.31MB +2026-Feb-04 14:33:30.538736 c21bb7e51cd3 Downloading [====> ] 3.817MB/47.31MB +2026-Feb-04 14:33:30.636667 c21bb7e51cd3 Downloading [=======> ] 7.18MB/47.31MB +2026-Feb-04 14:33:30.795144 c21bb7e51cd3 Downloading [=============> ] 12.96MB/47.31MB +2026-Feb-04 14:33:30.899034 c21bb7e51cd3 Downloading [===================> ] 18.22MB/47.31MB +2026-Feb-04 14:33:31.053921 c21bb7e51cd3 Downloading [======================> ] 21.1MB/47.31MB +2026-Feb-04 14:33:31.145568 ce1944d72bca Downloading [> ] 63.22kB/6.175MB +2026-Feb-04 14:33:31.182506 c21bb7e51cd3 Downloading [===========================> ] 25.9MB/47.31MB +2026-Feb-04 14:33:31.222897 ce1944d72bca Downloading [=============================> ] 3.604MB/6.175MB +2026-Feb-04 14:33:31.222897 c21ebd7bbded Downloading [==================> ] 953B/2.608kB +2026-Feb-04 14:33:31.222897 c21ebd7bbded Downloading [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:33:31.222897 c21ebd7bbded Verifying Checksum +2026-Feb-04 14:33:31.222897 c21ebd7bbded Download complete +2026-Feb-04 14:33:31.288284 ce1944d72bca Downloading [==============================================> ] 5.718MB/6.175MB +2026-Feb-04 14:33:31.323051 c21bb7e51cd3 Downloading [===============================> ] 29.72MB/47.31MB +2026-Feb-04 14:33:31.323051 ce1944d72bca Verifying Checksum +2026-Feb-04 14:33:31.323051 ce1944d72bca Download complete +2026-Feb-04 14:33:31.409482 c21bb7e51cd3 Downloading [===================================> ] 34.01MB/47.31MB +2026-Feb-04 14:33:31.527909 c21bb7e51cd3 Downloading [=======================================> ] 37.83MB/47.31MB +2026-Feb-04 14:33:31.650510 c21bb7e51cd3 Downloading [==============================================> ] 43.55MB/47.31MB +2026-Feb-04 14:33:31.761681 c21bb7e51cd3 Downloading [=================================================> ] 46.43MB/47.31MB +2026-Feb-04 14:33:31.802318 c21bb7e51cd3 Verifying Checksum +2026-Feb-04 14:33:31.802318 c21bb7e51cd3 Download complete +2026-Feb-04 14:33:31.840288 c21bb7e51cd3 Extracting [> ] 491.5kB/47.31MB +2026-Feb-04 14:33:31.936746 c21bb7e51cd3 Extracting [=> ] 983kB/47.31MB +2026-Feb-04 14:33:32.046488 c21bb7e51cd3 Extracting [==> ] 2.458MB/47.31MB +2026-Feb-04 14:33:32.183351 c21bb7e51cd3 Extracting [======> ] 6.39MB/47.31MB +2026-Feb-04 14:33:32.305661 142c5fc9ea8a Downloading [==================================================>] 331B/331B +2026-Feb-04 14:33:32.305661 142c5fc9ea8a Verifying Checksum +2026-Feb-04 14:33:32.305661 142c5fc9ea8a Download complete +2026-Feb-04 14:33:32.416049 c21bb7e51cd3 Extracting [=======> ] 7.373MB/47.31MB +2026-Feb-04 14:33:32.522305 c21bb7e51cd3 Extracting [=========> ] 9.339MB/47.31MB +2026-Feb-04 14:33:32.634049 c21bb7e51cd3 Extracting [============> ] 11.8MB/47.31MB +2026-Feb-04 14:33:32.742597 c21bb7e51cd3 Extracting [===============> ] 14.25MB/47.31MB +2026-Feb-04 14:33:32.805858 526dbe6f3591 Downloading [> ] 507.9kB/49.93MB +2026-Feb-04 14:33:32.859109 c21bb7e51cd3 Extracting [===================> ] 18.19MB/47.31MB +2026-Feb-04 14:33:32.898993 b05b17de9630 Downloading [==================================================>] 317B/317B +2026-Feb-04 14:33:32.898993 b05b17de9630 Verifying Checksum +2026-Feb-04 14:33:32.898993 b05b17de9630 Download complete +2026-Feb-04 14:33:32.937590 526dbe6f3591 Downloading [====> ] 4.571MB/49.93MB +2026-Feb-04 14:33:32.975120 c21bb7e51cd3 Extracting [======================> ] 21.63MB/47.31MB +2026-Feb-04 14:33:33.039798 526dbe6f3591 Downloading [===========> ] 11.14MB/49.93MB +2026-Feb-04 14:33:33.081085 c21bb7e51cd3 Extracting [=========================> ] 24.58MB/47.31MB +2026-Feb-04 14:33:33.140892 526dbe6f3591 Downloading [==============> ] 14.17MB/49.93MB +2026-Feb-04 14:33:33.184831 c21bb7e51cd3 Extracting [==============================> ] 28.51MB/47.31MB +2026-Feb-04 14:33:33.250337 526dbe6f3591 Downloading [===================> ] 19.74MB/49.93MB +2026-Feb-04 14:33:33.302787 c21bb7e51cd3 Extracting [================================> ] 30.97MB/47.31MB +2026-Feb-04 14:33:33.353806 526dbe6f3591 Downloading [=====================> ] 21.77MB/49.93MB +2026-Feb-04 14:33:33.421636 c21bb7e51cd3 Extracting [=================================> ] 31.95MB/47.31MB +2026-Feb-04 14:33:33.458754 526dbe6f3591 Downloading [=============================> ] 29.38MB/49.93MB +2026-Feb-04 14:33:33.497013 3145e04eb470 Downloading [> ] 540.7kB/128.1MB +2026-Feb-04 14:33:33.547880 c21bb7e51cd3 Extracting [===================================> ] 33.42MB/47.31MB +2026-Feb-04 14:33:33.607234 526dbe6f3591 Downloading [===============================> ] 31.4MB/49.93MB +2026-Feb-04 14:33:33.651918 c21bb7e51cd3 Extracting [=========================================> ] 38.83MB/47.31MB +2026-Feb-04 14:33:33.651918 3145e04eb470 Downloading [=> ] 2.671MB/128.1MB +2026-Feb-04 14:33:33.707774 526dbe6f3591 Downloading [=====================================> ] 37.47MB/49.93MB +2026-Feb-04 14:33:33.756936 3145e04eb470 Downloading [=> ] 3.736MB/128.1MB +2026-Feb-04 14:33:33.799713 526dbe6f3591 Downloading [========================================> ] 39.98MB/49.93MB +2026-Feb-04 14:33:33.848342 c21bb7e51cd3 Extracting [===========================================> ] 41.29MB/47.31MB +2026-Feb-04 14:33:33.888701 526dbe6f3591 Downloading [===============================================> ] 47.05MB/49.93MB +2026-Feb-04 14:33:33.888701 3145e04eb470 Downloading [=> ] 4.817MB/128.1MB +2026-Feb-04 14:33:33.940837 526dbe6f3591 Download complete +2026-Feb-04 14:33:33.986400 c21bb7e51cd3 Extracting [=============================================> ] 42.76MB/47.31MB +2026-Feb-04 14:33:34.023699 3145e04eb470 Downloading [==> ] 5.898MB/128.1MB +2026-Feb-04 14:33:34.057383 f79b7cf07833 Downloading [============> ] 1.369kB/5.33kB +2026-Feb-04 14:33:34.057383 f79b7cf07833 Download complete +2026-Feb-04 14:33:34.181960 3145e04eb470 Downloading [==> ] 7.512MB/128.1MB +2026-Feb-04 14:33:34.391761 3145e04eb470 Downloading [===> ] 9.126MB/128.1MB +2026-Feb-04 14:33:34.505216 3145e04eb470 Downloading [===> ] 10.21MB/128.1MB +2026-Feb-04 14:33:34.650739 3145e04eb470 Downloading [====> ] 11.27MB/128.1MB +2026-Feb-04 14:33:34.735821 c21bb7e51cd3 Extracting [==============================================> ] 44.24MB/47.31MB +2026-Feb-04 14:33:34.779079 3145e04eb470 Downloading [====> ] 12.34MB/128.1MB +2026-Feb-04 14:33:34.846263 c21bb7e51cd3 Extracting [================================================> ] 46.2MB/47.31MB +2026-Feb-04 14:33:34.891061 3145e04eb470 Downloading [=====> ] 12.88MB/128.1MB +2026-Feb-04 14:33:34.961077 c21bb7e51cd3 Extracting [==================================================>] 47.31MB/47.31MB +2026-Feb-04 14:33:35.035319 3145e04eb470 Downloading [=====> ] 14.48MB/128.1MB +2026-Feb-04 14:33:35.082744 c21bb7e51cd3 Pull complete +2026-Feb-04 14:33:35.082744 d9bba75f9c49 Extracting [==================================================>] 884B/884B +2026-Feb-04 14:33:35.082744 d9bba75f9c49 Extracting [==================================================>] 884B/884B +2026-Feb-04 14:33:35.123903 b4f9f94601d6 Downloading [==================================================>] 122B/122B +2026-Feb-04 14:33:35.123903 b4f9f94601d6 Verifying Checksum +2026-Feb-04 14:33:35.123903 b4f9f94601d6 Download complete +2026-Feb-04 14:33:35.171230 d9bba75f9c49 Pull complete +2026-Feb-04 14:33:35.171230 d7842cc74782 Extracting [==> ] 32.77kB/783.6kB +2026-Feb-04 14:33:35.208160 3145e04eb470 Downloading [======> ] 16.63MB/128.1MB +2026-Feb-04 14:33:35.258313 d7842cc74782 Extracting [==================================================>] 783.6kB/783.6kB +2026-Feb-04 14:33:35.258313 d7842cc74782 Extracting [==================================================>] 783.6kB/783.6kB +2026-Feb-04 14:33:35.309910 d7842cc74782 Pull complete +2026-Feb-04 14:33:35.309910 3145e04eb470 Downloading [=======> ] 18.24MB/128.1MB +2026-Feb-04 14:33:35.309910 ce1944d72bca Extracting [> ] 65.54kB/6.175MB +2026-Feb-04 14:33:35.403154 ce1944d72bca Extracting [============> ] 1.507MB/6.175MB +2026-Feb-04 14:33:35.440980 3145e04eb470 Downloading [=======> ] 19.31MB/128.1MB +2026-Feb-04 14:33:35.505892 ce1944d72bca Extracting [====================> ] 2.49MB/6.175MB +2026-Feb-04 14:33:35.607507 ce1944d72bca Extracting [=================================> ] 4.129MB/6.175MB +2026-Feb-04 14:33:35.607507 3145e04eb470 Downloading [========> ] 20.92MB/128.1MB +2026-Feb-04 14:33:35.678782 ce1944d72bca Extracting [==================================================>] 6.175MB/6.175MB +2026-Feb-04 14:33:35.726142 ce1944d72bca Pull complete +2026-Feb-04 14:33:35.761870 c21ebd7bbded Extracting [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:33:35.761870 c21ebd7bbded Extracting [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:33:35.816467 3145e04eb470 Downloading [========> ] 23.06MB/128.1MB +2026-Feb-04 14:33:35.865600 c21ebd7bbded Pull complete +2026-Feb-04 14:33:35.865600 142c5fc9ea8a Extracting [==================================================>] 331B/331B +2026-Feb-04 14:33:35.865600 142c5fc9ea8a Extracting [==================================================>] 331B/331B +2026-Feb-04 14:33:35.911757 142c5fc9ea8a Pull complete +2026-Feb-04 14:33:35.973348 526dbe6f3591 Extracting [> ] 524.3kB/49.93MB +2026-Feb-04 14:33:36.012373 3145e04eb470 Downloading [=========> ] 24.66MB/128.1MB +2026-Feb-04 14:33:36.077589 526dbe6f3591 Extracting [===> ] 3.67MB/49.93MB +2026-Feb-04 14:33:36.159758 3145e04eb470 Downloading [==========> ] 26.27MB/128.1MB +2026-Feb-04 14:33:36.204803 526dbe6f3591 Extracting [======> ] 6.291MB/49.93MB +2026-Feb-04 14:33:36.276065 3145e04eb470 Downloading [==========> ] 27.88MB/128.1MB +2026-Feb-04 14:33:36.322622 526dbe6f3591 Extracting [========> ] 8.913MB/49.93MB +2026-Feb-04 14:33:36.398587 3145e04eb470 Downloading [===========> ] 28.41MB/128.1MB +2026-Feb-04 14:33:36.450814 526dbe6f3591 Extracting [===========> ] 11.01MB/49.93MB +2026-Feb-04 14:33:36.499284 3145e04eb470 Downloading [===========> ] 30MB/128.1MB +2026-Feb-04 14:33:36.597504 526dbe6f3591 Extracting [=============> ] 13.63MB/49.93MB +2026-Feb-04 14:33:36.654196 3145e04eb470 Downloading [============> ] 31.08MB/128.1MB +2026-Feb-04 14:33:36.710625 526dbe6f3591 Extracting [===============> ] 15.2MB/49.93MB +2026-Feb-04 14:33:36.759788 3145e04eb470 Downloading [============> ] 32.69MB/128.1MB +2026-Feb-04 14:33:36.827070 526dbe6f3591 Extracting [================> ] 16.78MB/49.93MB +2026-Feb-04 14:33:36.881335 3145e04eb470 Downloading [=============> ] 34.31MB/128.1MB +2026-Feb-04 14:33:36.945568 526dbe6f3591 Extracting [=================> ] 17.83MB/49.93MB +2026-Feb-04 14:33:37.015376 3145e04eb470 Downloading [=============> ] 35.39MB/128.1MB +2026-Feb-04 14:33:37.051366 526dbe6f3591 Extracting [===================> ] 19.92MB/49.93MB +2026-Feb-04 14:33:37.104925 3145e04eb470 Downloading [==============> ] 37MB/128.1MB +2026-Feb-04 14:33:37.161874 526dbe6f3591 Extracting [======================> ] 22.02MB/49.93MB +2026-Feb-04 14:33:37.232310 3145e04eb470 Downloading [===============> ] 39.15MB/128.1MB +2026-Feb-04 14:33:37.275030 526dbe6f3591 Extracting [=========================> ] 25.69MB/49.93MB +2026-Feb-04 14:33:37.339644 3145e04eb470 Downloading [===============> ] 39.68MB/128.1MB +2026-Feb-04 14:33:37.395110 526dbe6f3591 Extracting [==============================> ] 30.41MB/49.93MB +2026-Feb-04 14:33:37.472562 3145e04eb470 Downloading [================> ] 41.29MB/128.1MB +2026-Feb-04 14:33:37.510945 526dbe6f3591 Extracting [==================================> ] 34.6MB/49.93MB +2026-Feb-04 14:33:37.593412 3145e04eb470 Downloading [================> ] 42.36MB/128.1MB +2026-Feb-04 14:33:37.652181 526dbe6f3591 Extracting [=====================================> ] 37.75MB/49.93MB +2026-Feb-04 14:33:37.720269 3145e04eb470 Downloading [=================> ] 43.97MB/128.1MB +2026-Feb-04 14:33:37.767969 526dbe6f3591 Extracting [=======================================> ] 39.32MB/49.93MB +2026-Feb-04 14:33:37.821368 3145e04eb470 Downloading [=================> ] 46.11MB/128.1MB +2026-Feb-04 14:33:37.878710 526dbe6f3591 Extracting [==========================================> ] 42.47MB/49.93MB +2026-Feb-04 14:33:37.987984 526dbe6f3591 Extracting [=============================================> ] 45.09MB/49.93MB +2026-Feb-04 14:33:38.025860 3145e04eb470 Downloading [==================> ] 47.19MB/128.1MB +2026-Feb-04 14:33:38.096857 526dbe6f3591 Extracting [===============================================> ] 47.71MB/49.93MB +2026-Feb-04 14:33:38.131692 3145e04eb470 Downloading [===================> ] 48.81MB/128.1MB +2026-Feb-04 14:33:38.273837 526dbe6f3591 Extracting [==================================================>] 49.93MB/49.93MB +2026-Feb-04 14:33:38.273837 3145e04eb470 Downloading [===================> ] 50.94MB/128.1MB +2026-Feb-04 14:33:38.354588 526dbe6f3591 Pull complete +2026-Feb-04 14:33:38.400224 3145e04eb470 Downloading [====================> ] 52.01MB/128.1MB +2026-Feb-04 14:33:38.400224 b05b17de9630 Extracting [==================================================>] 317B/317B +2026-Feb-04 14:33:38.400224 b05b17de9630 Extracting [==================================================>] 317B/317B +2026-Feb-04 14:33:38.444270 b05b17de9630 Pull complete +2026-Feb-04 14:33:38.493179 3145e04eb470 Downloading [====================> ] 53.62MB/128.1MB +2026-Feb-04 14:33:38.594442 3145e04eb470 Downloading [=====================> ] 55.77MB/128.1MB +2026-Feb-04 14:33:38.703150 3145e04eb470 Downloading [======================> ] 56.84MB/128.1MB +2026-Feb-04 14:33:38.838260 3145e04eb470 Downloading [=======================> ] 58.98MB/128.1MB +2026-Feb-04 14:33:38.960399 3145e04eb470 Downloading [=======================> ] 60.05MB/128.1MB +2026-Feb-04 14:33:39.087928 3145e04eb470 Downloading [========================> ] 61.65MB/128.1MB +2026-Feb-04 14:33:39.203313 3145e04eb470 Downloading [=========================> ] 64.32MB/128.1MB +2026-Feb-04 14:33:39.329805 3145e04eb470 Downloading [=========================> ] 64.86MB/128.1MB +2026-Feb-04 14:33:39.508773 3145e04eb470 Downloading [==========================> ] 66.99MB/128.1MB +2026-Feb-04 14:33:39.685320 3145e04eb470 Downloading [===========================> ] 70.21MB/128.1MB +2026-Feb-04 14:33:39.824368 3145e04eb470 Downloading [============================> ] 72.88MB/128.1MB +2026-Feb-04 14:33:39.934644 3145e04eb470 Downloading [=============================> ] 75.02MB/128.1MB +2026-Feb-04 14:33:40.043279 3145e04eb470 Downloading [=============================> ] 76.1MB/128.1MB +2026-Feb-04 14:33:40.197098 3145e04eb470 Downloading [==============================> ] 78.77MB/128.1MB +2026-Feb-04 14:33:40.306886 3145e04eb470 Downloading [===============================> ] 80.91MB/128.1MB +2026-Feb-04 14:33:40.420293 3145e04eb470 Downloading [================================> ] 82.51MB/128.1MB +2026-Feb-04 14:33:40.552246 3145e04eb470 Downloading [================================> ] 84.12MB/128.1MB +2026-Feb-04 14:33:40.656949 3145e04eb470 Downloading [=================================> ] 86.25MB/128.1MB +2026-Feb-04 14:33:40.765098 3145e04eb470 Downloading [==================================> ] 87.85MB/128.1MB +2026-Feb-04 14:33:40.890661 3145e04eb470 Downloading [===================================> ] 89.96MB/128.1MB +2026-Feb-04 14:33:40.991039 3145e04eb470 Downloading [===================================> ] 92.09MB/128.1MB +2026-Feb-04 14:33:41.131222 3145e04eb470 Downloading [====================================> ] 93.16MB/128.1MB +2026-Feb-04 14:33:41.293360 3145e04eb470 Downloading [=====================================> ] 95.31MB/128.1MB +2026-Feb-04 14:33:41.500804 3145e04eb470 Downloading [======================================> ] 97.46MB/128.1MB +2026-Feb-04 14:33:41.618263 3145e04eb470 Downloading [======================================> ] 99.59MB/128.1MB +2026-Feb-04 14:33:41.718620 3145e04eb470 Downloading [=======================================> ] 100.6MB/128.1MB +2026-Feb-04 14:33:41.866141 3145e04eb470 Downloading [========================================> ] 102.8MB/128.1MB +2026-Feb-04 14:33:41.990505 3145e04eb470 Downloading [========================================> ] 104.4MB/128.1MB +2026-Feb-04 14:33:42.113517 3145e04eb470 Downloading [=========================================> ] 105.5MB/128.1MB +2026-Feb-04 14:33:42.217145 3145e04eb470 Downloading [=========================================> ] 107.1MB/128.1MB +2026-Feb-04 14:33:42.331064 3145e04eb470 Downloading [==========================================> ] 108.2MB/128.1MB +2026-Feb-04 14:33:42.431457 3145e04eb470 Downloading [==========================================> ] 109.8MB/128.1MB +2026-Feb-04 14:33:42.566632 3145e04eb470 Downloading [===========================================> ] 110.9MB/128.1MB +2026-Feb-04 14:33:42.708151 3145e04eb470 Downloading [============================================> ] 113MB/128.1MB +2026-Feb-04 14:33:42.827646 3145e04eb470 Downloading [============================================> ] 114.1MB/128.1MB +2026-Feb-04 14:33:42.988341 3145e04eb470 Downloading [=============================================> ] 115.7MB/128.1MB +2026-Feb-04 14:33:43.094525 3145e04eb470 Downloading [=============================================> ] 117.8MB/128.1MB +2026-Feb-04 14:33:43.202066 3145e04eb470 Downloading [==============================================> ] 118.4MB/128.1MB +2026-Feb-04 14:33:43.323118 3145e04eb470 Downloading [==============================================> ] 120MB/128.1MB +2026-Feb-04 14:33:43.436726 3145e04eb470 Downloading [===============================================> ] 121MB/128.1MB +2026-Feb-04 14:33:43.548301 3145e04eb470 Downloading [===============================================> ] 122.6MB/128.1MB +2026-Feb-04 14:33:43.653843 3145e04eb470 Downloading [================================================> ] 124.2MB/128.1MB +2026-Feb-04 14:33:43.809953 3145e04eb470 Downloading [================================================> ] 125.3MB/128.1MB +2026-Feb-04 14:33:43.936879 3145e04eb470 Downloading [=================================================> ] 126.9MB/128.1MB +2026-Feb-04 14:33:44.031954 3145e04eb470 Verifying Checksum +2026-Feb-04 14:33:44.031954 3145e04eb470 Download complete +2026-Feb-04 14:33:44.099296 3145e04eb470 Extracting [> ] 557.1kB/128.1MB +2026-Feb-04 14:33:44.199576 3145e04eb470 Extracting [=> ] 3.899MB/128.1MB +2026-Feb-04 14:33:44.311327 3145e04eb470 Extracting [===> ] 7.799MB/128.1MB +2026-Feb-04 14:33:44.413145 3145e04eb470 Extracting [====> ] 10.58MB/128.1MB +2026-Feb-04 14:33:44.549589 3145e04eb470 Extracting [=====> ] 12.81MB/128.1MB +2026-Feb-04 14:33:44.655514 3145e04eb470 Extracting [=====> ] 15.04MB/128.1MB +2026-Feb-04 14:33:44.792299 3145e04eb470 Extracting [======> ] 17.83MB/128.1MB +2026-Feb-04 14:33:44.923005 3145e04eb470 Extracting [=======> ] 19.5MB/128.1MB +2026-Feb-04 14:33:45.027298 3145e04eb470 Extracting [========> ] 21.73MB/128.1MB +2026-Feb-04 14:33:45.146278 3145e04eb470 Extracting [=========> ] 23.95MB/128.1MB +2026-Feb-04 14:33:45.258982 3145e04eb470 Extracting [=========> ] 25.07MB/128.1MB +2026-Feb-04 14:33:45.394723 3145e04eb470 Extracting [==========> ] 27.85MB/128.1MB +2026-Feb-04 14:33:45.562237 3145e04eb470 Extracting [===========> ] 28.97MB/128.1MB +2026-Feb-04 14:33:45.741667 3145e04eb470 Extracting [============> ] 31.2MB/128.1MB +2026-Feb-04 14:33:45.991007 3145e04eb470 Extracting [============> ] 31.75MB/128.1MB +2026-Feb-04 14:33:46.408571 3145e04eb470 Extracting [============> ] 32.31MB/128.1MB +2026-Feb-04 14:33:46.787598 3145e04eb470 Extracting [============> ] 32.87MB/128.1MB +2026-Feb-04 14:33:47.179561 3145e04eb470 Extracting [=============> ] 33.42MB/128.1MB +2026-Feb-04 14:33:47.579440 3145e04eb470 Extracting [=============> ] 33.98MB/128.1MB +2026-Feb-04 14:33:47.841432 3145e04eb470 Extracting [=============> ] 34.54MB/128.1MB +2026-Feb-04 14:33:48.151557 3145e04eb470 Extracting [=============> ] 35.09MB/128.1MB +2026-Feb-04 14:33:48.434605 3145e04eb470 Extracting [=============> ] 35.65MB/128.1MB +2026-Feb-04 14:33:48.707286 3145e04eb470 Extracting [==============> ] 36.21MB/128.1MB +2026-Feb-04 14:33:49.051008 3145e04eb470 Extracting [==============> ] 36.77MB/128.1MB +2026-Feb-04 14:33:49.291566 3145e04eb470 Extracting [==============> ] 37.32MB/128.1MB +2026-Feb-04 14:33:49.709953 3145e04eb470 Extracting [==============> ] 37.88MB/128.1MB +2026-Feb-04 14:33:50.166122 3145e04eb470 Extracting [===============> ] 38.44MB/128.1MB +2026-Feb-04 14:33:50.519246 3145e04eb470 Extracting [===============> ] 38.99MB/128.1MB +2026-Feb-04 14:33:50.923325 3145e04eb470 Extracting [===============> ] 39.55MB/128.1MB +2026-Feb-04 14:33:51.221078 3145e04eb470 Extracting [===============> ] 40.11MB/128.1MB +2026-Feb-04 14:33:51.483322 3145e04eb470 Extracting [===============> ] 40.67MB/128.1MB +2026-Feb-04 14:33:51.804982 3145e04eb470 Extracting [================> ] 41.22MB/128.1MB +2026-Feb-04 14:33:52.161976 3145e04eb470 Extracting [================> ] 41.78MB/128.1MB +2026-Feb-04 14:33:52.538484 3145e04eb470 Extracting [================> ] 42.34MB/128.1MB +2026-Feb-04 14:33:52.834478 3145e04eb470 Extracting [================> ] 42.89MB/128.1MB +2026-Feb-04 14:33:53.146740 3145e04eb470 Extracting [================> ] 43.45MB/128.1MB +2026-Feb-04 14:33:53.463921 3145e04eb470 Extracting [=================> ] 44.01MB/128.1MB +2026-Feb-04 14:33:53.767385 3145e04eb470 Extracting [=================> ] 44.56MB/128.1MB +2026-Feb-04 14:33:54.092768 3145e04eb470 Extracting [=================> ] 45.12MB/128.1MB +2026-Feb-04 14:33:54.487907 3145e04eb470 Extracting [=================> ] 45.68MB/128.1MB +2026-Feb-04 14:33:54.627880 3145e04eb470 Extracting [==================> ] 46.79MB/128.1MB +2026-Feb-04 14:33:54.728750 3145e04eb470 Extracting [==================> ] 47.35MB/128.1MB +2026-Feb-04 14:33:54.906393 3145e04eb470 Extracting [==================> ] 48.46MB/128.1MB +2026-Feb-04 14:33:55.195206 3145e04eb470 Extracting [===================> ] 49.02MB/128.1MB +2026-Feb-04 14:33:55.329187 3145e04eb470 Extracting [===================> ] 50.14MB/128.1MB +2026-Feb-04 14:33:55.448950 3145e04eb470 Extracting [====================> ] 52.36MB/128.1MB +2026-Feb-04 14:33:55.555545 3145e04eb470 Extracting [=====================> ] 56.26MB/128.1MB +2026-Feb-04 14:33:55.663550 3145e04eb470 Extracting [=======================> ] 59.6MB/128.1MB +2026-Feb-04 14:33:55.766243 3145e04eb470 Extracting [========================> ] 61.83MB/128.1MB +2026-Feb-04 14:33:55.872001 3145e04eb470 Extracting [=========================> ] 64.62MB/128.1MB +2026-Feb-04 14:33:55.974855 3145e04eb470 Extracting [==========================> ] 67.96MB/128.1MB +2026-Feb-04 14:33:56.122388 3145e04eb470 Extracting [===========================> ] 70.75MB/128.1MB +2026-Feb-04 14:33:56.239197 3145e04eb470 Extracting [============================> ] 72.97MB/128.1MB +2026-Feb-04 14:33:56.334391 3145e04eb470 Extracting [=============================> ] 75.76MB/128.1MB +2026-Feb-04 14:33:56.442273 3145e04eb470 Extracting [==============================> ] 79.1MB/128.1MB +2026-Feb-04 14:33:56.552839 3145e04eb470 Extracting [================================> ] 82.44MB/128.1MB +2026-Feb-04 14:33:56.676465 3145e04eb470 Extracting [=================================> ] 84.67MB/128.1MB +2026-Feb-04 14:33:56.778308 3145e04eb470 Extracting [=================================> ] 86.9MB/128.1MB +2026-Feb-04 14:33:56.881652 3145e04eb470 Extracting [==================================> ] 89.13MB/128.1MB +2026-Feb-04 14:33:57.002554 3145e04eb470 Extracting [===================================> ] 90.8MB/128.1MB +2026-Feb-04 14:33:57.136839 3145e04eb470 Extracting [====================================> ] 92.47MB/128.1MB +2026-Feb-04 14:33:57.247066 3145e04eb470 Extracting [====================================> ] 94.7MB/128.1MB +2026-Feb-04 14:33:57.349067 3145e04eb470 Extracting [======================================> ] 98.6MB/128.1MB +2026-Feb-04 14:33:57.457595 3145e04eb470 Extracting [========================================> ] 103.6MB/128.1MB +2026-Feb-04 14:33:57.566295 3145e04eb470 Extracting [=========================================> ] 105.8MB/128.1MB +2026-Feb-04 14:33:57.666293 3145e04eb470 Extracting [===========================================> ] 110.3MB/128.1MB +2026-Feb-04 14:33:57.767878 3145e04eb470 Extracting [=============================================> ] 115.9MB/128.1MB +2026-Feb-04 14:33:57.899358 3145e04eb470 Extracting [===============================================> ] 121.4MB/128.1MB +2026-Feb-04 14:33:58.001803 3145e04eb470 Extracting [================================================> ] 123.1MB/128.1MB +2026-Feb-04 14:33:58.104572 3145e04eb470 Extracting [================================================> ] 125.3MB/128.1MB +2026-Feb-04 14:33:58.185068 3145e04eb470 Extracting [==================================================>] 128.1MB/128.1MB +2026-Feb-04 14:33:58.185068 3145e04eb470 Extracting [==================================================>] 128.1MB/128.1MB +2026-Feb-04 14:33:58.399306 3145e04eb470 Pull complete +2026-Feb-04 14:33:58.447901 f79b7cf07833 Extracting [==================================================>] 5.33kB/5.33kB +2026-Feb-04 14:33:58.447901 f79b7cf07833 Extracting [==================================================>] 5.33kB/5.33kB +2026-Feb-04 14:33:58.497621 f79b7cf07833 Pull complete +2026-Feb-04 14:33:58.541635 b4f9f94601d6 Extracting [==================================================>] 122B/122B +2026-Feb-04 14:33:58.541635 b4f9f94601d6 Extracting [==================================================>] 122B/122B +2026-Feb-04 14:33:58.586657 b4f9f94601d6 Pull complete +2026-Feb-04 14:33:58.647461 mysql Pulled +2026-Feb-04 14:33:58.687700 Volume "p4w4csg8kcocs00s480w40cs_app-storage" Creating +2026-Feb-04 14:33:58.687700 Volume "p4w4csg8kcocs00s480w40cs_app-storage" Created +2026-Feb-04 14:33:58.687700 Volume "p4w4csg8kcocs00s480w40cs_mysql-data" Creating +2026-Feb-04 14:33:58.687700 Volume "p4w4csg8kcocs00s480w40cs_mysql-data" Created +2026-Feb-04 14:33:58.687700 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Creating +2026-Feb-04 14:34:01.231021 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Created +2026-Feb-04 14:34:01.297918 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Creating +2026-Feb-04 14:34:01.461588 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Created +2026-Feb-04 14:34:01.521800 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Starting +2026-Feb-04 14:34:02.259807 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Started +2026-Feb-04 14:34:02.259807 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Waiting +2026-Feb-04 14:34:33.263357 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Healthy +2026-Feb-04 14:34:33.263357 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Starting +2026-Feb-04 14:34:34.020978 Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint app-p4w4csg8kcocs00s480w40cs-142727814627 (55fb03153653172f944b9b47ead20b816a3f8c00a6b3cad069185d7f84a3712e): Bind for 0.0.0.0:8000 failed: port is already allocated +2026-Feb-04 14:34:34.071960 exit status 1 +2026-Feb-04 14:34:34.244441 ======================================== +2026-Feb-04 14:34:34.310472 Deployment failed: Command execution failed (exit code 1): docker exec w4gkwgg4ccww8oc4s8w0soog bash -c 'COOLIFY_BRANCH=main COOLIFY_RESOURCE_UUID=p4w4csg8kcocs00s480w40cs docker compose --env-file /artifacts/w4gkwgg4ccww8oc4s8w0soog/.env --project-name p4w4csg8kcocs00s480w40cs --project-directory /artifacts/w4gkwgg4ccww8oc4s8w0soog -f /artifacts/w4gkwgg4ccww8oc4s8w0soog/docker-compose.yml up -d' +2026-Feb-04 14:34:34.310472 Error: mysql Pulling +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Pulling fs layer +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Pulling fs layer +2026-Feb-04 14:34:34.310472 d7842cc74782 Pulling fs layer +2026-Feb-04 14:34:34.310472 ce1944d72bca Pulling fs layer +2026-Feb-04 14:34:34.310472 c21ebd7bbded Pulling fs layer +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Pulling fs layer +2026-Feb-04 14:34:34.310472 526dbe6f3591 Pulling fs layer +2026-Feb-04 14:34:34.310472 b05b17de9630 Pulling fs layer +2026-Feb-04 14:34:34.310472 3145e04eb470 Pulling fs layer +2026-Feb-04 14:34:34.310472 f79b7cf07833 Pulling fs layer +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Pulling fs layer +2026-Feb-04 14:34:34.310472 526dbe6f3591 Waiting +2026-Feb-04 14:34:34.310472 b05b17de9630 Waiting +2026-Feb-04 14:34:34.310472 3145e04eb470 Waiting +2026-Feb-04 14:34:34.310472 f79b7cf07833 Waiting +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Waiting +2026-Feb-04 14:34:34.310472 ce1944d72bca Waiting +2026-Feb-04 14:34:34.310472 c21ebd7bbded Waiting +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Waiting +2026-Feb-04 14:34:34.310472 d7842cc74782 Downloading [> ] 9.165kB/783.6kB +2026-Feb-04 14:34:34.310472 d7842cc74782 Verifying Checksum +2026-Feb-04 14:34:34.310472 d7842cc74782 Download complete +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Downloading [==================================================>] 884B/884B +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Verifying Checksum +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Download complete +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [> ] 475.1kB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [====> ] 3.817MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [=======> ] 7.18MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [=============> ] 12.96MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [===================> ] 18.22MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [======================> ] 21.1MB/47.31MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Downloading [> ] 63.22kB/6.175MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [===========================> ] 25.9MB/47.31MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Downloading [=============================> ] 3.604MB/6.175MB +2026-Feb-04 14:34:34.310472 c21ebd7bbded Downloading [==================> ] 953B/2.608kB +2026-Feb-04 14:34:34.310472 c21ebd7bbded Downloading [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:34:34.310472 c21ebd7bbded Verifying Checksum +2026-Feb-04 14:34:34.310472 c21ebd7bbded Download complete +2026-Feb-04 14:34:34.310472 ce1944d72bca Downloading [==============================================> ] 5.718MB/6.175MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [===============================> ] 29.72MB/47.31MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Verifying Checksum +2026-Feb-04 14:34:34.310472 ce1944d72bca Download complete +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [===================================> ] 34.01MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [=======================================> ] 37.83MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [==============================================> ] 43.55MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Downloading [=================================================> ] 46.43MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Verifying Checksum +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Download complete +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [> ] 491.5kB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=> ] 983kB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [==> ] 2.458MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [======> ] 6.39MB/47.31MB +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Downloading [==================================================>] 331B/331B +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Verifying Checksum +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Download complete +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=======> ] 7.373MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=========> ] 9.339MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [============> ] 11.8MB/47.31MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [===============> ] 14.25MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [> ] 507.9kB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [===================> ] 18.19MB/47.31MB +2026-Feb-04 14:34:34.310472 b05b17de9630 Downloading [==================================================>] 317B/317B +2026-Feb-04 14:34:34.310472 b05b17de9630 Verifying Checksum +2026-Feb-04 14:34:34.310472 b05b17de9630 Download complete +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [====> ] 4.571MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [======================> ] 21.63MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [===========> ] 11.14MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=========================> ] 24.58MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [==============> ] 14.17MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [==============================> ] 28.51MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [===================> ] 19.74MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [================================> ] 30.97MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [=====================> ] 21.77MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=================================> ] 31.95MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [=============================> ] 29.38MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [> ] 540.7kB/128.1MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [===================================> ] 33.42MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [===============================> ] 31.4MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=========================================> ] 38.83MB/47.31MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=> ] 2.671MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [=====================================> ] 37.47MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=> ] 3.736MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [========================================> ] 39.98MB/49.93MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [===========================================> ] 41.29MB/47.31MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Downloading [===============================================> ] 47.05MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=> ] 4.817MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Download complete +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [=============================================> ] 42.76MB/47.31MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==> ] 5.898MB/128.1MB +2026-Feb-04 14:34:34.310472 f79b7cf07833 Downloading [============> ] 1.369kB/5.33kB +2026-Feb-04 14:34:34.310472 f79b7cf07833 Download complete +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==> ] 7.512MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===> ] 9.126MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===> ] 10.21MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [====> ] 11.27MB/128.1MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [==============================================> ] 44.24MB/47.31MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [====> ] 12.34MB/128.1MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [================================================> ] 46.2MB/47.31MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=====> ] 12.88MB/128.1MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Extracting [==================================================>] 47.31MB/47.31MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=====> ] 14.48MB/128.1MB +2026-Feb-04 14:34:34.310472 c21bb7e51cd3 Pull complete +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Extracting [==================================================>] 884B/884B +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Extracting [==================================================>] 884B/884B +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Downloading [==================================================>] 122B/122B +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Verifying Checksum +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Download complete +2026-Feb-04 14:34:34.310472 d9bba75f9c49 Pull complete +2026-Feb-04 14:34:34.310472 d7842cc74782 Extracting [==> ] 32.77kB/783.6kB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [======> ] 16.63MB/128.1MB +2026-Feb-04 14:34:34.310472 d7842cc74782 Extracting [==================================================>] 783.6kB/783.6kB +2026-Feb-04 14:34:34.310472 d7842cc74782 Extracting [==================================================>] 783.6kB/783.6kB +2026-Feb-04 14:34:34.310472 d7842cc74782 Pull complete +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=======> ] 18.24MB/128.1MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Extracting [> ] 65.54kB/6.175MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Extracting [============> ] 1.507MB/6.175MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=======> ] 19.31MB/128.1MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Extracting [====================> ] 2.49MB/6.175MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Extracting [=================================> ] 4.129MB/6.175MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [========> ] 20.92MB/128.1MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Extracting [==================================================>] 6.175MB/6.175MB +2026-Feb-04 14:34:34.310472 ce1944d72bca Pull complete +2026-Feb-04 14:34:34.310472 c21ebd7bbded Extracting [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:34:34.310472 c21ebd7bbded Extracting [==================================================>] 2.608kB/2.608kB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [========> ] 23.06MB/128.1MB +2026-Feb-04 14:34:34.310472 c21ebd7bbded Pull complete +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Extracting [==================================================>] 331B/331B +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Extracting [==================================================>] 331B/331B +2026-Feb-04 14:34:34.310472 142c5fc9ea8a Pull complete +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [> ] 524.3kB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=========> ] 24.66MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [===> ] 3.67MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==========> ] 26.27MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [======> ] 6.291MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==========> ] 27.88MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [========> ] 8.913MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===========> ] 28.41MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [===========> ] 11.01MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===========> ] 30MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=============> ] 13.63MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [============> ] 31.08MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [===============> ] 15.2MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [============> ] 32.69MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [================> ] 16.78MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============> ] 34.31MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=================> ] 17.83MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============> ] 35.39MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [===================> ] 19.92MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==============> ] 37MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [======================> ] 22.02MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===============> ] 39.15MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=========================> ] 25.69MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===============> ] 39.68MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [==============================> ] 30.41MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================> ] 41.29MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [==================================> ] 34.6MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================> ] 42.36MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=====================================> ] 37.75MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=================> ] 43.97MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=======================================> ] 39.32MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=================> ] 46.11MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [==========================================> ] 42.47MB/49.93MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [=============================================> ] 45.09MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==================> ] 47.19MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [===============================================> ] 47.71MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===================> ] 48.81MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Extracting [==================================================>] 49.93MB/49.93MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===================> ] 50.94MB/128.1MB +2026-Feb-04 14:34:34.310472 526dbe6f3591 Pull complete +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [====================> ] 52.01MB/128.1MB +2026-Feb-04 14:34:34.310472 b05b17de9630 Extracting [==================================================>] 317B/317B +2026-Feb-04 14:34:34.310472 b05b17de9630 Extracting [==================================================>] 317B/317B +2026-Feb-04 14:34:34.310472 b05b17de9630 Pull complete +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [====================> ] 53.62MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=====================> ] 55.77MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [======================> ] 56.84MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=======================> ] 58.98MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=======================> ] 60.05MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [========================> ] 61.65MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=========================> ] 64.32MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=========================> ] 64.86MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==========================> ] 66.99MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===========================> ] 70.21MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [============================> ] 72.88MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============================> ] 75.02MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============================> ] 76.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==============================> ] 78.77MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===============================> ] 80.91MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================================> ] 82.51MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================================> ] 84.12MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=================================> ] 86.25MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==================================> ] 87.85MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===================================> ] 89.96MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===================================> ] 92.09MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [====================================> ] 93.16MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=====================================> ] 95.31MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [======================================> ] 97.46MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [======================================> ] 99.59MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=======================================> ] 100.6MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [========================================> ] 102.8MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [========================================> ] 104.4MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=========================================> ] 105.5MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=========================================> ] 107.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==========================================> ] 108.2MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==========================================> ] 109.8MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===========================================> ] 110.9MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [============================================> ] 113MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [============================================> ] 114.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============================================> ] 115.7MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=============================================> ] 117.8MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==============================================> ] 118.4MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [==============================================> ] 120MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===============================================> ] 121MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [===============================================> ] 122.6MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================================================> ] 124.2MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [================================================> ] 125.3MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Downloading [=================================================> ] 126.9MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Verifying Checksum +2026-Feb-04 14:34:34.310472 3145e04eb470 Download complete +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [> ] 557.1kB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=> ] 3.899MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===> ] 7.799MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [====> ] 10.58MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=====> ] 12.81MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=====> ] 15.04MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [======> ] 17.83MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=======> ] 19.5MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [========> ] 21.73MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=========> ] 23.95MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=========> ] 25.07MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==========> ] 27.85MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===========> ] 28.97MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [============> ] 31.2MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [============> ] 31.75MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [============> ] 32.31MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [============> ] 32.87MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============> ] 33.42MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============> ] 33.98MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============> ] 34.54MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============> ] 35.09MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============> ] 35.65MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==============> ] 36.21MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==============> ] 36.77MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==============> ] 37.32MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==============> ] 37.88MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============> ] 38.44MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============> ] 38.99MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============> ] 39.55MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============> ] 40.11MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============> ] 40.67MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================> ] 41.22MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================> ] 41.78MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================> ] 42.34MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================> ] 42.89MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================> ] 43.45MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================> ] 44.01MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================> ] 44.56MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================> ] 45.12MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================> ] 45.68MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================> ] 46.79MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================> ] 47.35MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================> ] 48.46MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===================> ] 49.02MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===================> ] 50.14MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [====================> ] 52.36MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=====================> ] 56.26MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=======================> ] 59.6MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [========================> ] 61.83MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=========================> ] 64.62MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==========================> ] 67.96MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===========================> ] 70.75MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [============================> ] 72.97MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============================> ] 75.76MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==============================> ] 79.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================================> ] 82.44MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================================> ] 84.67MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=================================> ] 86.9MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================================> ] 89.13MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===================================> ] 90.8MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [====================================> ] 92.47MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [====================================> ] 94.7MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [======================================> ] 98.6MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [========================================> ] 103.6MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=========================================> ] 105.8MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===========================================> ] 110.3MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [=============================================> ] 115.9MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [===============================================> ] 121.4MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================================================> ] 123.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [================================================> ] 125.3MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================================================>] 128.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Extracting [==================================================>] 128.1MB/128.1MB +2026-Feb-04 14:34:34.310472 3145e04eb470 Pull complete +2026-Feb-04 14:34:34.310472 f79b7cf07833 Extracting [==================================================>] 5.33kB/5.33kB +2026-Feb-04 14:34:34.310472 f79b7cf07833 Extracting [==================================================>] 5.33kB/5.33kB +2026-Feb-04 14:34:34.310472 f79b7cf07833 Pull complete +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Extracting [==================================================>] 122B/122B +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Extracting [==================================================>] 122B/122B +2026-Feb-04 14:34:34.310472 b4f9f94601d6 Pull complete +2026-Feb-04 14:34:34.310472 mysql Pulled +2026-Feb-04 14:34:34.310472 Volume "p4w4csg8kcocs00s480w40cs_app-storage" Creating +2026-Feb-04 14:34:34.310472 Volume "p4w4csg8kcocs00s480w40cs_app-storage" Created +2026-Feb-04 14:34:34.310472 Volume "p4w4csg8kcocs00s480w40cs_mysql-data" Creating +2026-Feb-04 14:34:34.310472 Volume "p4w4csg8kcocs00s480w40cs_mysql-data" Created +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Creating +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Created +2026-Feb-04 14:34:34.310472 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Creating +2026-Feb-04 14:34:34.310472 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Created +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Starting +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Started +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Waiting +2026-Feb-04 14:34:34.310472 Container mysql-p4w4csg8kcocs00s480w40cs-142727859689 Healthy +2026-Feb-04 14:34:34.310472 Container app-p4w4csg8kcocs00s480w40cs-142727814627 Starting +2026-Feb-04 14:34:34.310472 Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint app-p4w4csg8kcocs00s480w40cs-142727814627 (55fb03153653172f944b9b47ead20b816a3f8c00a6b3cad069185d7f84a3712e): Bind for 0.0.0.0:8000 failed: port is already allocated +2026-Feb-04 14:34:34.310472 exit status 1 +2026-Feb-04 14:34:34.373070 Error type: RuntimeException +2026-Feb-04 14:34:34.437663 Error code: 0 +2026-Feb-04 14:34:34.497571 Location: /var/www/html/app/Traits/ExecuteRemoteCommand.php:243 +2026-Feb-04 14:34:34.572236 Stack trace (first 5 lines): diff --git a/dewemoji-admin-walkthrough.md b/dewemoji-admin-walkthrough.md new file mode 100644 index 0000000..34ae8ed --- /dev/null +++ b/dewemoji-admin-walkthrough.md @@ -0,0 +1,115 @@ +# Dewemoji Admin Dashboard Walkthrough + +This guide explains how to access and operate the admin dashboard, plus how each section is wired in the current build. + +## Access + +1. Sign in with an admin user (role `admin`). +2. Navigate to `/dashboard/admin/*` routes. +3. The sidebar automatically shows admin navigation when the session user is admin. + +## Admin Sections + +### Analytics + +Route: `/dashboard/admin/analytics` +What it shows: +- User totals, active subscriptions, webhook counts +- Recent webhook events + +Data source: +- Direct database counts via `AdminDashboardController::analytics()` + +### Users + +Route: `/dashboard/admin/users` +What it shows: +- User list (latest 50) +- Filters: search, tier, role +- Inline tier update (free/personal) + +Actions: +- Update tier: POST `/dashboard/admin/users/tier` + +### Subscriptions + +Route: `/dashboard/admin/subscriptions` +What it shows: +- Subscription list (latest 50) +- Grant/revoke forms + +Actions: +- Grant: POST `/dashboard/admin/subscriptions/grant` +- Revoke: POST `/dashboard/admin/subscriptions/revoke` + +Notes: +- Granting an active subscription automatically sets user tier to `personal`. +- Revoking updates the user tier based on remaining active subscriptions. + +### Pricing + +Route: `/dashboard/admin/pricing` +What it shows: +- Pricing plans with editable fields +- Change log (latest 5) + +Actions: +- Update pricing: POST `/dashboard/admin/pricing/update` +- Reset to defaults: POST `/dashboard/admin/pricing/reset` + +Notes: +- Updates are stored in `pricing_plans`. +- Each change logs a snapshot to `pricing_changes`. + +### Webhooks + +Route: `/dashboard/admin/webhooks` +What it shows: +- Recent webhook events (latest 50) +- Replay action per event + +Actions: +- Replay: POST `/dashboard/admin/webhooks/{id}/replay` + +Notes: +- Replay marks the event as `pending`. (Actual processing should be handled by the webhook processor job/worker.) + +### Settings + +Route: `/dashboard/admin/settings` +What it shows: +- Current environment config summaries +- Editable settings for public access + maintenance mode + +Actions: +- Update settings: POST `/dashboard/admin/settings/update` + +Settings stored: +- `maintenance_enabled` (bool) +- `public_enforce` (bool) +- `public_origins` (array) +- `public_extension_ids` (array) +- `public_hourly_limit` (int) + +## Admin Routes Reference + +- GET `/dashboard/admin/analytics` +- GET `/dashboard/admin/users` +- POST `/dashboard/admin/users/tier` +- GET `/dashboard/admin/subscriptions` +- POST `/dashboard/admin/subscriptions/grant` +- POST `/dashboard/admin/subscriptions/revoke` +- GET `/dashboard/admin/pricing` +- POST `/dashboard/admin/pricing/update` +- POST `/dashboard/admin/pricing/reset` +- GET `/dashboard/admin/webhooks` +- POST `/dashboard/admin/webhooks/{id}/replay` +- GET `/dashboard/admin/settings` +- POST `/dashboard/admin/settings/update` + +## Notes for Future Wiring + +- Replace placeholder analytics charts with real metrics/graphs. +- Add pagination + sorting for users, subscriptions, and webhooks. +- Add confirmation dialogs for destructive actions. +- Wire replay to actual processor/job queue if needed. diff --git a/dewemoji-direction-2026.md b/dewemoji-direction-2026.md new file mode 100755 index 0000000..fe934d9 --- /dev/null +++ b/dewemoji-direction-2026.md @@ -0,0 +1,641 @@ +# Dewemoji Product Direction & Strategy Brief + +**Version:** 2.0 +**Date:** February 8, 2026 +**Author:** Dwindi (Project Owner) + +--- + +## Executive Summary + +Dewemoji pivots from a public community-driven emoji dictionary to a **personal emoji library platform** where users build, sync, and own their keyword vocabularies across devices. This eliminates moderation overhead, AI costs, and public abuse risks while monetizing the core unique value: **private, multilingual keyword customization + seamless sync**. + +**New Tagline:** *"Your words → your emojis, anywhere"* + +--- + +## 1. Vision & Mission + +### Vision +Enable everyone to find and use emojis using *their* language, slang, and personal vocabulary—without language barriers or platform limitations. + +### Mission +Provide a semantic emoji discovery platform that: +- Offers unlimited free public search (EN/ID + semantic matching) +- Lets users create private, personal keyword libraries (any language, any script) +- Syncs personal libraries across web, extensions, and future apps +- Removes friction from emoji usage in daily communication + +### Core Problem Being Solved +"I spent too much time finding an emoji because I think in my language/slang ('bekicot' for 🐌), and most tools only understand English keywords." + +--- + +## 2. Strategic Pivot: Why Private-Only Keywords + +### Previous Model (Abandoned) +- Public community keyword submissions +- Voting/moderation for global searchability +- AI moderation for toxicity +- SEO feeding from user keywords + +### Problems with Previous Model +1. **AI moderation costs** haunting scalability +2. **Moral responsibility** for public bad words feeding internet +3. **Unclear monetization** (who pays for emoji stuff?) +4. **Complexity** managing voting, thresholds, public curation + +### New Model (Adopted) +- **Fully private user keyword libraries** +- No public submissions, no voting, no AI moderation +- Users own and control their keywords (stored per account) +- Public search stays free and unlimited (referrer-whitelisted) + +### Benefits +✅ **Zero moderation burden** (private = user's responsibility) +✅ **No AI costs** (no content filtering needed) +✅ **Clear monetization** (pay for personal sync, not public features) +✅ **Moral simplicity** (no liability for user's private words) +✅ **Technical simplicity** (CRUD keywords per user_id) + +--- + +## 3. Monetization Model + +### Core Principle +**"Free discovery → Paid personalization"** + +Users get unlimited free public search to discover and love the product, then upgrade to sync their personal vocabulary. + +### Tiers + +| Feature | Free | Personal ($4.99/mo) | +|---------|------|---------------------| +| **Public emoji search** | ✅ Unlimited (EN/ID keywords) | ✅ Unlimited | +| **Search result limit** | ✅ No limits | ✅ No limits | +| **Skintone variations** | ✅ Free | ✅ Free | +| **Copy to clipboard** | ✅ Free | ✅ Free | +| **Auto-Insert to page** | ✅ Free (viral hook!) | ✅ Free | +| **Automatic mode** | ✅ Free | ✅ Free | +| **Private keywords** | ❌ Not available | ✅ Unlimited CRUD | +| **Keyword sync** | ❌ Not available | ✅ Cross-device/app | +| **API keys** | ❌ Not available | ✅ Generate/revoke | +| **Dashboard access** | ❌ Not available | ✅ Full management | + +### Tier Naming +- **Free** → stays "Free" +- **Pro** → renamed to **"Personal"** (reflects private/personal keywords, not business/pro tools) + +### Pricing Options +- **Monthly:** $4.99/month (Stripe subscription) +- **Annual:** $49/year (~$4.08/month, 17% savings) +- **Lifetime:** $99 (one-time, early adopter offer) + +### Payment Flexibility +Self-generated API keys mean **any payment provider works**: +- Stripe (primary, global) +- Paddle (backup) +- Midtrans/Xendit (Indonesia localization) +- No dependency on Gumroad license keys + +--- + +## 4. Channel Roles & User Flows + +### 4.1 Website (dewemoji.com) + +#### Non-Logged Users +**Purpose:** Free discovery & viral entry point + +**Features:** +- Search emojis by public keywords (EN/ID) +- Browse by category/subcategory +- Copy emojis to clipboard +- View emoji details (unified, codepoints, shortcodes) +- No account required + +**CTA:** "Want your own keywords like 'bekicot'? → Sign Up Free" + +#### Logged Users (Free Account) +**Purpose:** Dashboard teaser + +**Features:** +- View personal keywords section (muted/disabled with upgrade prompt) +- View API keys section (muted/disabled) +- Access to upgrade flow +- Search still unlimited (public keywords) + +**State:** "You have 0 personal keywords. Upgrade to Personal to create unlimited." + +#### Logged Users (Personal Tier) +**Purpose:** Full keyword management hub + +**Features:** +- **Keyword Management:** + - Table view: emoji | your keywords | language | actions (edit/delete) + - Add new keyword: select emoji → enter keyword(s) → set language → save + - Bulk import/export (JSON) +- **API Key Management:** + - Generate new keys (dew_abc123...) + - Revoke keys + - Copy to clipboard (for extension login) + - View usage stats per key (future) +- **Billing Dashboard:** + - Current plan status + - Payment history table (date, amount, status, invoice) + - Upgrade/downgrade/cancel buttons + - Next billing date + +**Navigation:** +``` +Dashboard +├─ Search (always visible) +├─ My Keywords +├─ API Keys +└─ Billing +``` + +--- + +### 4.2 Chrome Extension + +**Purpose:** Viral growth engine + seamless Personal upsell + +#### Free Features (Unlimited, No Limits) +- Search public emoji keywords (EN/ID + semantic) +- Skintone variations +- Copy to clipboard +- **Auto-Insert** (click emoji → inserts at cursor position) +- **Automatic mode** (detect input → insert; else copy) +- No daily/hourly limits +- No login required for public search + +#### Personal Features (Requires Login) +- Search blends **private + public** keywords +- Personal keywords auto-sync from dashboard +- API key authentication (stored securely in chrome.storage) + +#### Auth Flow +1. User clicks "Link Account" in extension settings +2. Login popup (email/password) → POST /v1/user/login +3. Extension receives + stores API key +4. All searches now include Authorization: Bearer header +5. Results blend user's private keywords + public semantic data + +#### Upgrade Prompt +- Trigger: User searches term matching no public results +- Message: "Not found in public keywords. Create 'bekicot → 🐌' in your Personal library?" +- CTA: Opens dewemoji.com/upgrade in new tab + +--- + +### 4.3 API (Backend) + +**Purpose:** Single source of truth for all channels + +#### Public Endpoints (Free, Referrer-Whitelisted) +``` +GET /v1/emojis # Search/browse public keywords +GET /v1/emoji/:slug # Emoji detail +GET /v1/categories # Category list +GET /v1/health # Health check +``` + +**Whitelist Rules:** +- `Origin: https://dewemoji.com` +- `User-Agent: ...chrome-extension://elcikbedkbpkmdhkcmfnkdaacmnpdmha...` +- `Origin: localhost | 127.0.0.1` (dev) + +**Rate Limit:** Soft throttle at 5000 requests/hour/IP (invisible to real users, stops bombers) + +#### User Endpoints (Authentication Required) +``` +POST /v1/user/register # Create account +POST /v1/user/login # Login → returns api_keys +POST /v1/user/logout # Invalidate session +``` + +#### Personal Tier Endpoints (API Key Required) +``` +# Keyword CRUD +GET /v1/keywords # List user's private keywords +POST /v1/keywords # Create/update keyword +DELETE /v1/keywords/:id # Delete keyword +GET /v1/search?private=true # Search (private + public blend) + +# API Key Management +GET /v1/user/apikeys # List user's keys +POST /v1/user/apikeys # Generate new key +DELETE /v1/user/apikeys/:key # Revoke key +``` + +**Authentication:** +- Header: `Authorization: Bearer dew_abc123...` +- Validation: Lookup in `user_api_keys` table → verify user_id has active Personal subscription + +--- + +## 5. Technical Implementation + +### 5.1 Database Schema Changes + +#### New Tables + +```sql +-- Users table +users ( + id UUID PRIMARY KEY, + email VARCHAR UNIQUE NOT NULL, + password_hash VARCHAR NOT NULL, + tier ENUM('free', 'personal') DEFAULT 'free', + created_at TIMESTAMP, + updated_at TIMESTAMP +) + +-- API keys table +user_api_keys ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users(id), + key VARCHAR(64) UNIQUE NOT NULL, -- e.g., dew_abc123... + name VARCHAR(100), -- optional label + created_at TIMESTAMP, + last_used_at TIMESTAMP, + revoked_at TIMESTAMP NULL +) + +-- Private keywords table +user_keywords ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users(id), + emoji_slug VARCHAR NOT NULL, -- references existing emoji dataset + keyword VARCHAR(200) NOT NULL, + lang VARCHAR(10) NOT NULL, -- ISO code or 'slang' + created_at TIMESTAMP, + updated_at TIMESTAMP, + UNIQUE(user_id, emoji_slug, keyword) +) + +-- Subscriptions table (for billing) +subscriptions ( + id UUID PRIMARY KEY, + user_id UUID REFERENCES users(id), + plan VARCHAR(20), -- 'monthly', 'annual', 'lifetime' + status ENUM('active', 'canceled', 'expired'), + started_at TIMESTAMP, + expires_at TIMESTAMP NULL, + stripe_subscription_id VARCHAR NULL +) +``` + +### 5.2 API Validation Flow + +**For Public Endpoints:** +``` +1. Check Origin/Referer/User-Agent +2. If whitelisted → allow unlimited +3. Else → require valid API key (Personal tier) +4. Apply soft IP throttle (5000/hour) +``` + +**For Personal Endpoints:** +``` +1. Extract Authorization: Bearer +2. Lookup key in user_api_keys (not revoked) +3. Lookup user_id → verify subscriptions.status = 'active' +4. If valid → proceed +5. Else → 401 Unauthorized +``` + +### 5.3 Search Logic (Private + Public Blend) + +**Endpoint:** `GET /v1/search?q=bekicot&private=true` + +**Algorithm:** +``` +1. If private=true and valid API key: + a. Query user_keywords WHERE user_id=X AND keyword LIKE '%bekicot%' + b. Query public emojis.json WHERE keywords LIKE '%bekicot%' + c. Merge results (private first, then public) + d. Deduplicate by emoji_slug + +2. If private=false or no API key: + a. Query public emojis.json only + +3. Return unified response +``` + +### 5.4 API Key Generation + +**Format:** `dew_{random_32_chars}` + +**Example:** `dew_k7j3m9q2n8p4r6s1t5v8w0x2y4z7a9c1` + +**Generation:** +```php +function generateApiKey() { + return 'dew_' . bin2hex(random_bytes(16)); +} +``` + +**Storage:** Hashed (bcrypt) or plain (with secure storage + HTTPS) + +--- + +## 6. Migration Strategy + +### Phase 1: Foundation (Week 1-2) +**Backend:** +- [ ] Create database tables (users, user_api_keys, user_keywords, subscriptions) +- [ ] Build auth endpoints (register, login, logout) +- [ ] Build API key CRUD endpoints +- [ ] Build private keyword CRUD endpoints +- [ ] Implement referrer whitelisting logic +- [ ] Update search endpoint to blend private + public + +**Frontend (Website):** +- [ ] Build registration/login UI +- [ ] Build dashboard with tabs (Keywords, API Keys, Billing) +- [ ] Build keyword management table (CRUD interface) +- [ ] Build API key management UI +- [ ] Add upgrade CTAs for free users + +**Testing:** +- [ ] Test auth flow +- [ ] Test keyword CRUD +- [ ] Test search blending (private + public) +- [ ] Test referrer whitelisting + +### Phase 2: Extension Integration (Week 3) +**Extension Update:** +- [ ] Add "Link Account" button in settings +- [ ] Build login popup (OAuth-style or simple form) +- [ ] Store API key in chrome.storage.sync +- [ ] Update search to send Authorization header when logged in +- [ ] Update UI to show "Signed in as {email}" +- [ ] Add logout button +- [ ] Add upgrade prompt on private keyword miss + +**Testing:** +- [ ] Test login flow from extension +- [ ] Test private keyword search from extension +- [ ] Test auto-insert with private keywords +- [ ] Test logout/revoke flow + +### Phase 3: Payment Integration (Week 4) +**Stripe Setup:** +- [ ] Create Stripe products (Monthly, Annual, Lifetime) +- [ ] Build checkout flow (dewemoji.com/upgrade) +- [ ] Build webhook handler (subscription created/updated/canceled) +- [ ] Update subscriptions table on payment events +- [ ] Build billing dashboard (payment history, cancel) + +**Testing:** +- [ ] Test full upgrade flow (free → Personal) +- [ ] Test subscription renewal +- [ ] Test cancellation +- [ ] Test lifetime purchase + +### Phase 4: Deprecation of Gumroad (Optional) +- [ ] Add migration tool for existing Gumroad license holders +- [ ] Offer 1-click conversion: paste license key → create account → auto-upgrade to Personal +- [ ] Send email to existing users with migration instructions +- [ ] Set sunset date for Gumroad validation (e.g., 90 days) + +--- + +## 7. Changes Required to Current Site + +### Homepage (dewemoji.com) +**Current:** General emoji search + copy +**Required Changes:** +- [ ] Add hero section: "Find emojis in *your* language. Add personal keywords like 'bekicot' → 🐌" +- [ ] Add CTA: "Search Free" + "Create Personal Library" +- [ ] Add feature comparison table (Free vs Personal) +- [ ] Update footer: Add "Pricing", "Dashboard", "API Docs" + +### Search Page +**Current:** Public search only +**Required Changes:** +- [ ] No changes for non-logged users +- [ ] For logged Personal users: blend private keywords in results +- [ ] Add badge on results: "Your keyword" vs "Public keyword" +- [ ] Add "Edit keyword" quick action on personal results + +### Emoji Detail Page +**Current:** Shows public keywords, metadata +**Required Changes:** +- [ ] Add "Add to my keywords" button (Personal users only) +- [ ] Quick add modal: "What do you call this? → [input] → Save" +- [ ] Show user's private keywords for this emoji (if any) +- [ ] Remove voting/public submission UI (deprecated) + +### New Pages to Build + +#### `/register` +- Email + password form +- "Continue with Google" (optional, future) +- Terms acceptance +- Auto-login after registration + +#### `/login` +- Email + password +- "Forgot password" link +- Redirect to dashboard after login + +#### `/dashboard` +**Tabs:** +1. **My Keywords** (default) + - Table: Emoji | Keywords | Language | Actions + - Add button → modal (search emoji → add keyword) + - Bulk import/export buttons + +2. **API Keys** + - List of keys with names + last used + - Generate button → creates new key + - Copy button + revoke button per key + +3. **Billing** + - Current plan badge + - Next billing date + - Payment history table + - Upgrade/downgrade/cancel buttons + +#### `/upgrade` or `/pricing` +- Feature comparison table (Free vs Personal) +- Pricing cards (Monthly $4.99 | Annual $49 | Lifetime $99) +- Stripe checkout integration +- FAQ section + +--- + +## 8. Marketing & Positioning + +### Target Audiences + +**Primary:** +1. **Multilingual communicators** (Indonesian, Korean, Japanese, etc.) + - Problem: "Emoji pickers don't understand my language" + - Hook: "Search in bahasa Indonesia: 'bekicot' → 🐌" + +2. **Heavy messengers** (WhatsApp, Discord, Twitter power users) + - Problem: "I use emojis 50+ times/day, default pickers suck" + - Hook: "Auto-insert emojis anywhere, instantly" + +3. **Content creators & social media managers** + - Problem: "Need specific emojis fast, can't waste time scrolling" + - Hook: "Your custom emoji library, synced everywhere" + +**Secondary:** +1. Developers needing semantic emoji API +2. Writers using emojis in documentation +3. Non-Latin language communities (Korean, Japanese, Russian) + +### Positioning Statements + +**For Indonesian users:** +*"Dewemoji adalah library emoji pribadi yang ngerti bahasa lo—dari 'bekicot' sampe slang gaul, semua bisa jadi shortcut emoji lo."* + +**For global users:** +*"Your personal emoji dictionary that speaks your language—sync your custom keywords across all your devices."* + +**For Chrome Web Store:** +*"Emoji search that understands you. Add personal keywords like 'snail' or 'bekicot'—works anywhere, syncs everywhere."* + +### Growth Channels + +1. **Chrome Web Store** + - Current: Already live (https://chromewebstore.google.com/detail/dewemoji...) + - Action: Update description with Personal tier benefits + - Strategy: Drive reviews via in-extension prompt ("Enjoying Dewemoji? Rate us!") + +2. **Indonesian tech communities** + - Reddit: r/indonesia, r/indonesian + - Kaskus, Discord servers (DevID, IndieHackers Indonesia) + - Messaging: "Finally, emoji search yang ngerti bahasa kita" + +3. **Product Hunt launch** + - Position: "Personal emoji library with multilingual keyword search" + - Hook: "Stop scrolling through emoji pickers—search in your language" + +4. **Twitter/X shares** + - User screenshots: "Look, I can search 'bekicot' now!" + - Developer shares: "Semantic emoji API that understands Indonesian slang" + +5. **SEO (organic)** + - Target: "emoji search [language]", "emoji picker indonesia", "find emoji by keyword" + - Content: Blog posts on emoji localization, multilingual search + +--- + +## 9. Success Metrics + +### Growth Metrics +- **Extension installs/month:** Target 1,000 → 10,000 in 6 months +- **Website MAU:** Target 5,000 → 50,000 in 6 months +- **Free → Personal conversion:** Target 2-5% (industry standard) + +### Revenue Metrics +- **MRR (Monthly Recurring Revenue):** Target $500 → $5,000 in 6 months +- **Annual plan adoption:** Target 30% of paid users +- **Lifetime purchases:** Target 10% of paid users + +### Usage Metrics +- **Avg searches/user/day:** Track engagement depth +- **Private keywords created/user:** Measure feature adoption +- **API key active usage:** Track cross-device sync adoption + +### Quality Metrics +- **Extension rating:** Maintain >4.5 stars +- **User retention (30-day):** Target >40% +- **Churn rate:** Target <10%/month for Personal tier + +--- + +## 10. Risks & Mitigation + +### Risk 1: Low conversion (free → Personal) +**Mitigation:** +- Make free tier extremely generous (unlimited searches, all features except private) +- Add in-context upgrade prompts ("Not found. Create this keyword in Personal?") +- Offer 7-day free trial on Personal tier + +### Risk 2: API abuse (free tier bombing) +**Mitigation:** +- Referrer whitelisting (already planned) +- Soft IP throttle (5000/hour) +- Monitor usage patterns; tighten if needed + +### Risk 3: Low awareness ("Who needs emoji search?") +**Mitigation:** +- Target pain-aware users (multilingual, heavy messengers) +- Leverage Chrome Web Store (existing 237M Chrome users search "emoji") +- Create viral hooks (screenshot-worthy Indonesian keyword searches) + +### Risk 4: Payment processor issues (Indonesia) +**Mitigation:** +- Start with Stripe (global, easiest) +- Add Midtrans/Xendit for local payment methods (bank transfer, e-wallet) +- Offer annual/lifetime for users without recurring billing access + +--- + +## 11. Next Steps (Immediate Actions) + +### Week 1: Backend Foundation +1. Design & implement database schema +2. Build auth system (register, login, JWT/session) +3. Build API key generation/validation +4. Build private keyword CRUD endpoints +5. Update search endpoint to blend private + public + +### Week 2: Frontend Dashboard +1. Build registration/login pages +2. Build dashboard layout (tabs: Keywords, API Keys, Billing) +3. Build keyword management table + CRUD UI +4. Build API key management UI +5. Add upgrade CTAs throughout free tier + +### Week 3: Extension Integration +1. Add "Link Account" in extension settings +2. Build login popup for extension +3. Store API key securely (chrome.storage) +4. Update search to send auth header when logged in +5. Add upgrade prompt on private keyword miss + +### Week 4: Payment & Launch +1. Set up Stripe products (Monthly, Annual, Lifetime) +2. Build checkout flow + webhook handler +3. Build billing dashboard +4. Test full user journey (register → add keywords → login in extension → search) +5. Soft launch to existing users + Indonesian tech communities + +--- + +## 12. Appendix: Key Decisions Made + +| Decision | Rationale | +|----------|-----------| +| **Private-only keywords (no public)** | Eliminates moderation costs, AI costs, legal risks, complexity | +| **Free unlimited public search** | Drives viral growth; users fall in love before paywall | +| **Auto-Insert free (not paid)** | Core viral hook; competitors lack this, users share screenshots | +| **Tier renamed: Pro → Personal** | "Personal" clarifies it's private keywords, not business tools | +| **Self-generated API keys** | Flexibility with any payment provider (Stripe, Paddle, local) | +| **Referrer whitelisting for free** | Protects API from abuse without limiting real users | +| **No search count limits** | Emoji tools die with limits; unlimited = frictionless growth | +| **Payment: $4.99/mo or $49/yr** | Coffee price for individuals; low friction, high volume model | + +--- + +## 13. Questions for Future Consideration + +1. **Team libraries:** Should Personal tier allow shared keyword libraries (e.g., family/team)? +2. **Mobile apps:** Native iOS/Android apps or continue web + extension focus? +3. **API marketplace:** Offer public API access for developers (separate paid tier)? +4. **Localization:** Add more default language packs (Korean, Japanese, Spanish)? +5. **AI assistance:** "Suggest keywords for this emoji based on my usage patterns"? + +--- + +**End of Brief** + +This document serves as the north star for Dewemoji's development through 2026. All implementation decisions should align with the principle: **"Free discovery → Paid personalization"** and the vision of enabling personal, multilingual emoji expression for everyone. \ No newline at end of file diff --git a/dewemoji-extension-notes.md b/dewemoji-extension-notes.md new file mode 100644 index 0000000..b59acdf --- /dev/null +++ b/dewemoji-extension-notes.md @@ -0,0 +1,64 @@ +# Dewemoji Extension Notes / To-Do + +## Context (Why paused) +- GCM token registration appears blocked or flaky in unpacked mode. +- Diagnostics show: token missing + "Asynchronous operation is pending". +- Likely need Web Store (unlisted) install to validate GCM/FCM end-to-end. + +--- + +## Priority A — GCM / Token +- Verify GCM/FCM token registration in a Web Store (unlisted) install. +- Confirm sender/project ID consistency across manifest + backend. +- Add dev-mode fallback token for local testing (unpacked). +- Add clear UI guidance when token missing (ex: “Unpacked builds may not support GCM”). +- Add retry + backoff messaging for token refresh. + +## Priority B — Diagnostics +- Keep diagnostics visible in settings (done). +- Add “Force token refresh” with timeout (done). +- Add copy-to-clipboard for diagnostics output. +- Show last error + timestamp (done). +- Add quick “Open service worker console” helper link (optional). + +## Priority C — License & Pro +- Verify license activation/deactivation flow with real API. +- Implement `/license/deactivate` endpoint and wire client. +- Add graceful handling for license server downtime. +- Confirm Pro actions (insert/auto) are blocked for free users. + +## Priority D — Insert / Auto +- Validate content script injection across common sites. +- Improve detection when no editable element exists. +- Add clearer user feedback when insert fails. + +## Priority E — Search / Performance +- Confirm caching + paging behavior is correct. +- Ensure auto-load sentinel doesn’t duplicate results. +- Test daily usage cap flow (free users). + +## Priority F — Tone UX +- Validate tone lock + preferred tone across sessions. +- Confirm policy list coverage vs Unicode updates. +- Accessibility checks for tone picker controls. + +## Priority G — UI / UX Polish +- Improve keyboard navigation in settings. +- Add tooltips for Pro features + diagnostics. +- Ensure error banners are theme-consistent. + +## Priority H — Release / Packaging +- Create unlisted Web Store listing for real-world testing. +- Document packaging flow + PEM usage for stable extension ID. +- Add release checklist (build, test, upload, verify). + +## Priority I — Security / Privacy +- Verify minimum permissions in `manifest.json`. +- Document local vs sync data storage. + +--- + +## Notes / Observations +- Unpacked installs often can’t obtain GCM tokens. +- CRX install is blocked by Chrome unless via Web Store. + diff --git a/dewemoji-ux-flow-brief.md b/dewemoji-ux-flow-brief.md new file mode 100755 index 0000000..7abbe55 --- /dev/null +++ b/dewemoji-ux-flow-brief.md @@ -0,0 +1,873 @@ +# Dewemoji User Flow & UX Brief + +**Version:** 1.0 +**Date:** February 8, 2026 +**Purpose:** Define seamless user experience across visitor → logged → paid states +**Related Doc:** dewemoji-direction-2026.md + +--- + +## Executive Summary + +Dewemoji implements a **hybrid quick-add flow** where Personal users can add keywords instantly from emoji detail pages (80% of use cases) while maintaining full CRUD power in the dashboard (20% management). This creates a frictionless progression: discovery → personalization → habit, without disrupting the free user experience. + +**Core UX Principle:** *"Add keywords where you discover emojis, manage them where you organize."* + +--- + +## 1. User State Definitions + +### 1.1 Visitor (Non-Logged) +**Who:** Anyone landing on dewemoji.com or using Chrome extension (no account) +**Intent:** Quick emoji search and usage +**Experience:** Zero friction, no login walls + +### 1.2 Free User (Logged, No Subscription) +**Who:** Registered account, free tier +**Intent:** Exploring Personal features, considering upgrade +**Experience:** Full free features + gentle upgrade hints + +### 1.3 Personal User (Logged, Paid) +**Who:** Active Personal subscription ($4.99/mo, $49/yr, or $99 lifetime) +**Intent:** Building and syncing personal keyword library +**Experience:** Full personalization power across all touchpoints + +--- + +## 2. Primary User Flows + +### 2.1 Discovery Flow (All Users) + +``` +User lands on dewemoji.com + ↓ +Search bar: "bekicot" + ↓ +Results page: 🐌 snail (public keywords: "snail, escargot") + ↓ +Click emoji → Detail page + ↓ +[State-dependent experience - see Section 3] +``` + +**Key Insight:** All users start here. Free discovery hooks them; Personal lets them own it. + +--- + +### 2.2 Personalization Flow (Personal Users) + +#### Primary: Quick Add from Detail Page (80% Usage) + +``` +Personal user searches "snail" + ↓ +Detail page shows: +┌─────────────────────────────────────┐ +│ 🐌 Snail │ +│ │ +│ Public Keywords: snail, escargot │ +│ │ +│ Your Keywords: (none yet) │ +│ [+ Add Your Keyword] │ +└─────────────────────────────────────┘ + ↓ +User clicks [+ Add Your Keyword] + ↓ +Inline modal appears: +┌─────────────────────────────────────┐ +│ What do you call this emoji? │ +│ ┌─────────────────────────────────┐│ +│ │ bekicot, siput ││ +│ └─────────────────────────────────┘│ +│ Language: [Indonesian ▾] │ +│ [Cancel] [Save Keyword] │ +└─────────────────────────────────────┘ + ↓ +Saves instantly → Toast: "Added 'bekicot' to your library ✓" + ↓ +Detail page now shows: +┌─────────────────────────────────────┐ +│ 🐌 Snail │ +│ │ +│ Public Keywords: snail, escargot │ +│ │ +│ Your Keywords: │ +│ • bekicot (ID) [edit] [×] │ +│ • siput (ID) [edit] [×] │ +│ [+ Add Another] │ +└─────────────────────────────────────┘ + ↓ +Next search: "bekicot" → 🐌 appears in results! +``` + +**Why This Flow:** +- **Contextual:** User is *already looking at* the emoji they want to name +- **Fast:** 2 clicks (add button → save), ~5 seconds total +- **Immediate gratification:** See change instantly in searches +- **Low friction:** No navigation away from discovery flow + +--- + +#### Secondary: Dashboard Management (20% Usage) + +**When Used:** +- Bulk editing/organizing keywords +- Reviewing all keywords at once +- Exporting/importing keyword libraries +- Fixing typos across multiple entries + +``` +User navigates to Dashboard → My Keywords tab + ↓ +Table view: +┌───────────────────────────────────────────────────────────┐ +│ Emoji | Your Keywords | Lang | Actions │ +├───────────────────────────────────────────────────────────┤ +│ 🐌 | bekicot, siput | ID | [Edit] [Delete] │ +│ 😊 | senyum, happy | ID | [Edit] [Delete] │ +│ 🔥 | api, fire, lit | ID | [Edit] [Delete] │ +└───────────────────────────────────────────────────────────┘ +[+ Add Keyword] [Import JSON] [Export JSON] [Search/Filter] + ↓ +User clicks [+ Add Keyword] + ↓ +Modal: Search emoji picker → Select 🎉 → Add keywords + ↓ +Saves to table → Auto-sync to extension +``` + +**Why Dashboard Exists:** +- Power users want bulk operations +- Easy to review/audit entire library +- Import/export for backup +- Edit mistakes without finding emoji again + +--- + +### 2.3 Upgrade Flow (Free → Personal) + +#### Trigger Points + +**1. On Detail Page (Soft Prompt)** +``` +Free user on emoji detail page sees: +┌─────────────────────────────────────┐ +│ 🐌 Snail │ +│ │ +│ Public Keywords: snail, escargot │ +│ │ +│ 💎 Want to add your own keywords? │ +│ like 'bekicot' or 'siput'? │ +│ [Upgrade to Personal →] │ +└─────────────────────────────────────┘ +``` + +**2. On Search Miss (Strong Prompt)** +``` +User searches "bekicot" → No results + ↓ +Results page shows: +┌─────────────────────────────────────┐ +│ No results for "bekicot" │ +│ │ +│ 💡 With Personal, you can create │ +│ "bekicot → 🐌" and sync it │ +│ everywhere. │ +│ [Try Personal Free for 7 Days] │ +└─────────────────────────────────────┘ +``` + +**3. From Extension (Contextual)** +``` +Extension user searches "bekicot" → Not found + ↓ +Extension shows inline banner: +"Add 'bekicot' to your library with Personal" +[Upgrade] button → Opens dewemoji.com/upgrade +``` + +**4. From Dashboard (Clear Path)** +``` +Free user clicks "My Keywords" tab + ↓ +Shows empty state: +┌─────────────────────────────────────┐ +│ 📚 Your Personal Keyword Library │ +│ │ +│ You have 0 keywords. │ +│ │ +│ Upgrade to Personal to: │ +│ ✓ Add unlimited keywords │ +│ ✓ Search in your language │ +│ ✓ Sync across all devices │ +│ │ +│ [Start 7-Day Free Trial] │ +└─────────────────────────────────────┘ +``` + +--- + +## 3. State-Dependent UI Elements + +### 3.1 Emoji Detail Page + +#### Visitor (Non-Logged) +```html + +
+

🐌 Snail

+
+

Keywords

+
    +
  • snail
  • +
  • escargot
  • +
  • slow
  • +
+
+ +
+

💡 Want to search in your language?

+ +
+
+``` + +#### Free User (Logged) +```html + +
+

🐌 Snail

+ +
+

Keywords

+
  • snail
  • escargot
+
+ +
+

Your Keywords

+
+

💎 Add personal keywords like 'bekicot'

+ +
+
+
+``` + +#### Personal User (Logged + Paid) +```html + +
+

🐌 Snail

+ +
+

Public Keywords

+
  • snail
  • escargot
  • slow
+
+ +
+

Your Keywords

+
    +
  • + bekicot + ID + + +
  • +
  • + siput + ID + + +
  • +
+ +
+
+ + + +

What do you call this emoji?

+ + + +
+``` + +--- + +### 3.2 Search Results Page + +#### All Users (Public Results) +```html +
+
+ 🐌 + Snail + snail +
+
+``` + +#### Personal User (Blended Results) +```html +
+ +
+ 🐌 + Snail + + bekicot + Your keyword + + +
+ + +
+ 🐌 + Snail + snail +
+
+``` + +--- + +### 3.3 Dashboard (Personal Users Only) + +```html +
+ + + +
+
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
EmojiYour KeywordsLanguageActions
🐌bekicot, siputID + + +
+
+
+``` + +--- + +## 4. API Endpoints for UX Flows + +### 4.1 Detail Page Quick Add + +**Fetch user's keywords for specific emoji:** +``` +GET /v1/emoji/:slug?include_user_keywords=true +Authorization: Bearer dew_abc123... + +Response: +{ + "emoji": {...}, + "public_keywords": ["snail", "escargot"], + "user_keywords": [ + {"id": "uk_1", "keyword": "bekicot", "lang": "id"}, + {"id": "uk_2", "keyword": "siput", "lang": "id"} + ] +} +``` + +**Add keyword from detail page:** +``` +POST /v1/keywords/quick +Authorization: Bearer dew_abc123... + +Body: +{ + "emoji_slug": "snail", + "keywords": ["bekicot", "siput"], + "lang": "id" +} + +Response: +{ + "success": true, + "added": ["bekicot", "siput"], + "emoji_slug": "snail" +} +``` + +**Edit single keyword:** +``` +PATCH /v1/keywords/:id +Authorization: Bearer dew_abc123... + +Body: +{ + "keyword": "bekicot kecil" +} +``` + +**Delete keyword:** +``` +DELETE /v1/keywords/:id +Authorization: Bearer dew_abc123... +``` + +--- + +### 4.2 Dashboard Bulk Operations + +**List all user keywords:** +``` +GET /v1/keywords?page=1&limit=50 +Authorization: Bearer dew_abc123... + +Response: +{ + "keywords": [ + { + "id": "uk_1", + "emoji_slug": "snail", + "emoji": "🐌", + "keyword": "bekicot", + "lang": "id", + "created_at": "2026-02-08T10:30:00Z" + } + // ... more + ], + "total": 47, + "page": 1 +} +``` + +**Bulk import:** +``` +POST /v1/keywords/import +Authorization: Bearer dew_abc123... + +Body: +{ + "keywords": [ + {"emoji_slug": "snail", "keywords": ["bekicot"], "lang": "id"}, + {"emoji_slug": "fire", "keywords": ["api"], "lang": "id"} + ] +} + +Response: +{ + "imported": 2, + "skipped": 0, + "errors": [] +} +``` + +**Export:** +``` +GET /v1/keywords/export?format=json +Authorization: Bearer dew_abc123... + +Response: (Download JSON file) +``` + +--- + +## 5. Frontend Implementation Specs + +### 5.1 Emoji Detail Page Changes + +**File:** `/pages/emoji/[slug].js` (or equivalent) + +**Required Elements:** + +1. **User keywords section** (Personal only) + - Fetch on page load: `GET /v1/emoji/:slug?include_user_keywords=true` + - Show list of user's keywords with edit/delete buttons + - Show "Add Keyword" button + +2. **Add keyword modal** + - Input: comma-separated keywords + - Dropdown: language selector (EN, ID, KO, JA, etc.) + - Save button → POST `/v1/keywords/quick` + - Success → update UI without page reload + +3. **Inline edit** + - Click "edit" → input becomes editable + - Save → PATCH `/v1/keywords/:id` + - Cancel → revert + +4. **Inline delete** + - Click "×" → confirm modal + - Yes → DELETE `/v1/keywords/:id` → remove from UI + +**State Management:** +```javascript +const [userKeywords, setUserKeywords] = useState([]); +const [isPersonal, setIsPersonal] = useState(false); + +// On mount +useEffect(() => { + if (user?.tier === 'personal') { + fetchUserKeywords(emojiSlug); + } +}, [emojiSlug, user]); + +// Add keyword +const handleAddKeyword = async (keywords, lang) => { + const result = await api.post('/keywords/quick', { + emoji_slug: emojiSlug, + keywords: keywords.split(',').map(k => k.trim()), + lang + }); + + if (result.success) { + fetchUserKeywords(emojiSlug); // Refresh list + toast.success('Keywords added!'); + } +}; +``` + +--- + +### 5.2 Dashboard Implementation + +**File:** `/pages/dashboard.js` + +**Tabs:** +1. My Keywords (default) +2. API Keys +3. Billing + +**My Keywords Tab Components:** + +```javascript +// Main table component + + +// Toolbar actions + + + + + + + +// Add keyword modal (with emoji picker) + +``` + +**Features:** +- Pagination (50 per page) +- Search/filter by keyword or emoji +- Bulk select + delete +- Sort by: date added, emoji name, language + +--- + +### 5.3 Upgrade Flow Pages + +**File:** `/pages/upgrade.js` or `/pages/pricing.js` + +**Components:** + +1. **Feature comparison table** + ```html + + + + + + + + + + + + + + + + + +
FeatureFreePersonal
Public emoji search✅ Unlimited✅ Unlimited
Private keywords✅ Unlimited
+ ``` + +2. **Pricing cards** + ```html +
+
+

Monthly

+

$4.99/mo

+ +
+ +
+

Lifetime

+

$99 once

+ +
+
+ ``` + +3. **Stripe checkout integration** + ```javascript + const handleCheckout = async (plan) => { + const session = await api.post('/stripe/checkout', { + plan, // 'monthly' | 'annual' | 'lifetime' + success_url: `${baseUrl}/dashboard?upgraded=true`, + cancel_url: `${baseUrl}/upgrade` + }); + + window.location.href = session.url; + }; + ``` + +--- + +## 6. UX Copy & Messaging + +### 6.1 Upgrade Prompts + +**Soft (Detail Page):** +> 💡 Want to search in your language? Add personal keywords like 'bekicot' for 🐌 +> [Upgrade to Personal →] + +**Strong (Search Miss):** +> No results for "bekicot" +> +> 💎 **Create your own keywords with Personal** +> Add "bekicot → 🐌" and sync it across all devices +> [Try Free for 7 Days] + +**Empty State (Dashboard):** +> 📚 **Your Personal Keyword Library** +> +> You have 0 keywords. +> +> Upgrade to Personal to: +> ✓ Add unlimited keywords +> ✓ Search in your language +> ✓ Sync across all devices +> +> [Start 7-Day Free Trial] + +--- + +### 6.2 Success Messages + +**After adding keyword:** +> ✓ Added "bekicot" to your library + +**After editing:** +> ✓ Keyword updated + +**After deleting:** +> ✓ Keyword removed + +**After upgrade:** +> 🎉 Welcome to Personal! Start adding your keywords. + +--- + +### 6.3 Error Messages + +**Duplicate keyword:** +> ⚠️ You already have "bekicot" for this emoji + +**Network error:** +> ❌ Couldn't save. Check your connection and try again. + +**Unauthorized:** +> 🔒 Please log in to add personal keywords + +--- + +## 7. Mobile Considerations + +### 7.1 Detail Page on Mobile + +- Add keyword button: **sticky bottom bar** (always visible) +- Modal: **full-screen** on mobile (easier typing) +- Keyword list: **swipeable cards** (swipe left to delete) + +### 7.2 Dashboard on Mobile + +- Tabs: **horizontal scroll** or bottom nav +- Table: **card view** (stack columns vertically) +- Actions: **swipe gestures** (edit/delete) + +--- + +## 8. Performance & Optimization + +### 8.1 Caching Strategy + +**Client-side:** +- Cache user keywords in localStorage/sessionStorage +- Only refetch when: + - User adds/edits/deletes + - Page reload after 5 minutes + +**API-side:** +- ETag support (already implemented) +- Cache user keywords per user_id (Redis) +- Invalidate on mutation + +### 8.2 Loading States + +**Detail page:** +``` +Loading user keywords... +└─ Skeleton: [▯▯▯▯] [▯▯▯] [▯▯▯▯▯] +``` + +**Dashboard:** +``` +Loading your library... +└─ Table skeleton (5 rows) +``` + +--- + +## 9. Analytics & Tracking + +### Key Events to Track + +**Discovery:** +- `emoji_viewed` (slug, user_tier) +- `public_search` (query, has_results) +- `search_miss` (query) → upgrade opportunity + +**Personalization:** +- `keyword_added` (method: 'quick_add' | 'dashboard') +- `keyword_edited` +- `keyword_deleted` +- `keywords_exported` + +**Conversion:** +- `upgrade_prompt_shown` (location: 'detail' | 'search' | 'dashboard') +- `upgrade_clicked` (location) +- `trial_started` +- `subscription_created` (plan: 'monthly' | 'annual' | 'lifetime') + +**Usage:** +- `private_keyword_searched` (query, has_results) +- `extension_synced` (keyword_count) + +--- + +## 10. Testing Checklist + +### 10.1 User State Tests + +- [ ] Visitor can search and view emoji details (no login) +- [ ] Visitor sees upgrade CTA (non-intrusive) +- [ ] Free user sees muted keyword section +- [ ] Free user can't add keywords without upgrade +- [ ] Personal user sees active keyword section +- [ ] Personal user can add keywords from detail page +- [ ] Personal user can edit/delete keywords inline + +### 10.2 Flow Tests + +- [ ] Quick add: add keyword → appears in list immediately +- [ ] Quick add: new keyword searchable instantly +- [ ] Dashboard: bulk add works correctly +- [ ] Dashboard: export downloads valid JSON +- [ ] Dashboard: import restores keywords +- [ ] Search: private keywords appear first in results +- [ ] Search: private keywords have "Your keyword" badge + +### 10.3 Edge Cases + +- [ ] Add duplicate keyword → shows error +- [ ] Delete last keyword for emoji → removes emoji from search +- [ ] Offline: queue mutations, sync when online +- [ ] Rate limit: show friendly error +- [ ] API error: show retry option + +--- + +## 11. Implementation Priority + +### Phase 1: Detail Page Quick Add (Week 1) +1. Add user keywords section to detail page +2. Build add keyword modal +3. Implement POST /keywords/quick endpoint +4. Add inline edit/delete + +### Phase 2: Search Blending (Week 1) +1. Update search to blend private + public +2. Add "Your keyword" badge to results +3. Show private matches first + +### Phase 3: Dashboard (Week 2) +1. Build My Keywords tab with table +2. Add bulk actions (import/export) +3. Implement search/filter + +### Phase 4: Upgrade Flow (Week 2) +1. Build upgrade prompts (detail, search miss, dashboard) +2. Create pricing page +3. Integrate Stripe checkout + +--- + +## 12. Open Questions & Future Enhancements + +1. **Keyword suggestions:** Should we suggest keywords based on emoji name/category? +2. **Keyboard shortcuts:** Quick add keyword with hotkey (Ctrl+K)? +3. **Recently added:** Show "Recently added keywords" widget on dashboard? +4. **Keyword collections:** Group keywords by category/theme? +5. **Sharing:** Allow users to share their keyword libraries with friends? + +--- + +**End of UX Brief** + +This document defines the seamless user experience for Dewemoji's core value proposition: instant, contextual personalization. Implementation should prioritize the detail page quick-add flow (80% of usage) while building dashboard for power users (20%). \ No newline at end of file diff --git a/env-migration-checklist.md b/env-migration-checklist.md new file mode 100644 index 0000000..ee2a9a5 --- /dev/null +++ b/env-migration-checklist.md @@ -0,0 +1,117 @@ +# .env Migration Checklist + +Use this to map legacy `dewemoji-live-backend/public_html/config/env.php` into NativePHP app `app/.env`. + +## 1) Local development (safe default) + +```env +APP_ENV=local +APP_DEBUG=true +APP_URL=http://127.0.0.1:8000 + +DB_CONNECTION=sqlite + +DEWEMOJI_BILLING_MODE=sandbox +DEWEMOJI_LICENSE_ACCEPT_ALL=false +DEWEMOJI_PRO_KEYS= + +DEWEMOJI_ALLOWED_ORIGINS=http://127.0.0.1:8000,http://localhost:8000 +DEWEMOJI_FRONTEND_HEADER=web-v1 +DEWEMOJI_FREE_DAILY_LIMIT=30 + +DEWEMOJI_GUMROAD_ENABLED=false +DEWEMOJI_MAYAR_ENABLED=false +``` + +## 2) Staging (real provider test) + +```env +APP_ENV=staging +APP_DEBUG=false +APP_URL=https://staging.your-domain.com + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=dewemojiAPI_DB +DB_USERNAME=... +DB_PASSWORD=... + +DEWEMOJI_BILLING_MODE=live +DEWEMOJI_LICENSE_ACCEPT_ALL=false +DEWEMOJI_PRO_KEYS= + +DEWEMOJI_ALLOWED_ORIGINS=https://staging.your-domain.com,https://dewemoji.com,https://www.dewemoji.com,https://emoji.dewe.pw +DEWEMOJI_FRONTEND_HEADER=web-v1 +DEWEMOJI_FREE_DAILY_LIMIT=30 + +DEWEMOJI_GUMROAD_ENABLED=true +DEWEMOJI_GUMROAD_VERIFY_URL=https://api.gumroad.com/v2/licenses/verify +DEWEMOJI_GUMROAD_PRODUCT_IDS=qfvcuT7RwcDn5Oi4KQcOBQ==,t8Kq1G5wzrd1KcYOgukpzw== + +DEWEMOJI_MAYAR_ENABLED=true +DEWEMOJI_MAYAR_API_BASE=https://api.mayar.id +DEWEMOJI_MAYAR_ENDPOINT_VERIFY=/v1/license/verify +DEWEMOJI_MAYAR_SECRET_KEY=... +``` + +## 3) Production + +```env +APP_ENV=production +APP_DEBUG=false +APP_URL=https://dewemoji.com + +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=dewemojiAPI_DB +DB_USERNAME=... +DB_PASSWORD=... + +DEWEMOJI_BILLING_MODE=live +DEWEMOJI_LICENSE_ACCEPT_ALL=false +DEWEMOJI_PRO_KEYS= + +DEWEMOJI_ALLOWED_ORIGINS=https://dewemoji.com,https://www.dewemoji.com +DEWEMOJI_FRONTEND_HEADER=web-v1 +DEWEMOJI_FREE_DAILY_LIMIT=30 + +DEWEMOJI_GUMROAD_ENABLED=true +DEWEMOJI_GUMROAD_VERIFY_URL=https://api.gumroad.com/v2/licenses/verify +DEWEMOJI_GUMROAD_PRODUCT_IDS=qfvcuT7RwcDn5Oi4KQcOBQ==,t8Kq1G5wzrd1KcYOgukpzw== + +DEWEMOJI_MAYAR_ENABLED=true +DEWEMOJI_MAYAR_API_BASE=https://api.mayar.id +DEWEMOJI_MAYAR_ENDPOINT_VERIFY=/v1/license/verify +DEWEMOJI_MAYAR_SECRET_KEY=... +``` + +## 4) Legacy -> NativePHP key map + +- `gateway_mode` -> `DEWEMOJI_BILLING_MODE` +- `allowed_origins[]` -> `DEWEMOJI_ALLOWED_ORIGINS` (comma-separated) +- `frontend_header` -> `DEWEMOJI_FRONTEND_HEADER` +- `free_daily_limit` -> `DEWEMOJI_FREE_DAILY_LIMIT` +- `gumroad.product_ids[]` -> `DEWEMOJI_GUMROAD_PRODUCT_IDS` (comma-separated) +- `gumroad.verify_url` -> `DEWEMOJI_GUMROAD_VERIFY_URL` +- `mayar.api_base` -> `DEWEMOJI_MAYAR_API_BASE` +- `mayar.endpoint_verify` -> `DEWEMOJI_MAYAR_ENDPOINT_VERIFY` +- `mayar.secret_key` -> `DEWEMOJI_MAYAR_SECRET_KEY` + +## 5) Final checks + +1. Run: `php artisan config:clear` +2. Run: `php artisan migrate --force` +3. Test verify endpoint with real key (Gumroad and Mayar) +4. Confirm `/v1/license/activate` + `/v1/license/deactivate` +5. Confirm frontend pages: `/`, `/browse`, `/support`, `/pricing`, `/api-docs` + +## 6) Security note + +Legacy `env.php` contains exposed secrets. Rotate all production credentials before final cutover: +- DB password +- Mayar key +- Turnstile keys +- OpenRouter key +- Redis password diff --git a/rebuild-progress.md b/rebuild-progress.md index c1817cc..6862001 100644 --- a/rebuild-progress.md +++ b/rebuild-progress.md @@ -43,7 +43,7 @@ - [x] Implement `GET /v1/categories`. - [x] Implement `POST /v1/license/verify` (temporary env-based validation). - [x] Support both `q` and `query`. -- [ ] Add/verify full response contract parity with live docs (`variants`, `related`, trimmed `keywords_en`, limit behavior by tier). +- [x] Add/verify full response contract parity with live docs (`variants`, `related`, trimmed `keywords_en`, limit behavior by tier). - [x] Match live cache/rate semantics baseline (`page=1` metering behavior, 401/429 payload shape, ETag/304 behavior). - [x] Verify header compatibility baseline: `Authorization`, `X-License-Key`, `X-Account-Id`, `X-Dewemoji-Frontend`, `X-Dewemoji-Tier`. - [x] Restrict CORS to configured origins (no default `*`). @@ -63,9 +63,9 @@ - [x] Keep URL behavior parity (canonical no-trailing-slash pages, redirect rules, pretty-to-query hydration). - [x] no-trailing-slash redirect middleware and canonical link baseline implemented. - [x] pretty route hydration wired into homepage initial filters + URL sync. -- [ ] Port homepage behavior parity: +- [x] Port homepage behavior parity: - API-backed filters (`q`, category, subcategory), URL sync, load-more pagination. - - API fallback when scoped search returns 0 (retry on `all` + hint). + - [ ] API fallback when scoped search returns 0 (retry on `all` + hint). - [ ] Port single emoji page parity: - 404 `noindex` for missing. - 410 + `X-Robots-Tag: noindex, noarchive` for policy-hidden emoji. @@ -73,17 +73,17 @@ - related fallback (same subcategory), prev/next navigation. - details blocks: aliases, shortcodes, EN/ID keywords, copy interactions. - curated blurbs support from `data/emoji_descriptions.json`. -- [ ] Port legal/support content parity and FAQ schema blocks. +- [x] Port legal/support content parity and FAQ schema blocks. ### Phase 4 - Pricing and payments -- [ ] Keep pricing structure parity: +- [x] Keep pricing structure parity: - Free, Pro subscription, Lifetime. - Pro: `$3/mo` and yearly display `$27/yr` in UI. - Lifetime: `$69`. -- [ ] Preserve live Gumroad links: +- [x] Preserve live Gumroad links: - `https://dwindown.gumroad.com/l/dewemoji-pro-subscription` - `https://dwindown.gumroad.com/l/dewemoji-pro-lifetime` -- [ ] Keep IDR/Mayar messaging parity (manual-renew note). +- [x] Keep IDR/Mayar messaging parity (manual-renew note). - [ ] Implement real license lifecycle (activate/deactivate/verify + max 3 Chrome profiles) in new backend. - [x] Implement real license lifecycle baseline in rebuild (`verify/activate/deactivate`, immutable owner binding behavior, max device cap). - [ ] Implement provider verification parity: @@ -92,10 +92,10 @@ - [x] Gumroad verify API flow (final payload/contract parity with live provider account) - [x] Mayar verify API flow (final payload/contract parity with live provider account) - gateway mode switch (`sandbox` vs `live`) -- [ ] Implement immutable license binding to user + multi-device activation policy parity. +- [x] Implement immutable license binding to user + multi-device activation policy parity. ### Phase 5 - SEO parity (must not disrupt GSC) -- [ ] Preserve canonical strategy for all pages (including emoji detail + pretty category pages). +- [x] Preserve canonical strategy for all pages (including emoji detail + pretty category pages). - [x] Add/verify meta + social tags parity baseline: title/description/OG/Twitter + theme color. - [ ] Port JSON-LD strategy: - [x] Global `WebSite` + `SearchAction` + Organization. @@ -105,12 +105,13 @@ - [x] `CreativeWork` + `BreadcrumbList` baseline on emoji pages. - [x] Implement `robots.txt` parity and dynamic `sitemap.xml` baseline. - [x] Ensure sitemap excludes policy-hidden emoji URLs (same filter policy as live). -- [ ] Keep core indexed URLs stable: `/`, `/pricing`, `/api-docs`, `/support`, `/privacy`, `/terms`, `/emoji/{slug}`. +- [x] Keep core indexed URLs stable: `/`, `/pricing`, `/api-docs`, `/support`, `/privacy`, `/terms`, `/emoji/{slug}`. ### Phase 6 - Analytics, consent, and compliance - [ ] Re-implement cookie consent flow before analytics activation. - [ ] Re-implement GA4 only on allowed production hosts (live uses `G-R7FYYRBVJK`). - [ ] Keep privacy/terms statements aligned with live content. + - [ ] Add light/dark mode toggle in UI (persist user preference). ### Phase 7 - Data/ops pipelines - [ ] Port blurb pipeline: @@ -124,6 +125,12 @@ - Keywords index build (`build_keywords_json_from_sql.php`) - Unicode parity validation (`validate_emojis_against_unicode.php`) - License expiry revocation cron (`check_license_expiry.php`) + - [x] Added live SQL import command for app DB (`php artisan dewemoji:import-live-sql`). + - [x] Added legacy table migrations + JSON normalization for import. + - [ ] Port legacy JSON generator as Laravel command (cache-first strategy): + - Source: `dewemoji-live-backend/jobs/build_emojis_json_from_sql.php` + - Output: `app/data/emojis.json` (default API dataset) + - [ ] Add scheduled task (Coolify) for JSON rebuild (daily or on-demand). ### Phase 8 - Community feature migration - [ ] Port contributor auth flow: @@ -159,6 +166,7 @@ - [ ] Add deployment runbook with minimum required env vars and health verification steps. - [ ] Add post-deploy smoke checks (`/`, `/v1/health`, `/v1/emojis`, `/robots.txt`, `/sitemap.xml`). - [x] Add container healthcheck for app service using `/v1/health`. + - [x] Staging data sync validated using R2 upload + import flow. ## Recent implementation update @@ -197,10 +205,22 @@ - Added billing provider hardening: - Gumroad: validate `is_valid`, reject refunded/chargebacked purchases, preserve product-id matching. - Mayar: broaden request payload compatibility, normalize multiple response shapes, optional product-id allowlist (`DEWEMOJI_MAYAR_PRODUCT_IDS`). +- Added live SQL import tooling: + - New migrations for legacy tables + import service + - JSON normalization for legacy `meta_json`/`payload`/`raw_response` fields +- API list responses now always include `plan` for pro/free tests. - Added SEO polish: - Global JSON-LD for `WebSite`, `SearchAction`, and `Organization` in shared layout. - Static `public/robots.txt` now explicitly allows crawling and exposes sitemap URL. +## Cache strategy decision (open) + +- Current API reads from `app/data/emojis.json`. +- Live legacy server regenerates that JSON from MySQL via cron: + - `dewemoji-live-backend/jobs/build_emojis_json_from_sql.php` +- Recommendation: keep JSON cache (fast + stable) and port the generator into Laravel, + then schedule it in Coolify (daily or on-demand). + ## Live audit highlights (reference) - Live web routes in `dewemoji-live/public_html`: `/`, `/emoji/{slug}`, `/browse`, `/pricing`, `/api-docs`, `/support`, `/privacy`, `/terms`, `/sitemap.xml`. diff --git a/redirection-dewemoji-plan.md b/redirection-dewemoji-plan.md new file mode 100644 index 0000000..0dfb662 --- /dev/null +++ b/redirection-dewemoji-plan.md @@ -0,0 +1,188 @@ +# Redirection Plan — Dewemoji Pivot (2026) + +**Source of truth:** `dewemoji-direction-2026.md` (Feb 8, 2026) + +This document maps the **2026 pivot** (“personal emoji library + sync”) against what we have **already built** in the rebuild app, then defines a concrete redirection plan. + +--- + +## 1) Pivot Summary (as confirmed) + +**New product north star:** +- Dewemoji is a **personal emoji library**. +- Users create private keywords in any language (including slang and non‑Latin scripts), sync across devices, and **own their vocabulary**. +- Public discovery remains free (EN/ID + semantic) as a growth engine. +- No public/community submissions → no moderation burden. + +**Monetization shift:** +- Free: public search only. +- Paid: private keyword library + sync + API keys + dashboard. +- Rename **Pro → Personal**. + +--- + +## 2) What We’ve Already Built (Current State) + +### ✅ Built & aligned +- Public emoji discovery (JSON dataset, EN + ID keywords). +- API endpoints: `/v1/emojis`, `/v1/categories`, `/v1/emoji`, `/v1/health`. +- Frontend search + browse + emoji detail pages. +- Basic SEO + sitemap + robots. +- License verification/activation endpoints (legacy‑style) and supporting services. +- The rebuild is already cache‑first (`app/data/emojis.json`). + +### ⚠️ Built but **misaligned** with pivot +- **License‑based Pro system** (Gumroad/Mayar validation). +- **Device activation** + license tables intended for legacy Pro (not Personal plan). +- “Pro” pricing page and marketing copy (old pricing, old narrative). +- API docs + support pages referencing license key flow. + +### ❌ Not built yet (required by pivot) +- User accounts (register/login/session). +- Personal tier subscription model (Stripe + subscriptions table). +- API key management tied to user (generate/revoke). +- Private keyword CRUD (user keywords table). +- Personal dashboard (keywords, API keys, billing). +- Extension account linking + private keyword sync. +- Public endpoint whitelisting (origin + extension UA) + soft throttling. + +--- + +## 3) Directional Conflicts to Resolve + +| Area | Current | Pivot Requirement | Decision | +|------|---------|------------------|----------| +| Monetization | Pro license keys | Personal subscription | **Replace** license key system with account + API key model | +| Identity | None | User accounts | **Add** auth system + dashboard | +| Keywords | Public only | Private per user | **Add** `user_keywords` + blended search | +| API Access | License key | User API keys | **Replace** authorization method | +| Community | Planned public contributions | Private‑only | **Remove** community feature scope | +| Pricing | $3/mo + $27/yr + $69 lifetime | $4.99/mo + $49/yr + $99 lifetime | **Update** pricing + copy | + +--- + +## 4) Redirection Plan (Phased) + +### Phase A — Foundation (Backend) ✅ *Start here* +Goal: replace license model with **account + API key** architecture. + +**Backend tasks** +- Add tables: `users`, `user_api_keys`, `user_keywords`, `subscriptions`. +- Add auth endpoints: + - `POST /v1/user/register` + - `POST /v1/user/login` + - `POST /v1/user/logout` +- Add API key endpoints: + - `GET /v1/user/apikeys` + - `POST /v1/user/apikeys` + - `DELETE /v1/user/apikeys/:key` +- Add private keyword endpoints: + - `GET /v1/keywords` + - `POST /v1/keywords` + - `DELETE /v1/keywords/:id` +- Add `GET /v1/search?private=true` to **blend private + public** results. +- Implement **origin/UA whitelist** for public endpoints and soft throttling. + +**What to freeze** +- Legacy license endpoints stay online temporarily but **deprecated**. +- No new features on Gumroad/Mayar flow. + +--- + +### Phase B — Dashboard UI (Web) +Goal: provide a **personal workspace** for private keywords and API keys. + +**Frontend tasks** +- Add `/register`, `/login`, `/dashboard`. +- Dashboard tabs: + - **My Keywords** (CRUD, bulk import/export) + - **API Keys** (generate/revoke) + - **Billing** (plan status, upgrade links) +- Update emoji detail page: + - “Add to My Keywords” for Personal users. + - Show personal keywords for this emoji (if any). + +--- + +### Phase C — Extension Integration +Goal: enable personal keywords in extension + sync. + +**Extension tasks** +- “Link Account” flow in extension. +- Store API key in `chrome.storage.sync`. +- Include `Authorization: Bearer dew_…` header when logged in. +- Blend private + public results. +- Upgrade prompt on missing keyword: “Create this in Personal?” + +--- + +### Phase D — Payments + Plan Rename +Goal: Personal tier + billing system. + +**Billing tasks** +- PayPal subscription plan (Monthly/Annual) + webhook handler. +- Keep pricing **admin‑controlled** (see Admin Dashboard plan). +- Webhooks → populate `subscriptions`. +- Plan rename everywhere: **Pro → Personal**. +- Pricing page update. + +--- + +### Phase E — Deprecate Legacy Licenses +Goal: cut off old Gumroad model cleanly. + +**Migration tasks** +- “Paste license → auto‑create account → grant Personal (lifetime)” tool. +- Email existing license users. +- Sunset date for legacy validation. + +--- + +## 5) Immediate File Updates (Recommended Next) + +- Update **API docs** to mention account/API keys (not licenses). +- Update **Pricing page** to Personal tier and new price points. +- Update **Support/Terms/Privacy** copy with Personal tier language. +- Update **community-plan.md** (already aligned with private‑only direction). + +--- + +## 6) Risk Notes + +- The pivot **removes public contribution features** and their associated moderation burden. This is consistent with the new revenue model but changes the original story. Make sure homepage and extension copy reflect **personal library** first. +- Referrer whitelist + soft throttle is required to keep free endpoints open without abuse. +- **Public unlimited usage** should only be granted to **real extension installs**. Plan: use Chrome Verified Access / `chrome.identity.getCertificationToken()` to prove the request is from a legitimate Web Store install before allowing unlimited public access. +- **Private keywords + sync** always require **user authentication** (magic‑link/OTP) — no exceptions. + +--- + +## 7) Quick Comparison Snapshot + +**What we should keep:** +- Public emoji search + dataset caching. +- Site UI/SEO baseline. +- API response contract (minus license semantics). + +**What we should replace:** +- Gumroad/Mayar license verification. +- Pro/lifetime license activation. +- Community submissions/voting. + +**What we should add:** +- User accounts + API keys. +- Private keyword library + sync. +- Dashboard + billing. + +--- + +## 8) Decision Checkpoints + +Before coding Phase A, confirm: +1. **Plan name** is officially “Personal” (not Pro). +2. **API key format** (`dew_…`) accepted. +3. Public endpoints remain unlimited for **dewemoji.com + extension**. +4. Stripe is the primary payment provider. + +--- + +If you want, I can immediately convert this into a task checklist by repo folder (backend, web, extension) and start Phase A scaffolding. diff --git a/references/email-designs/email-verification.html b/references/email-designs/email-verification.html new file mode 100644 index 0000000..9495570 --- /dev/null +++ b/references/email-designs/email-verification.html @@ -0,0 +1,141 @@ + + + + + + + Verify Email Address + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + \ No newline at end of file diff --git a/staging-sync-checklist.md b/staging-sync-checklist.md index bcebd29..c0cb6ad 100644 --- a/staging-sync-checklist.md +++ b/staging-sync-checklist.md @@ -4,7 +4,7 @@ This is the exact, minimal checklist to sync **live SQL → staging MySQL**. ## 1) Point app to MySQL -Edit `app/.env` (or set in Coolify ENV): +Edit `.env` (or set in Coolify ENV): ``` DB_CONNECTION=mysql @@ -15,12 +15,18 @@ DB_USERNAME=YOUR_USER DB_PASSWORD=YOUR_PASS ``` -## 2) Run migrations + import +## 2) Run migrations + import (inside Coolify app container) ```bash -cd /Users/dwindown/Developments/dewemoji/app +cd /var/www/html php artisan migrate -php artisan dewemoji:import-live-sql /Users/dwindown/Developments/dewemoji-live-backend/dewemojiAPI_DB.sql --truncate +php artisan dewemoji:import-live-sql /var/www/html/dewemojiAPI_DB.sql --truncate +``` + +If your SQL file is elsewhere, locate it first: + +```bash +find / -name "dewemojiAPI_DB.sql" 2>/dev/null ``` ## 3) Quick sanity checks diff --git a/tableplus-ssh-tunnel-guide.md b/tableplus-ssh-tunnel-guide.md new file mode 100644 index 0000000..47e9b8b --- /dev/null +++ b/tableplus-ssh-tunnel-guide.md @@ -0,0 +1,70 @@ +# TablePlus (Paid) or Sequel Ace (Free) + SSH Tunnel Guide (MySQL) + +This is a complete, step‑by‑step guide to access your **internal Coolify MySQL** from your Mac using **SSH tunnel + TablePlus or Sequel Ace**. + +## 1) Install a GUI client + +Choose one: + +### Option A — Sequel Ace (Free) +```bash +brew install --cask sequel-ace +``` + +### Option B — TablePlus (Trial/paid) + +Pick one method: + +**Option A — Homebrew** +```bash +brew install --cask tableplus +``` + +**Option B — Download App** +- Download from TablePlus website and install normally. + +## 2) Create the SSH tunnel (Mac Terminal) + +Replace `USER` and `YOUR_SERVER` with your SSH credentials: + +```bash +ssh -N -L 3307:127.0.0.1:3306 USER@YOUR_SERVER +``` + +Keep this terminal **open** while you use TablePlus. +If you close it, the tunnel disconnects. + +## 3) Open TablePlus or Sequel Ace and create connection + +In the app: +1) Click **Create a new connection** +2) Choose **MySQL** +3) Fill in: + - **Name:** Dewemoji (or anything) + - **Host:** `127.0.0.1` + - **Port:** `3307` + - **User:** `dewesql` (or your MySQL user) + - **Password:** (your MySQL password) + - **Database:** `dewemoji` (or your DB name) + +4) Click **Test** → should be green +5) Click **Connect** + +## 4) Done + +You now have full GUI access to the internal MySQL. + +## Troubleshooting + +**“Connection refused”** +- Tunnel not running (step 2). Keep it open. + +**“Access denied”** +- Wrong MySQL username/password. + +**No tables** +- Wrong database name. + +--- + +If you want, I can add a short “quick commands” section for `mysql` CLI too.