Output:
Chunk ID: 3ff6b9
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 23
Output:
sed: tests/Feature/Api/Admin/AdminShippingSettingsApiTest.php: No such file or directory


sed -n '1,220p' app/Http/Controllers/Api/Admin/V1/ShippingZoneController.php

ShippingZoneController.php

<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\ShippingZoneResource;
use App\Models\ShippingZone;
use App\Models\Store;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Validation\ValidationException;

class ShippingZoneController extends Controller
{
    public function index(Request $request, Store $store): AnonymousResourceCollection
    {
        $this->authorizeStore($request, $store);

        $zones = ShippingZone::withoutGlobalScopes()
            ->with(['rates' => fn ($query) => $query->withoutGlobalScopes()->orderBy('id'), 'store'])
            ->where('store_id', $store->getKey())
            ->orderBy('id')
            ->get();

        return ShippingZoneResource::collection($zones);
    }

    public function store(Request $request, Store $store): JsonResponse
    {
        $this->authorizeStore($request, $store);

        $validated = $this->validatePayload($request, $store);

        $zone = ShippingZone::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            ...$this->attributes($validated),
        ]);

        return ShippingZoneResource::make($this->loadZone($zone))
            ->response()
            ->setStatusCode(201);
    }

    public function update(Request $request, Store $store, ShippingZone $shippingZone): ShippingZoneResource
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessZoneBelongsToStore($shippingZone, $store);

        $validated = $this->validatePayload($request, $store, $shippingZone);

        $shippingZone->update($this->attributes($validated));

        return ShippingZoneResource::make($this->loadZone($shippingZone->refresh()));
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function abortUnlessZoneBelongsToStore(ShippingZone $zone, Store $store): void
    {
        abort_unless((int) $zone->store_id === $store->getKey(), 404);
    }

    /**
     * @return array<string, mixed>
     */
    private function validatePayload(Request $request, Store $store, ?ShippingZone $zone = null): array
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'countries_json' => ['required', 'array', 'min:1'],
            'countries_json.*' => ['required', 'string', 'size:2'],
            'regions_json' => ['sometimes', 'array'],
            'regions_json.*' => ['string', 'max:20'],
        ]);

        $countries = $this->countryCodes($validated['countries_json']);

        if ($countries === []) {
            throw ValidationException::withMessages([
                'countries_json' => __('Enter at least one ISO country code.'),
            ]);
        }

        $overlap = ShippingZone::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->when($zone instanceof ShippingZone, fn (Builder $query) => $query->whereKeyNot($zone->getKey()))
            ->get()
            ->first(fn (ShippingZone $existing): bool => array_intersect($countries, $existing->countries_json ?? []) !== []);

        if ($overlap instanceof ShippingZone) {
            throw ValidationException::withMessages([
                'countries_json' => __('One or more countries already belong to another shipping zone.'),
            ]);
        }

        $validated['countries_json'] = $countries;
        $validated['regions_json'] = $this->regionCodes($validated['regions_json'] ?? []);

        return $validated;
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributes(array $validated): array
    {
        return [
            'name' => $validated['name'],
            'countries_json' => $validated['countries_json'],
            'regions_json' => $validated['regions_json'],
        ];
    }

    /**
     * @param  list<string>  $countries
     * @return list<string>
     */
    private function countryCodes(array $countries): array
    {
        return collect($countries)
            ->map(fn (string $country): string => strtoupper(trim($country)))
            ->filter(fn (string $country): bool => preg_match('/^[A-Z]{2}$/', $country) === 1)
            ->unique()
            ->values()
            ->all();
    }

    /**
     * @param  list<string>  $regions
     * @return list<string>
     */
    private function regionCodes(array $regions): array
    {
        return collect($regions)
            ->map(fn (string $region): string => strtoupper(trim($region)))
            ->filter()
            ->unique()
            ->values()
            ->all();
    }

    private function loadZone(ShippingZone $zone): ShippingZone
    {
        return $zone->load([
            'rates' => fn ($query) => $query->withoutGlobalScopes()->orderBy('id'),
            'store',
        ]);
    }
}


Output:
Chunk ID: 6fef01
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1324
Output:
<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\ShippingZoneResource;
use App\Models\ShippingZone;
use App\Models\Store;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Validation\ValidationException;

class ShippingZoneController extends Controller
{
    public function index(Request $request, Store $store): AnonymousResourceCollection
    {
        $this->authorizeStore($request, $store);

        $zones = ShippingZone::withoutGlobalScopes()
            ->with(['rates' => fn ($query) => $query->withoutGlobalScopes()->orderBy('id'), 'store'])
            ->where('store_id', $store->getKey())
            ->orderBy('id')
            ->get();

        return ShippingZoneResource::collection($zones);
    }

    public function store(Request $request, Store $store): JsonResponse
    {
        $this->authorizeStore($request, $store);

        $validated = $this->validatePayload($request, $store);

        $zone = ShippingZone::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            ...$this->attributes($validated),
        ]);

        return ShippingZoneResource::make($this->loadZone($zone))
            ->response()
            ->setStatusCode(201);
    }

    public function update(Request $request, Store $store, ShippingZone $shippingZone): ShippingZoneResource
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessZoneBelongsToStore($shippingZone, $store);

        $validated = $this->validatePayload($request, $store, $shippingZone);

        $shippingZone->update($this->attributes($validated));

        return ShippingZoneResource::make($this->loadZone($shippingZone->refresh()));
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function abortUnlessZoneBelongsToStore(ShippingZone $zone, Store $store): void
    {
        abort_unless((int) $zone->store_id === $store->getKey(), 404);
    }

    /**
     * @return array<string, mixed>
     */
    private function validatePayload(Request $request, Store $store, ?ShippingZone $zone = null): array
    {
        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'countries_json' => ['required', 'array', 'min:1'],
            'countries_json.*' => ['required', 'string', 'size:2'],
            'regions_json' => ['sometimes', 'array'],
            'regions_json.*' => ['string', 'max:20'],
        ]);

        $countries = $this->countryCodes($validated['countries_json']);

        if ($countries === []) {
            throw ValidationException::withMessages([
                'countries_json' => __('Enter at least one ISO country code.'),
            ]);
        }

        $overlap = ShippingZone::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->when($zone instanceof ShippingZone, fn (Builder $query) => $query->whereKeyNot($zone->getKey()))
            ->get()
            ->first(fn (ShippingZone $existing): bool => array_intersect($countries, $existing->countries_json ?? []) !== []);

        if ($overlap instanceof ShippingZone) {
            throw ValidationException::withMessages([
                'countries_json' => __('One or more countries already belong to another shipping zone.'),
            ]);
        }

        $validated['countries_json'] = $countries;
        $validated['regions_json'] = $this->regionCodes($validated['regions_json'] ?? []);

        return $validated;
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributes(array $validated): array
    {
        return [
            'name' => $validated['name'],
            'countries_json' => $validated['countries_json'],
            'regions_json' => $validated['regions_json'],
        ];
    }

    /**
     * @param  list<string>  $countries
     * @return list<string>
     */
    private function countryCodes(array $countries): array
    {
        return collect($countries)
            ->map(fn (string $country): string => strtoupper(trim($country)))
            ->filter(fn (string $country): bool => preg_match('/^[A-Z]{2}$/', $country) === 1)
            ->unique()
            ->values()
            ->all();
    }

    /**
     * @param  list<string>  $regions
     * @return list<string>
     */
    private function regionCodes(array $regions): array
    {
        return collect($regions)
            ->map(fn (string $region): string => strtoupper(trim($region)))
            ->filter()
            ->unique()
            ->values()
            ->all();
    }

    private function loadZone(ShippingZone $zone): ShippingZone
    {
        return $zone->load([
            'rates' => fn ($query) => $query->withoutGlobalScopes()->orderBy('id'),
            'store',
        ]);
    }
}


The Livewire theme flow already has the core semantics: duplicating draft themes, saving JSON settings, publishing one active theme per store, and flushing the theme settings cache. I’m going to mirror that behavior in API controllers and keep archive upload validation deliberately narrow to what the current app can actually process.


find tests/Feature/Api/Admin -maxdepth 1 -type f | sort


sed -n '1,260p' tests/Feature/Api/Admin/AdminTaxSettingsApiTest.php


sed -n '1,260p' tests/Feature/Api/Admin/AdminPageApiTest.php


sed -n '1,220p' app/Http/Controllers/Api/Admin/V1/TaxSettingsController.php


sed -n '1,220p' app/Http/Controllers/Api/Admin/V1/PageController.php


sed -n '1,220p' app/Http/Middleware/EnsureAdminApiScope.php


sed -n '1,260p' tests/Feature/Api/Admin/AdminTaxSettingsApiTest.php

sed: tests/Feature/Api/Admin/AdminTaxSettingsApiTest.php: No such file or directory


find tests/Feature/Api/Admin -maxdepth 1 -type f | sort

find: tests/Feature/Api/Admin: No such file or directory


Output:
Chunk ID: f79b99
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 15
Output:
find: tests/Feature/Api/Admin: No such file or directory


Output:
Chunk ID: 7e6542
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 21
Output:
sed: tests/Feature/Api/Admin/AdminTaxSettingsApiTest.php: No such file or directory


sed -n '1,260p' tests/Feature/Api/Admin/AdminPageApiTest.php

sed: tests/Feature/Api/Admin/AdminPageApiTest.php: No such file or directory


Output:
Chunk ID: 3f5dd4
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 20
Output:
sed: tests/Feature/Api/Admin/AdminPageApiTest.php: No such file or directory


sed -n '1,220p' app/Http/Controllers/Api/Admin/V1/TaxSettingsController.php

<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Enums\TaxMode;
use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\TaxSettingsResource;
use App\Models\Store;
use App\Models\TaxSettings;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class TaxSettingsController extends Controller
{
    public function show(Request $request, Store $store): TaxSettingsResource
    {
        $this->authorizeStore($request, $store);

        return TaxSettingsResource::make($this->settings($store));
    }

    public function update(Request $request, Store $store): TaxSettingsResource
    {
        $this->authorizeStore($request, $store);

        $validated = $request->validate([
            'mode' => ['required', Rule::in(array_map(fn (TaxMode $mode): string => $mode->value, TaxMode::cases()))],
            'provider' => ['required_if:mode,provider', Rule::in(['none', 'stripe_tax'])],
            'prices_include_tax' => ['required', 'boolean'],
            'config_json' => ['required', 'array'],
            'config_json.default_tax_rate' => ['nullable', 'integer', 'min:0', 'max:10000'],
            'config_json.default_rate_bps' => ['nullable', 'integer', 'min:0', 'max:10000'],
            'config_json.tax_rates' => ['nullable', 'array'],
            'config_json.tax_rates.*.country_code' => ['required_with:config_json.tax_rates', 'string', 'size:2'],
            'config_json.tax_rates.*.rate' => ['required_with:config_json.tax_rates', 'integer', 'min:0', 'max:10000'],
            'config_json.tax_rates.*.name' => ['required_with:config_json.tax_rates', 'string', 'max:50'],
            'config_json.tax_rates.*.shipping_taxed' => ['nullable', 'boolean'],
            'config_json.rates' => ['nullable', 'array'],
            'config_json.rates.*.country' => ['required_with:config_json.rates', 'string', 'size:2'],
            'config_json.rates.*.rate_bps' => ['required_with:config_json.rates', 'integer', 'min:0', 'max:10000'],
            'config_json.rates.*.name' => ['required_with:config_json.rates', 'string', 'max:50'],
        ]);

        $settings = TaxSettings::withoutGlobalScopes()->updateOrCreate(
            ['store_id' => $store->getKey()],
            [
                'mode' => TaxMode::from($validated['mode']),
                'provider' => $validated['mode'] === TaxMode::Provider->value ? $validated['provider'] : 'none',
                'prices_include_tax' => (bool) $validated['prices_include_tax'],
                'config_json' => $this->normalizeConfig($request->input('config_json', [])),
            ],
        );

        return TaxSettingsResource::make($settings->refresh());
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function settings(Store $store): TaxSettings
    {
        return TaxSettings::withoutGlobalScopes()->firstOrCreate(
            ['store_id' => $store->getKey()],
            [
                'mode' => TaxMode::Manual,
                'provider' => 'none',
                'prices_include_tax' => false,
                'config_json' => [
                    'name' => 'Tax',
                    'default_rate_bps' => 0,
                    'shipping_taxable' => true,
                    'rates' => [],
                ],
            ],
        );
    }

    /**
     * @param  array<string, mixed>  $config
     * @return array<string, mixed>
     */
    private function normalizeConfig(array $config): array
    {
        $rates = collect($config['tax_rates'] ?? $config['rates'] ?? [])
            ->map(fn (array $rate): array => [
                'country' => strtoupper((string) ($rate['country_code'] ?? $rate['country'])),
                'rate_bps' => (int) ($rate['rate'] ?? $rate['rate_bps']),
                'name' => (string) $rate['name'],
                'shipping_taxed' => (bool) ($rate['shipping_taxed'] ?? true),
            ])
            ->values()
            ->all();

        return [
            ...$config,
            'default_rate_bps' => (int) ($config['default_tax_rate'] ?? $config['default_rate_bps'] ?? 0),
            'shipping_taxable' => (bool) ($config['shipping_taxable'] ?? true),
            'rates' => $rates,
        ];
    }
}


Output:
Chunk ID: ff46ce
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1119
Output:
<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Enums\TaxMode;
use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\TaxSettingsResource;
use App\Models\Store;
use App\Models\TaxSettings;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class TaxSettingsController extends Controller
{
    public function show(Request $request, Store $store): TaxSettingsResource
    {
        $this->authorizeStore($request, $store);

        return TaxSettingsResource::make($this->settings($store));
    }

    public function update(Request $request, Store $store): TaxSettingsResource
    {
        $this->authorizeStore($request, $store);

        $validated = $request->validate([
            'mode' => ['required', Rule::in(array_map(fn (TaxMode $mode): string => $mode->value, TaxMode::cases()))],
            'provider' => ['required_if:mode,provider', Rule::in(['none', 'stripe_tax'])],
            'prices_include_tax' => ['required', 'boolean'],
            'config_json' => ['required', 'array'],
            'config_json.default_tax_rate' => ['nullable', 'integer', 'min:0', 'max:10000'],
            'config_json.default_rate_bps' => ['nullable', 'integer', 'min:0', 'max:10000'],
            'config_json.tax_rates' => ['nullable', 'array'],
            'config_json.tax_rates.*.country_code' => ['required_with:config_json.tax_rates', 'string', 'size:2'],
            'config_json.tax_rates.*.rate' => ['required_with:config_json.tax_rates', 'integer', 'min:0', 'max:10000'],
            'config_json.tax_rates.*.name' => ['required_with:config_json.tax_rates', 'string', 'max:50'],
            'config_json.tax_rates.*.shipping_taxed' => ['nullable', 'boolean'],
            'config_json.rates' => ['nullable', 'array'],
            'config_json.rates.*.country' => ['required_with:config_json.rates', 'string', 'size:2'],
            'config_json.rates.*.rate_bps' => ['required_with:config_json.rates', 'integer', 'min:0', 'max:10000'],
            'config_json.rates.*.name' => ['required_with:config_json.rates', 'string', 'max:50'],
        ]);

        $settings = TaxSettings::withoutGlobalScopes()->updateOrCreate(
            ['store_id' => $store->getKey()],
            [
                'mode' => TaxMode::from($validated['mode']),
                'provider' => $validated['mode'] === TaxMode::Provider->value ? $validated['provider'] : 'none',
                'prices_include_tax' => (bool) $validated['prices_include_tax'],
                'config_json' => $this->normalizeConfig($request->input('config_json', [])),
            ],
        );

        return TaxSettingsResource::make($settings->refresh());
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function settings(Store $store): TaxSettings
    {
        return TaxSettings::withoutGlobalScopes()->firstOrCreate(
            ['store_id' => $store->getKey()],
            [
                'mode' => TaxMode::Manual,
                'provider' => 'none',
                'prices_include_tax' => false,
                'config_json' => [
                    'name' => 'Tax',
                    'default_rate_bps' => 0,
                    'shipping_taxable' => true,
                    'rates' => [],
                ],
            ],
        );
    }

    /**
     * @param  array<string, mixed>  $config
     * @return array<string, mixed>
     */
    private function normalizeConfig(array $config): array
    {
        $rates = collect($config['tax_rates'] ?? $config['rates'] ?? [])
            ->map(fn (array $rate): array => [
                'country' => strtoupper((string) ($rate['country_code'] ?? $rate['country'])),
                'rate_bps' => (int) ($rate['rate'] ?? $rate['rate_bps']),
                'name' => (string) $rate['name'],
                'shipping_taxed' => (bool) ($rate['shipping_taxed'] ?? true),
            ])
            ->values()
            ->all();

        return [
            ...$config,
            'default_rate_bps' => (int) ($config['default_tax_rate'] ?? $config['default_rate_bps'] ?? 0),
            'shipping_taxable' => (bool) ($config['shipping_taxable'] ?? true),
            'rates' => $rates,
        ];
    }
}


sed -n '1,220p' app/Http/Middleware/EnsureAdminApiScope.php

sed: app/Http/Middleware/EnsureAdminApiScope.php: No such file or directory


sed -n '1,220p' app/Http/Controllers/Api/Admin/V1/PageController.php

<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Enums\PageStatus;
use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\PageResource;
use App\Models\NavigationMenu;
use App\Models\Page;
use App\Models\Store;
use App\Services\NavigationService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator as ValidationValidator;

class PageController extends Controller
{
    public function index(Request $request, Store $store): AnonymousResourceCollection
    {
        $this->authorizeStore($request, $store);

        $validated = $request->validate([
            'status' => ['nullable', Rule::in($this->pageStatusValues())],
            'query' => ['nullable', 'string', 'max:255'],
            'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
        ]);

        $pages = Page::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->when(data_get($validated, 'status'), fn (Builder $query, string $status) => $query->where('status', $status))
            ->when(data_get($validated, 'query'), function (Builder $query, string $search): void {
                $query->where(function (Builder $query) use ($search): void {
                    $query
                        ->where('title', 'like', '%'.$search.'%')
                        ->orWhere('handle', 'like', '%'.$search.'%');
                });
            })
            ->latest('updated_at')
            ->latest('id')
            ->paginate((int) data_get($validated, 'per_page', 25));

        return PageResource::collection($pages);
    }

    public function store(Request $request, Store $store, NavigationService $navigation): JsonResponse
    {
        $this->authorizeStore($request, $store);

        $validated = $this->validatePayload($request, $store);

        $page = Page::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            ...$this->attributesForCreate($validated),
        ]);

        $this->forgetNavigation($store, $navigation);

        return PageResource::make($page)
            ->response()
            ->setStatusCode(201);
    }

    public function update(Request $request, Store $store, Page $page, NavigationService $navigation): PageResource
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessPageBelongsToStore($page, $store);

        $validated = $this->validatePayload($request, $store, $page);
        $attributes = $this->attributesForUpdate($validated, $page);

        if ($attributes !== []) {
            $page->update($attributes);
            $this->forgetNavigation($store, $navigation);
        }

        return PageResource::make($page->refresh());
    }

    public function destroy(Request $request, Store $store, Page $page, NavigationService $navigation): JsonResponse
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessPageBelongsToStore($page, $store);

        $page->delete();
        $this->forgetNavigation($store, $navigation);

        return response()->json(['message' => 'Page deleted']);
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function abortUnlessPageBelongsToStore(Page $page, Store $store): void
    {
        abort_unless((int) $page->store_id === $store->getKey(), 404);
    }

    /**
     * @return array<string, mixed>
     */
    private function validatePayload(Request $request, Store $store, ?Page $page = null): array
    {
        $creating = $page === null;

        $validator = Validator::make($request->all(), [
            'title' => [$creating ? 'required' : 'sometimes', 'string', 'max:255'],
            'handle' => ['sometimes', 'nullable', 'string', 'max:255'],
            'body_html' => ['sometimes', 'nullable', 'string', 'max:65535'],
            'status' => ['sometimes', Rule::in($this->pageStatusValues())],
            'published_at' => ['sometimes', 'nullable', 'date'],
        ]);

        $validator->after(function (ValidationValidator $validator) use ($request, $store, $page, $creating): void {
            if ($validator->errors()->isNotEmpty()) {
                return;
            }

            $handle = $this->handleForRequest($request, $page, $creating);

            if ($handle === '') {
                $validator->errors()->add('handle', __('The handle must contain at least one letter or number.'));

                return;
            }

            $exists = Page::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('handle', $handle)
                ->when($page instanceof Page, fn (Builder $query) => $query->whereKeyNot($page->getKey()))
                ->exists();

            if ($exists) {
                $validator->errors()->add('handle', __('The handle has already been taken.'));
            }
        });

        return $validator->validate();
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributesForCreate(array $validated): array
    {
        $status = PageStatus::from(data_get($validated, 'status', PageStatus::Draft->value));

        return [
            'title' => $validated['title'],
            'handle' => $this->normalizeHandle($validated['handle'] ?? $validated['title']),
            'body_html' => $validated['body_html'] ?? null,
            'status' => $status,
            'published_at' => $this->publishedAtForCreate($validated, $status),
        ];
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributesForUpdate(array $validated, Page $page): array
    {
        $attributes = Arr::only($validated, ['title', 'body_html']);

        if (array_key_exists('handle', $validated) && filled($validated['handle'])) {
            $attributes['handle'] = $this->normalizeHandle($validated['handle']);
        }

        if (array_key_exists('status', $validated)) {
            $attributes['status'] = PageStatus::from($validated['status']);
        }

        if (array_key_exists('published_at', $validated)) {
            $attributes['published_at'] = $validated['published_at'];
        } elseif (($attributes['status'] ?? $page->status) === PageStatus::Published && $page->published_at === null) {
            $attributes['published_at'] = now();
        }

        return $attributes;
    }

    /**
     * @param  array<string, mixed>  $validated
     */
    private function publishedAtForCreate(array $validated, PageStatus $status): mixed
    {
        if (array_key_exists('published_at', $validated)) {
            return $validated['published_at'];
        }

        return $status === PageStatus::Published ? now() : null;
    }

    private function handleForRequest(Request $request, ?Page $page, bool $creating): string
    {
        if ($request->exists('handle') && filled($request->input('handle'))) {
            return $this->normalizeHandle($request->input('handle'));
        }

        if ($creating) {
            return $this->normalizeHandle($request->input('title'));
        }

        return (string) $page?->handle;
    }

    private function normalizeHandle(mixed $value): string
    {


Output:
Chunk ID: 6858b1
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1948
Output:
<?php

namespace App\Http\Controllers\Api\Admin\V1;

use App\Enums\PageStatus;
use App\Http\Controllers\Controller;
use App\Http\Resources\Admin\V1\PageResource;
use App\Models\NavigationMenu;
use App\Models\Page;
use App\Models\Store;
use App\Services\NavigationService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator as ValidationValidator;

class PageController extends Controller
{
    public function index(Request $request, Store $store): AnonymousResourceCollection
    {
        $this->authorizeStore($request, $store);

        $validated = $request->validate([
            'status' => ['nullable', Rule::in($this->pageStatusValues())],
            'query' => ['nullable', 'string', 'max:255'],
            'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
        ]);

        $pages = Page::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->when(data_get($validated, 'status'), fn (Builder $query, string $status) => $query->where('status', $status))
            ->when(data_get($validated, 'query'), function (Builder $query, string $search): void {
                $query->where(function (Builder $query) use ($search): void {
                    $query
                        ->where('title', 'like', '%'.$search.'%')
                        ->orWhere('handle', 'like', '%'.$search.'%');
                });
            })
            ->latest('updated_at')
            ->latest('id')
            ->paginate((int) data_get($validated, 'per_page', 25));

        return PageResource::collection($pages);
    }

    public function store(Request $request, Store $store, NavigationService $navigation): JsonResponse
    {
        $this->authorizeStore($request, $store);

        $validated = $this->validatePayload($request, $store);

        $page = Page::withoutGlobalScopes()->create([
            'store_id' => $store->getKey(),
            ...$this->attributesForCreate($validated),
        ]);

        $this->forgetNavigation($store, $navigation);

        return PageResource::make($page)
            ->response()
            ->setStatusCode(201);
    }

    public function update(Request $request, Store $store, Page $page, NavigationService $navigation): PageResource
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessPageBelongsToStore($page, $store);

        $validated = $this->validatePayload($request, $store, $page);
        $attributes = $this->attributesForUpdate($validated, $page);

        if ($attributes !== []) {
            $page->update($attributes);
            $this->forgetNavigation($store, $navigation);
        }

        return PageResource::make($page->refresh());
    }

    public function destroy(Request $request, Store $store, Page $page, NavigationService $navigation): JsonResponse
    {
        $this->authorizeStore($request, $store);
        $this->abortUnlessPageBelongsToStore($page, $store);

        $page->delete();
        $this->forgetNavigation($store, $navigation);

        return response()->json(['message' => 'Page deleted']);
    }

    private function authorizeStore(Request $request, Store $store): void
    {
        if (! $request->attributes->has('admin_api_oauth_token')) {
            abort_unless($request->user()?->stores()->whereKey($store->getKey())->exists(), 403);
        }

        app()->instance('current_store', $store);
    }

    private function abortUnlessPageBelongsToStore(Page $page, Store $store): void
    {
        abort_unless((int) $page->store_id === $store->getKey(), 404);
    }

    /**
     * @return array<string, mixed>
     */
    private function validatePayload(Request $request, Store $store, ?Page $page = null): array
    {
        $creating = $page === null;

        $validator = Validator::make($request->all(), [
            'title' => [$creating ? 'required' : 'sometimes', 'string', 'max:255'],
            'handle' => ['sometimes', 'nullable', 'string', 'max:255'],
            'body_html' => ['sometimes', 'nullable', 'string', 'max:65535'],
            'status' => ['sometimes', Rule::in($this->pageStatusValues())],
            'published_at' => ['sometimes', 'nullable', 'date'],
        ]);

        $validator->after(function (ValidationValidator $validator) use ($request, $store, $page, $creating): void {
            if ($validator->errors()->isNotEmpty()) {
                return;
            }

            $handle = $this->handleForRequest($request, $page, $creating);

            if ($handle === '') {
                $validator->errors()->add('handle', __('The handle must contain at least one letter or number.'));

                return;
            }

            $exists = Page::withoutGlobalScopes()
                ->where('store_id', $store->getKey())
                ->where('handle', $handle)
                ->when($page instanceof Page, fn (Builder $query) => $query->whereKeyNot($page->getKey()))
                ->exists();

            if ($exists) {
                $validator->errors()->add('handle', __('The handle has already been taken.'));
            }
        });

        return $validator->validate();
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributesForCreate(array $validated): array
    {
        $status = PageStatus::from(data_get($validated, 'status', PageStatus::Draft->value));

        return [
            'title' => $validated['title'],
            'handle' => $this->normalizeHandle($validated['handle'] ?? $validated['title']),
            'body_html' => $validated['body_html'] ?? null,
            'status' => $status,
            'published_at' => $this->publishedAtForCreate($validated, $status),
        ];
    }

    /**
     * @param  array<string, mixed>  $validated
     * @return array<string, mixed>
     */
    private function attributesForUpdate(array $validated, Page $page): array
    {
        $attributes = Arr::only($validated, ['title', 'body_html']);

        if (array_key_exists('handle', $validated) && filled($validated['handle'])) {
            $attributes['handle'] = $this->normalizeHandle($validated['handle']);
        }

        if (array_key_exists('status', $validated)) {
            $attributes['status'] = PageStatus::from($validated['status']);
        }

        if (array_key_exists('published_at', $validated)) {
            $attributes['published_at'] = $validated['published_at'];
        } elseif (($attributes['status'] ?? $page->status) === PageStatus::Published && $page->published_at === null) {
            $attributes['published_at'] = now();
        }

        return $attributes;
    }

    /**
     * @param  array<string, mixed>  $validated
     */
    private function publishedAtForCreate(array $validated, PageStatus $status): mixed
    {
        if (array_key_exists('published_at', $validated)) {
            return $validated['published_at'];
        }

        return $status === PageStatus::Published ? now() : null;
    }

    private function handleForRequest(Request $request, ?Page $page, bool $creating): string
    {
        if ($request->exists('handle') && filled($request->input('handle'))) {
            return $this->normalizeHandle($request->input('handle'));
        }

        if ($creating) {
            return $this->normalizeHandle($request->input('title'));
        }

        return (string) $page?->handle;
    }

    private function normalizeHandle(mixed $value): string
    {


Output:
Chunk ID: f831b7
Wall time: 0.0000 seconds
Process exited with code 1
Original token count: 19
Output:
sed: app/Http/Middleware/EnsureAdminApiScope.php: No such file or directory


rg --files tests | rg 'Api|Tax|Page|Shipping|Admin'


rg -n "class .*AdminApi|admin.api|read-products|write-themes|read-settings" app bootstrap routes tests


find app/Http/Middleware -maxdepth 1 -type f -print | sort


sed -n '220,420p' app/Http/Controllers/Api/Admin/V1/PageController.php


sed -n '1,220p' app/Http/Resources/Admin/V1/TaxSettingsResource.php


sed -n '1,220p' app/Http/Resources/Admin/V1/PageResource.php


rg --files tests | rg 'Api|Tax|Page|Shipping|Admin'

Question: Api|Tax|Page|Shipping|Admin


Output:
Chunk ID: 80d82b
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 272
Output:
tests/Feature/Api/StorefrontCheckoutApiTest.php
tests/Feature/Api/StorefrontSearchApiTest.php
tests/Feature/Api/AdminSearchIndexApiTest.php
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php
tests/Feature/Api/AdminCatalogApiTest.php
tests/Feature/Api/StorefrontAnalyticsApiTest.php
tests/Feature/Api/AdminShippingSettingsApiTest.php
tests/Feature/Api/AdminCollectionApiTest.php
tests/Feature/Api/AdminDiscountApiTest.php
tests/Feature/Api/StorefrontOrderApiTest.php
tests/Feature/Api/AdminOrderApiTest.php
tests/Feature/Api/AdminPageApiTest.php
tests/Feature/Api/AdminTaxSettingsApiTest.php
tests/Feature/Api/StorefrontCartApiTest.php
tests/Feature/Admin/CustomerManagementTest.php
tests/Feature/Admin/OrderManagementTest.php
tests/Feature/Admin/ContentManagementTest.php
tests/Feature/Admin/DiscountManagementTest.php
tests/Feature/Admin/ProductMediaManagementTest.php
tests/Feature/Admin/DashboardTest.php
tests/Feature/Admin/SettingsManagementTest.php
tests/Feature/Admin/SearchSettingsTest.php
tests/Feature/Admin/AppsDevelopersTest.php
tests/Feature/Admin/AnalyticsDashboardTest.php


rg -n "class .*AdminApi|admin.api|read-products|write-themes|read-settings" app bootstrap routes tests

rg -n 'class .*AdminApi|admin.api|read-products|write-themes|read-settings' app bootstrap routes tests

Question: class .*AdminApi|admin.api|read-products|write-themes|read-settings

routes/api.php:63:        Route::middleware('admin.api:read-products')->group(function (): void {
routes/api.php:68:        Route::middleware('admin.api:read-customers')->group(function (): void {
routes/api.php:73:        Route::middleware('admin.api:read-collections')->group(function (): void {
routes/api.php:77:        Route::middleware('admin.api:write-collections')->group(function (): void {
routes/api.php:83:        Route::middleware('admin.api:read-discounts')->group(function (): void {
routes/api.php:87:        Route::middleware('admin.api:write-discounts')->group(function (): void {
routes/api.php:93:        Route::middleware('admin.api:read-content')->group(function (): void {
routes/api.php:97:        Route::middleware('admin.api:write-content')->group(function (): void {
routes/api.php:103:        Route::middleware('admin.api:read-settings')->group(function (): void {
routes/api.php:109:        Route::middleware('admin.api:write-settings')->group(function (): void {
routes/api.php:117:        Route::middleware('admin.api:read-analytics')->group(function (): void {
routes/api.php:121:        Route::middleware('admin.api:read-orders')->group(function (): void {
routes/api.php:126:        Route::middleware('admin.api:write-orders')->group(function (): void {
bootstrap/app.php:19:            'admin.api' => AuthenticateAdminApi::class,
tests/Feature/Api/AdminSearchIndexApiTest.php:78:    $readToken = adminSearchIndexApiToken($store, ['read-settings']);
tests/Feature/Api/AdminSearchIndexApiTest.php:80:    $otherStoreToken = adminSearchIndexApiToken($otherStore, ['read-settings']);
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:119:    $wrongAbilityToken = adminAnalyticsSummaryApiToken($store, ['read-settings']);
app/Http/Controllers/Api/Admin/V1/PageController.php:98:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ShippingZoneController.php:60:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/TaxSettingsController.php:59:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/CustomerController.php:56:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderRefundController.php:45:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ProductController.php:65:        if (! $request->attributes->has('admin_api_oauth_token')) {
tests/Feature/Api/AdminCatalogApiTest.php:47:            'handle' => 'admin-api-jacket',
tests/Feature/Api/AdminCatalogApiTest.php:125:    $productToken = adminCatalogApiToken($store, ['read-products']);
tests/Feature/Api/AdminCatalogApiTest.php:165:        ->getJson('/oauth/authorize?client_id=test&redirect_uri=https://example.test/callback&response_type=code&scope=read-products&state=state')
app/Http/Controllers/Api/Admin/V1/DiscountController.php:77:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderFulfillmentController.php:39:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ShippingRateController.php:54:        if (! $request->attributes->has('admin_api_oauth_token')) {
tests/Feature/Api/AdminShippingSettingsApiTest.php:97:    $readToken = adminShippingSettingsApiToken($store, ['read-settings']);
tests/Feature/Api/AdminShippingSettingsApiTest.php:99:    $otherStoreToken = adminShippingSettingsApiToken($otherStore, ['read-settings']);
tests/Feature/Api/AdminTaxSettingsApiTest.php:82:    $readToken = adminTaxSettingsApiToken($store, ['read-settings']);
tests/Feature/Api/AdminTaxSettingsApiTest.php:84:    $otherStoreToken = adminTaxSettingsApiToken($otherStore, ['read-settings']);
app/Http/Middleware/AuthenticateAdminApi.php:12:class AuthenticateAdminApi
app/Http/Middleware/AuthenticateAdminApi.php:23:        app()->forgetInstance('admin_api_oauth_token');
app/Http/Middleware/AuthenticateAdminApi.php:63:        $request->attributes->set('admin_api_oauth_token', $token);
app/Http/Middleware/AuthenticateAdminApi.php:64:        app()->instance('admin_api_oauth_token', $token);
app/Livewire/Admin/Developers/Index.php:38:        'read-products',
app/Http/Controllers/Api/Admin/V1/CollectionController.php:105:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/SearchIndexController.php:68:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/AnalyticsSummaryController.php:66:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderController.php:62:        if (! $request->attributes->has('admin_api_oauth_token')) {


Output:
Chunk ID: 022d48
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1207
Output:
routes/api.php:63:        Route::middleware('admin.api:read-products')->group(function (): void {
routes/api.php:68:        Route::middleware('admin.api:read-customers')->group(function (): void {
routes/api.php:73:        Route::middleware('admin.api:read-collections')->group(function (): void {
routes/api.php:77:        Route::middleware('admin.api:write-collections')->group(function (): void {
routes/api.php:83:        Route::middleware('admin.api:read-discounts')->group(function (): void {
routes/api.php:87:        Route::middleware('admin.api:write-discounts')->group(function (): void {
routes/api.php:93:        Route::middleware('admin.api:read-content')->group(function (): void {
routes/api.php:97:        Route::middleware('admin.api:write-content')->group(function (): void {
routes/api.php:103:        Route::middleware('admin.api:read-settings')->group(function (): void {
routes/api.php:109:        Route::middleware('admin.api:write-settings')->group(function (): void {
routes/api.php:117:        Route::middleware('admin.api:read-analytics')->group(function (): void {
routes/api.php:121:        Route::middleware('admin.api:read-orders')->group(function (): void {
routes/api.php:126:        Route::middleware('admin.api:write-orders')->group(function (): void {
bootstrap/app.php:19:            'admin.api' => AuthenticateAdminApi::class,
tests/Feature/Api/AdminSearchIndexApiTest.php:78:    $readToken = adminSearchIndexApiToken($store, ['read-settings']);
tests/Feature/Api/AdminSearchIndexApiTest.php:80:    $otherStoreToken = adminSearchIndexApiToken($otherStore, ['read-settings']);
tests/Feature/Api/AdminAnalyticsSummaryApiTest.php:119:    $wrongAbilityToken = adminAnalyticsSummaryApiToken($store, ['read-settings']);
app/Http/Controllers/Api/Admin/V1/PageController.php:98:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ShippingZoneController.php:60:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/TaxSettingsController.php:59:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/CustomerController.php:56:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderRefundController.php:45:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ProductController.php:65:        if (! $request->attributes->has('admin_api_oauth_token')) {
tests/Feature/Api/AdminCatalogApiTest.php:47:            'handle' => 'admin-api-jacket',
tests/Feature/Api/AdminCatalogApiTest.php:125:    $productToken = adminCatalogApiToken($store, ['read-products']);
tests/Feature/Api/AdminCatalogApiTest.php:165:        ->getJson('/oauth/authorize?client_id=test&redirect_uri=https://example.test/callback&response_type=code&scope=read-products&state=state')
app/Http/Controllers/Api/Admin/V1/DiscountController.php:77:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderFulfillmentController.php:39:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/ShippingRateController.php:54:        if (! $request->attributes->has('admin_api_oauth_token')) {
tests/Feature/Api/AdminShippingSettingsApiTest.php:97:    $readToken = adminShippingSettingsApiToken($store, ['read-settings']);
tests/Feature/Api/AdminShippingSettingsApiTest.php:99:    $otherStoreToken = adminShippingSettingsApiToken($otherStore, ['read-settings']);
tests/Feature/Api/AdminTaxSettingsApiTest.php:82:    $readToken = adminTaxSettingsApiToken($store, ['read-settings']);
tests/Feature/Api/AdminTaxSettingsApiTest.php:84:    $otherStoreToken = adminTaxSettingsApiToken($otherStore, ['read-settings']);
app/Http/Middleware/AuthenticateAdminApi.php:12:class AuthenticateAdminApi
app/Http/Middleware/AuthenticateAdminApi.php:23:        app()->forgetInstance('admin_api_oauth_token');
app/Http/Middleware/AuthenticateAdminApi.php:63:        $request->attributes->set('admin_api_oauth_token', $token);
app/Http/Middleware/AuthenticateAdminApi.php:64:        app()->instance('admin_api_oauth_token', $token);
app/Livewire/Admin/Developers/Index.php:38:        'read-products',
app/Http/Controllers/Api/Admin/V1/CollectionController.php:105:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/SearchIndexController.php:68:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/AnalyticsSummaryController.php:66:        if (! $request->attributes->has('admin_api_oauth_token')) {
app/Http/Controllers/Api/Admin/V1/OrderController.php:62:        if (! $request->attributes->has('admin_api_oauth_token')) {


Output:
Chunk ID: 87b3aa
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 43
Output:
app/Http/Middleware/AuthenticateAdminApi.php
app/Http/Middleware/CheckStoreRole.php
app/Http/Middleware/EnsureUserEmailIsVerified.php
app/Http/Middleware/ResolveStore.php


sed -n '220,420p' app/Http/Controllers/Api/Admin/V1/PageController.php

    {
        return Str::slug((string) $value);
    }

    /**
     * @return list<string>
     */
    private function pageStatusValues(): array
    {
        return array_map(fn (PageStatus $status): string => $status->value, PageStatus::cases());
    }

    private function forgetNavigation(Store $store, NavigationService $navigation): void
    {
        NavigationMenu::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->get()
            ->each(fn (NavigationMenu $menu): mixed => $navigation->forget($menu));
    }
}


Output:
Chunk ID: ff1628
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 141
Output:
    {
        return Str::slug((string) $value);
    }

    /**
     * @return list<string>
     */
    private function pageStatusValues(): array
    {
        return array_map(fn (PageStatus $status): string => $status->value, PageStatus::cases());
    }

    private function forgetNavigation(Store $store, NavigationService $navigation): void
    {
        NavigationMenu::withoutGlobalScopes()
            ->where('store_id', $store->getKey())
            ->get()
            ->each(fn (NavigationMenu $menu): mixed => $navigation->forget($menu));
    }
}


sed -n '1,220p' app/Http/Resources/Admin/V1/TaxSettingsResource.php

<?php

namespace App\Http\Resources\Admin\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Arr;

class TaxSettingsResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'store_id' => $this->store_id,
            'mode' => $this->mode?->value,
            'provider' => $this->provider,
            'prices_include_tax' => $this->prices_include_tax,
            'config_json' => $this->publicConfig(),
            'updated_at' => null,
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function publicConfig(): array
    {
        $config = $this->config_json ?? [];

        if ($this->mode?->value === 'provider') {
            return Arr::except($config, ['provider_api_key']);
        }

        return [
            ...Arr::except($config, ['default_rate_bps', 'rates', 'provider_api_key']),
            'default_tax_rate' => (int) data_get($config, 'default_tax_rate', data_get($config, 'default_rate_bps', 0)),
            'tax_rates' => collect(data_get($config, 'tax_rates', data_get($config, 'rates', [])))
                ->map(fn (array $rate): array => [
                    'country_code' => strtoupper((string) data_get($rate, 'country_code', data_get($rate, 'country'))),
                    'rate' => (int) data_get($rate, 'rate', data_get($rate, 'rate_bps', 0)),
                    'name' => (string) data_get($rate, 'name', 'Tax'),
                    'shipping_taxed' => (bool) data_get($rate, 'shipping_taxed', data_get($config, 'shipping_taxable', true)),
                ])
                ->values()
                ->all(),
        ];
    }
}


Output:
Chunk ID: 0da6f2
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 457
Output:
<?php

namespace App\Http\Resources\Admin\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Arr;

class TaxSettingsResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'store_id' => $this->store_id,
            'mode' => $this->mode?->value,
            'provider' => $this->provider,
            'prices_include_tax' => $this->prices_include_tax,
            'config_json' => $this->publicConfig(),
            'updated_at' => null,
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function publicConfig(): array
    {
        $config = $this->config_json ?? [];

        if ($this->mode?->value === 'provider') {
            return Arr::except($config, ['provider_api_key']);
        }

        return [
            ...Arr::except($config, ['default_rate_bps', 'rates', 'provider_api_key']),
            'default_tax_rate' => (int) data_get($config, 'default_tax_rate', data_get($config, 'default_rate_bps', 0)),
            'tax_rates' => collect(data_get($config, 'tax_rates', data_get($config, 'rates', [])))
                ->map(fn (array $rate): array => [
                    'country_code' => strtoupper((string) data_get($rate, 'country_code', data_get($rate, 'country'))),
                    'rate' => (int) data_get($rate, 'rate', data_get($rate, 'rate_bps', 0)),
                    'name' => (string) data_get($rate, 'name', 'Tax'),
                    'shipping_taxed' => (bool) data_get($rate, 'shipping_taxed', data_get($config, 'shipping_taxable', true)),
                ])
                ->values()
                ->all(),
        ];
    }
}


sed -n '1,220p' app/Http/Resources/Admin/V1/PageResource.php

<?php

namespace App\Http\Resources\Admin\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class PageResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'title' => $this->title,
            'handle' => $this->handle,
            'body_html' => $this->body_html,
            'status' => $this->status?->value,
            'published_at' => $this->published_at?->toIso8601String(),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


Output:
Chunk ID: 3cafc4
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 204
Output:
<?php

namespace App\Http\Resources\Admin\V1;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class PageResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'store_id' => $this->store_id,
            'title' => $this->title,
            'handle' => $this->handle,
            'body_html' => $this->body_html,
            'status' => $this->status?->value,
            'published_at' => $this->published_at?->toIso8601String(),
            'created_at' => $this->created_at?->toIso8601String(),
            'updated_at' => $this->updated_at?->toIso8601String(),
        ];
    }
}


sed -n '1,260p' tests/Feature/Api/AdminShippingSettingsApiTest.php


sed -n '1,240p' tests/Feature/Api/AdminTaxSettingsApiTest.php


sed -n '1,260p' tests/Feature/Api/AdminPageApiTest.php


sed -n '1,260p' app/Http/Middleware/AuthenticateAdminApi.php


sed -n '1,260p' app/Http/Controllers/Api/Admin/V1/ShippingRateController.php


sed -n '1,220p' database/migrations/*create_themes* database/migrations/*create_theme* 2>/dev/null


sed -n '1,260p' tests/Feature/Api/AdminShippingSettingsApiTest.php

<?php

use App\Enums\ShippingRateType;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminShippingSettingsApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminShippingSettingsApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminShippingSettingsApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Shipping settings integration', $abilities);
}

test('admin shipping settings api lists creates updates zones and adds rates', function (): void {
    $store = adminShippingSettingsApiStore();
    $user = adminShippingSettingsApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertOk()
        ->assertJsonPath('data.0.name', 'DACH')
        ->assertJsonPath('data.0.rates.0.config_json.currency', $store->default_currency);

    $createResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Nordics API',
            'countries_json' => ['se', 'no'],
            'regions_json' => ['stockholm'],
        ])
        ->assertCreated()
        ->assertJsonPath('data.name', 'Nordics API')
        ->assertJsonPath('data.countries_json.0', 'SE')
        ->assertJsonPath('data.regions_json.0', 'STOCKHOLM');

    $zone = ShippingZone::withoutGlobalScopes()->findOrFail($createResponse->json('data.id'));

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}", [
            'name' => 'Nordics and Baltics API',
            'countries_json' => ['SE', 'DK'],
            'regions_json' => [],
        ])
        ->assertOk()
        ->assertJsonPath('data.name', 'Nordics and Baltics API')
        ->assertJsonPath('data.countries_json.1', 'DK');

    $rateResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'API Express',
            'type' => 'flat',
            'config_json' => [
                'price_amount' => 1200,
                'currency' => $store->default_currency,
            ],
            'is_active' => true,
        ])
        ->assertCreated()
        ->assertJsonPath('data.name', 'API Express')
        ->assertJsonPath('data.type', 'flat')
        ->assertJsonPath('data.config_json.price_amount', 1200);

    $rate = ShippingRate::withoutGlobalScopes()->findOrFail($rateResponse->json('data.id'));

    expect($zone->refresh()->countries_json)->toBe(['SE', 'DK'])
        ->and($rate->type)->toBe(ShippingRateType::Flat)
        ->and($rate->config_json['amount'])->toBe(1200);
});

test('admin shipping settings api enforces token abilities and store scope', function (): void {
    $store = adminShippingSettingsApiStore();
    $otherStore = Store::factory()->create();
    $zone = ShippingZone::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $readToken = adminShippingSettingsApiToken($store, ['read-settings']);
    $writeToken = adminShippingSettingsApiToken($store, ['write-settings']);
    $otherStoreToken = adminShippingSettingsApiToken($otherStore, ['read-settings']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertOk();

    $this->withToken($readToken['plain_text'])
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Read Only Zone',
            'countries_json' => ['FI'],
        ])
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'Token Rate',
            'type' => 'carrier',
            'config_json' => [
                'price_amount' => 999,
            ],
        ])
        ->assertCreated();
});

test('admin shipping settings api validates countries overlaps and rate types', function (): void {
    $store = adminShippingSettingsApiStore();
    $zone = ShippingZone::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();

    $this->actingAs(adminShippingSettingsApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Overlap API',
            'countries_json' => ['DE'],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['countries_json']);

    $this->actingAs(adminShippingSettingsApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'Invalid Rate',
            'type' => 'rocket',
            'config_json' => [],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['type']);
});


sed -n '1,240p' tests/Feature/Api/AdminTaxSettingsApiTest.php

<?php

use App\Enums\TaxMode;
use App\Models\Store;
use App\Models\TaxSettings;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminTaxSettingsApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminTaxSettingsApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminTaxSettingsApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Tax settings integration', $abilities);
}

test('admin tax settings api shows and updates manual settings', function (): void {
    $store = adminTaxSettingsApiStore();
    $user = adminTaxSettingsApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertOk()
        ->assertJsonPath('data.store_id', $store->getKey())
        ->assertJsonPath('data.mode', 'manual')
        ->assertJsonPath('data.config_json.default_tax_rate', 1900);

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => true,
            'config_json' => [
                'default_tax_rate' => 2100,
                'tax_rates' => [
                    [
                        'country_code' => 'de',
                        'rate' => 2100,
                        'name' => 'VAT',
                        'shipping_taxed' => true,
                    ],
                ],
            ],
        ])
        ->assertOk()
        ->assertJsonPath('data.prices_include_tax', true)
        ->assertJsonPath('data.config_json.default_tax_rate', 2100)
        ->assertJsonPath('data.config_json.tax_rates.0.country_code', 'DE');

    $settings = TaxSettings::withoutGlobalScopes()->whereKey($store->getKey())->firstOrFail();

    expect($settings->mode)->toBe(TaxMode::Manual)
        ->and($settings->provider)->toBe('none')
        ->and($settings->prices_include_tax)->toBeTrue()
        ->and($settings->config_json['default_rate_bps'])->toBe(2100)
        ->and($settings->config_json['rates'][0]['country'])->toBe('DE');
});

test('admin tax settings api enforces token abilities and store scope', function (): void {
    $store = adminTaxSettingsApiStore();
    $otherStore = Store::factory()->create();
    $readToken = adminTaxSettingsApiToken($store, ['read-settings']);
    $writeToken = adminTaxSettingsApiToken($store, ['write-settings']);
    $otherStoreToken = adminTaxSettingsApiToken($otherStore, ['read-settings']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertOk();

    $this->withToken($readToken['plain_text'])
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => false,
            'config_json' => [],
        ])
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'provider',
            'provider' => 'stripe_tax',
            'prices_include_tax' => false,
            'config_json' => [
                'stripe_tax_settings_id' => 'txr_api',
            ],
        ])
        ->assertOk()
        ->assertJsonPath('data.mode', 'provider')
        ->assertJsonPath('data.provider', 'stripe_tax');
});

test('admin tax settings api validates provider and rate payloads', function (): void {
    $store = adminTaxSettingsApiStore();

    $this->actingAs(adminTaxSettingsApiUser())
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'provider',
            'prices_include_tax' => false,
            'config_json' => [],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['provider']);

    $this->actingAs(adminTaxSettingsApiUser())
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => false,
            'config_json' => [
                'tax_rates' => [
                    [
                        'country_code' => 'DEU',
                        'rate' => 12000,
                        'name' => 'VAT',
                    ],
                ],
            ],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['config_json.tax_rates.0.country_code', 'config_json.tax_rates.0.rate']);
});


sed -n '1,260p' tests/Feature/Api/AdminPageApiTest.php

<?php

use App\Models\Page;
use App\Models\Store;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminPageApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminPageApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminPageApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Content integration', $abilities);
}

test('admin page api lists creates updates and deletes pages', function (): void {
    $store = adminPageApiStore();
    $otherStore = Store::factory()->create();
    Page::factory()->published()->create([
        'store_id' => $store->getKey(),
        'title' => 'API Visible Page',
        'handle' => 'api-visible-page',
    ]);
    Page::factory()->published()->create([
        'store_id' => $otherStore->getKey(),
        'title' => 'Other Store Page',
        'handle' => 'other-store-page',
    ]);
    $user = adminPageApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages?status=published&query=API")
        ->assertOk()
        ->assertJsonFragment(['title' => 'API Visible Page'])
        ->assertJsonMissing(['title' => 'Other Store Page']);

    $createResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Shipping Policy API',
            'body_html' => '
Shipping Policy

We ship worldwide.
',
            'status' => 'published',
        ])
        ->assertCreated()
        ->assertJsonPath('data.title', 'Shipping Policy API')
        ->assertJsonPath('data.handle', 'shipping-policy-api')
        ->assertJsonPath('data.status', 'published');

    $page = Page::withoutGlobalScopes()->findOrFail($createResponse->json('data.id'));

    expect($page->published_at)->not->toBeNull();

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}", [
            'handle' => 'API Shipping Policy Updated',
            'body_html' => '
Updated policy.
',
            'status' => 'draft',
        ])
        ->assertOk()
        ->assertJsonPath('data.handle', 'api-shipping-policy-updated')
        ->assertJsonPath('data.body_html', '
Updated policy.
')
        ->assertJsonPath('data.status', 'draft');

    $this->actingAs($user)
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertOk()
        ->assertJsonPath('message', 'Page deleted');

    expect(Page::withoutGlobalScopes()->whereKey($page->getKey())->exists())->toBeFalse();
});

test('admin page api enforces token abilities and store scope', function (): void {
    $store = adminPageApiStore();
    $otherStore = Store::factory()->create();
    $page = Page::factory()->published()->create([
        'store_id' => $store->getKey(),
        'title' => 'Token Content Page',
        'handle' => 'token-content-page',
    ]);
    $readToken = adminPageApiToken($store, ['read-content']);
    $writeToken = adminPageApiToken($store, ['write-content']);
    $otherStoreToken = adminPageApiToken($otherStore, ['read-content']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages?query=Token")
        ->assertOk()
        ->assertJsonPath('data.0.title', 'Token Content Page');

    $this->withToken($readToken['plain_text'])
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertOk();
});

test('admin page api validates normalized handles and published dates', function (): void {
    $store = adminPageApiStore();
    $existing = Page::factory()->create([
        'store_id' => $store->getKey(),
        'handle' => 'existing-api-page',
    ]);

    $this->actingAs(adminPageApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Invalid API Page',
            'handle' => str_replace('-', ' ', $existing->handle),
            'status' => 'published',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['handle']);

    $this->actingAs(adminPageApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Invalid API Date',
            'status' => 'published',
            'published_at' => 'not-a-date',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['published_at']);
});


Output:
Chunk ID: 193e67
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1395
Output:
<?php

use App\Enums\ShippingRateType;
use App\Models\ShippingRate;
use App\Models\ShippingZone;
use App\Models\Store;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminShippingSettingsApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminShippingSettingsApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminShippingSettingsApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Shipping settings integration', $abilities);
}

test('admin shipping settings api lists creates updates zones and adds rates', function (): void {
    $store = adminShippingSettingsApiStore();
    $user = adminShippingSettingsApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertOk()
        ->assertJsonPath('data.0.name', 'DACH')
        ->assertJsonPath('data.0.rates.0.config_json.currency', $store->default_currency);

    $createResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Nordics API',
            'countries_json' => ['se', 'no'],
            'regions_json' => ['stockholm'],
        ])
        ->assertCreated()
        ->assertJsonPath('data.name', 'Nordics API')
        ->assertJsonPath('data.countries_json.0', 'SE')
        ->assertJsonPath('data.regions_json.0', 'STOCKHOLM');

    $zone = ShippingZone::withoutGlobalScopes()->findOrFail($createResponse->json('data.id'));

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}", [
            'name' => 'Nordics and Baltics API',
            'countries_json' => ['SE', 'DK'],
            'regions_json' => [],
        ])
        ->assertOk()
        ->assertJsonPath('data.name', 'Nordics and Baltics API')
        ->assertJsonPath('data.countries_json.1', 'DK');

    $rateResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'API Express',
            'type' => 'flat',
            'config_json' => [
                'price_amount' => 1200,
                'currency' => $store->default_currency,
            ],
            'is_active' => true,
        ])
        ->assertCreated()
        ->assertJsonPath('data.name', 'API Express')
        ->assertJsonPath('data.type', 'flat')
        ->assertJsonPath('data.config_json.price_amount', 1200);

    $rate = ShippingRate::withoutGlobalScopes()->findOrFail($rateResponse->json('data.id'));

    expect($zone->refresh()->countries_json)->toBe(['SE', 'DK'])
        ->and($rate->type)->toBe(ShippingRateType::Flat)
        ->and($rate->config_json['amount'])->toBe(1200);
});

test('admin shipping settings api enforces token abilities and store scope', function (): void {
    $store = adminShippingSettingsApiStore();
    $otherStore = Store::factory()->create();
    $zone = ShippingZone::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();
    $readToken = adminShippingSettingsApiToken($store, ['read-settings']);
    $writeToken = adminShippingSettingsApiToken($store, ['write-settings']);
    $otherStoreToken = adminShippingSettingsApiToken($otherStore, ['read-settings']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertOk();

    $this->withToken($readToken['plain_text'])
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Read Only Zone',
            'countries_json' => ['FI'],
        ])
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'Token Rate',
            'type' => 'carrier',
            'config_json' => [
                'price_amount' => 999,
            ],
        ])
        ->assertCreated();
});

test('admin shipping settings api validates countries overlaps and rate types', function (): void {
    $store = adminShippingSettingsApiStore();
    $zone = ShippingZone::withoutGlobalScopes()->where('store_id', $store->getKey())->firstOrFail();

    $this->actingAs(adminShippingSettingsApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones", [
            'name' => 'Overlap API',
            'countries_json' => ['DE'],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['countries_json']);

    $this->actingAs(adminShippingSettingsApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/shipping/zones/{$zone->getKey()}/rates", [
            'name' => 'Invalid Rate',
            'type' => 'rocket',
            'config_json' => [],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['type']);
});


Output:
Chunk ID: 134539
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1299
Output:
<?php

use App\Enums\TaxMode;
use App\Models\Store;
use App\Models\TaxSettings;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminTaxSettingsApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminTaxSettingsApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminTaxSettingsApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Tax settings integration', $abilities);
}

test('admin tax settings api shows and updates manual settings', function (): void {
    $store = adminTaxSettingsApiStore();
    $user = adminTaxSettingsApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertOk()
        ->assertJsonPath('data.store_id', $store->getKey())
        ->assertJsonPath('data.mode', 'manual')
        ->assertJsonPath('data.config_json.default_tax_rate', 1900);

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => true,
            'config_json' => [
                'default_tax_rate' => 2100,
                'tax_rates' => [
                    [
                        'country_code' => 'de',
                        'rate' => 2100,
                        'name' => 'VAT',
                        'shipping_taxed' => true,
                    ],
                ],
            ],
        ])
        ->assertOk()
        ->assertJsonPath('data.prices_include_tax', true)
        ->assertJsonPath('data.config_json.default_tax_rate', 2100)
        ->assertJsonPath('data.config_json.tax_rates.0.country_code', 'DE');

    $settings = TaxSettings::withoutGlobalScopes()->whereKey($store->getKey())->firstOrFail();

    expect($settings->mode)->toBe(TaxMode::Manual)
        ->and($settings->provider)->toBe('none')
        ->and($settings->prices_include_tax)->toBeTrue()
        ->and($settings->config_json['default_rate_bps'])->toBe(2100)
        ->and($settings->config_json['rates'][0]['country'])->toBe('DE');
});

test('admin tax settings api enforces token abilities and store scope', function (): void {
    $store = adminTaxSettingsApiStore();
    $otherStore = Store::factory()->create();
    $readToken = adminTaxSettingsApiToken($store, ['read-settings']);
    $writeToken = adminTaxSettingsApiToken($store, ['write-settings']);
    $otherStoreToken = adminTaxSettingsApiToken($otherStore, ['read-settings']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertOk();

    $this->withToken($readToken['plain_text'])
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => false,
            'config_json' => [],
        ])
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'provider',
            'provider' => 'stripe_tax',
            'prices_include_tax' => false,
            'config_json' => [
                'stripe_tax_settings_id' => 'txr_api',
            ],
        ])
        ->assertOk()
        ->assertJsonPath('data.mode', 'provider')
        ->assertJsonPath('data.provider', 'stripe_tax');
});

test('admin tax settings api validates provider and rate payloads', function (): void {
    $store = adminTaxSettingsApiStore();

    $this->actingAs(adminTaxSettingsApiUser())
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'provider',
            'prices_include_tax' => false,
            'config_json' => [],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['provider']);

    $this->actingAs(adminTaxSettingsApiUser())
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/tax/settings", [
            'mode' => 'manual',
            'provider' => 'none',
            'prices_include_tax' => false,
            'config_json' => [
                'tax_rates' => [
                    [
                        'country_code' => 'DEU',
                        'rate' => 12000,
                        'name' => 'VAT',
                    ],
                ],
            ],
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['config_json.tax_rates.0.country_code', 'config_json.tax_rates.0.rate']);
});


Output:
Chunk ID: 65c363
Wall time: 0.0001 seconds
Process exited with code 0
Original token count: 1307
Output:
<?php

use App\Models\Page;
use App\Models\Store;
use App\Models\User;
use App\Services\WebhookService;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
    $this->withoutVite();
    $this->seed(DatabaseSeeder::class);
});

function adminPageApiStore(): Store
{
    return Store::query()->where('handle', 'acme-fashion')->firstOrFail();
}

function adminPageApiUser(): User
{
    return User::query()->where('email', 'admin@acme.test')->firstOrFail();
}

/**
 * @param  list<string>  $abilities
 * @return array{token: \App\Models\OauthToken, plain_text: string}
 */
function adminPageApiToken(Store $store, array $abilities): array
{
    return app(WebhookService::class)->createApiToken($store, 'Content integration', $abilities);
}

test('admin page api lists creates updates and deletes pages', function (): void {
    $store = adminPageApiStore();
    $otherStore = Store::factory()->create();
    Page::factory()->published()->create([
        'store_id' => $store->getKey(),
        'title' => 'API Visible Page',
        'handle' => 'api-visible-page',
    ]);
    Page::factory()->published()->create([
        'store_id' => $otherStore->getKey(),
        'title' => 'Other Store Page',
        'handle' => 'other-store-page',
    ]);
    $user = adminPageApiUser();

    $this->actingAs($user)
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages?status=published&query=API")
        ->assertOk()
        ->assertJsonFragment(['title' => 'API Visible Page'])
        ->assertJsonMissing(['title' => 'Other Store Page']);

    $createResponse = $this->actingAs($user)
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Shipping Policy API',
            'body_html' => '
Shipping Policy

We ship worldwide.
',
            'status' => 'published',
        ])
        ->assertCreated()
        ->assertJsonPath('data.title', 'Shipping Policy API')
        ->assertJsonPath('data.handle', 'shipping-policy-api')
        ->assertJsonPath('data.status', 'published');

    $page = Page::withoutGlobalScopes()->findOrFail($createResponse->json('data.id'));

    expect($page->published_at)->not->toBeNull();

    $this->actingAs($user)
        ->putJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}", [
            'handle' => 'API Shipping Policy Updated',
            'body_html' => '
Updated policy.
',
            'status' => 'draft',
        ])
        ->assertOk()
        ->assertJsonPath('data.handle', 'api-shipping-policy-updated')
        ->assertJsonPath('data.body_html', '
Updated policy.
')
        ->assertJsonPath('data.status', 'draft');

    $this->actingAs($user)
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertOk()
        ->assertJsonPath('message', 'Page deleted');

    expect(Page::withoutGlobalScopes()->whereKey($page->getKey())->exists())->toBeFalse();
});

test('admin page api enforces token abilities and store scope', function (): void {
    $store = adminPageApiStore();
    $otherStore = Store::factory()->create();
    $page = Page::factory()->published()->create([
        'store_id' => $store->getKey(),
        'title' => 'Token Content Page',
        'handle' => 'token-content-page',
    ]);
    $readToken = adminPageApiToken($store, ['read-content']);
    $writeToken = adminPageApiToken($store, ['write-content']);
    $otherStoreToken = adminPageApiToken($otherStore, ['read-content']);

    $this->withToken($readToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages?query=Token")
        ->assertOk()
        ->assertJsonPath('data.0.title', 'Token Content Page');

    $this->withToken($readToken['plain_text'])
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertForbidden();

    $this->withToken($otherStoreToken['plain_text'])
        ->getJson("/api/admin/v1/stores/{$store->getKey()}/pages")
        ->assertForbidden();

    $this->withToken($writeToken['plain_text'])
        ->deleteJson("/api/admin/v1/stores/{$store->getKey()}/pages/{$page->getKey()}")
        ->assertOk();
});

test('admin page api validates normalized handles and published dates', function (): void {
    $store = adminPageApiStore();
    $existing = Page::factory()->create([
        'store_id' => $store->getKey(),
        'handle' => 'existing-api-page',
    ]);

    $this->actingAs(adminPageApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Invalid API Page',
            'handle' => str_replace('-', ' ', $existing->handle),
            'status' => 'published',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['handle']);

    $this->actingAs(adminPageApiUser())
        ->postJson("/api/admin/v1/stores/{$store->getKey()}/pages", [
            'title' => 'Invalid API Date',
            'status' => 'published',
            'published_at' => 'not-a-date',
        ])
        ->assertUnprocessable()
        ->assertJsonValidationErrors(['published_at']);
});


sed -n '1,260p' app/Http/Middleware/AuthenticateAdminApi.php

<?php

namespace App\Http\Middleware;

use App\Enums\AppInstallationStatus;
use App\Models\OauthToken;
use App\Models\Store;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AuthenticateAdminApi
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, string ...$abilities): Response
    {
        $store = $this->storeFromRoute($request);

        app()->forgetInstance('admin_api_oauth_token');
        app()->instance('current_store', $store);

        if ($request->user() !== null) {
            if ($request->user()->stores()->whereKey($store->getKey())->exists()) {
                return $next($request);
            }

            return response()->json(['message' => 'Forbidden.'], 403);
        }

        $plainTextToken = $request->bearerToken();

        if (! is_string($plainTextToken) || $plainTextToken === '') {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

        $token = OauthToken::query()
            ->with('installation')
            ->where('access_token_hash', hash('sha256', $plainTextToken))
            ->first();

        if (! $token instanceof OauthToken || $token->isExpired()) {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

        $installation = $token->installation;

        if ($installation === null
            || $installation->status !== AppInstallationStatus::Active
            || (int) $installation->store_id !== $store->getKey()) {
            return response()->json(['message' => 'Forbidden.'], 403);
        }

        if (! $this->hasAbilities($token, $abilities)) {
            return response()->json(['message' => 'Forbidden.'], 403);
        }

        $token->forceFill(['last_used_at' => now()])->save();

        $request->attributes->set('admin_api_oauth_token', $token);
        app()->instance('admin_api_oauth_token', $token);

        return $next($request);
    }

    private function storeFromRoute(Request $request): Store
    {
        $store = $request->route('store');

        if ($store instanceof Store) {
            return $store;
        }

        return Store::query()->findOrFail($store);
    }

    /**
     * @param  list<string>  $abilities
     */
    private function hasAbilities(OauthToken $token, array $abilities): bool
    {
        if ($abilities === []) {
            return true;
        }

        $tokenAbilities = $token->abilities_json ?? [];

        if (in_array('*', $tokenAbilities, true)) {
            return true;
        }

        foreach ($abilities as $ability) {
            if (! in_array($ability, $tokenAbilities, true)) {
                return false;
            }
        }

        return true;
    }
}


Output:
Chunk ID: a22227
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 731
Output:
<?php

namespace App\Http\Middleware;

use App\Enums\AppInstallationStatus;
use App\Models\OauthToken;
use App\Models\Store;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class AuthenticateAdminApi
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, string ...$abilities): Response
    {
        $store = $this->storeFromRoute($request);

        app()->forgetInstance('admin_api_oauth_token');
        app()->instance('current_store', $store);

        if ($request->user() !== null) {
            if ($request->user()->stores()->whereKey($store->getKey())->exists()) {
                return $next($request);
            }

            return response()->json(['message' => 'Forbidden.'], 403);
        }

        $plainTextToken = $request->bearerToken();

        if (! is_string($plainTextToken) || $plainTextToken === '') {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

        $token = OauthToken::query()
            ->with('installation')
            ->where('access_token_hash', hash('sha256', $plainTextToken))
            ->first();

        if (! $token instanceof OauthToken || $token->isExpired()) {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

        $installation = $token->installation;

        if ($installation === null
            || $installation->status !== AppInstallationStatus::Active
            || (int) $installation->store_id !== $store->getKey()) {
            return response()->json(['message' => 'Forbidden.'], 403);
        }

        if (! $this->hasAbilities($token, $abilities)) {
            return response()->json(['message' => 'Forbidden.'], 403);
        }

        $token->forceFill(['last_used_at' => now()])->save();

        $request->attributes->set('admin_api_oauth_token', $token);
        app()->instance('admin_api_oauth_token', $token);

        return $next($request);
    }

    private function storeFromRoute(Request $request): Store
    {
        $store = $request->route('store');

        if ($store instanceof Store) {
            return $store;
        }

        return Store::query()->findOrFail($store);
    }

    /**
     * @param  list<string>  $abilities
     */
    private function hasAbilities(OauthToken $token, array $abilities): bool
    {
        if ($abilities === []) {
            return true;
        }

        $tokenAbilities = $token->abilities_json ?? [];

        if (in_array('*', $tokenAbilities, true)) {
            return true;
        }

        foreach ($abilities as $ability) {
            if (! in_array($ability, $tokenAbilities, true)) {
                return false;
            }
        }

        return true;
    }
}