niels / CodeSoftware / #apple,#developer

New team doesn’t show up in Apple Developer

So you invited someone to be a developer on your team, they accepted the invitation, they can use AppStore Connect, but not Apple Developer. What gives?

Organization

You must be an organization for your team members to get access to Apple Developer. If you are an individual developer, your team members get access to AppStore Connect, but not Apple Developer.

Certificates, Identifiers & Profiles

Still not working? Make sure you give your members the Access to Certificates, Identifiers & Profiles permission. Why? I guess because it’s the only reason someone, who is not the account holder, would need access to the Developer account.

Change your Currency

Still not working? Well, this fixed it for me:

  • Have your team member open AppStore Connect.
  • Click the drop-down in the top-right and choose Edit Profile.
  • Change the currency setting to something else.
  • Click Save.
  • Go back to developer.apple.com/account, reload the page and use the drop-down to switch to the new team!

No, I cannot explain this last one, but it worked for many!

0 comments

niels / Software / #laravel

Embedding Laravel Passport keys in .env

When deploying a Laravel project to a server, in an ideal scenario, there are two primary steps you should follow:

  • Clone your git repository
  • Configure the .env file

However, the introduction of Laravel Passport seemed to disrupt this streamlined process. Every time I deployed to a new server, I found myself needing to manually copy the oauth-private.key and oauth-public.key files.

In search of a solution to embed these keys within the .env file, I first stumbled upon this method on Laracasts. Although functional, it appeared somewhat untidy due to the double-escaped newline characters.

My pursuit for a cleaner solution led me to another approach on StackOverflow.


To avoid the hassle of manually reformatting these keys, I’ve crafted a convenient convert.php script for the task:

<?php

$privateKeyContent = str_replace(["-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", "\r", "\n"], ["", "", "", ""], trim(file_get_contents('storage/oauth-private.key')));
$publicKeyContent = str_replace(["-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", "\r", "\n"], ["", "", "", ""], trim(file_get_contents('storage/oauth-public.key')));

echo "PASSPORT_PRIVATE_KEY=\"-----BEGIN PRIVATE KEY-----\n{$privateKeyContent}\n-----END PRIVATE KEY-----\"\n";
echo "PASSPORT_PUBLIC_KEY=\"-----BEGIN PUBLIC KEY-----\n{$publicKeyContent}\n-----END PUBLIC KEY-----\"";
0 comments

niels / Software / #laravel

Redis Sentinel with Laravel

As the use of Redis Sentinel with Laravel does not appear to be documented at the time of writing, I’m sharing the configuration I’m using.

This is the redis section of my config/database.php:

    'redis' => [

        'client' => env('REDIS_CLIENT', 'predis'),

        'options' => [

            // Don't set 'cluster' option. The only valid values are 'predis' and 'redis',
            // both conflict with sentinel replication.
            // 'cluster' => env('REDIS_CLUSTER', 'predis'),

            'prefix' => Str::slug(env('APP_NAME', 'laravel'), '_') . '_database_',
        ],

        'default' => env('REDIS_SENTINELS', false) ? array_merge(
            array_map(function ($host) {
                return "tcp://{$host}:26379?timeout=0.1";
            }, explode(',', env('REDIS_SENTINELS', ''))),
            [
                'options' => [
                    'replication' => 'sentinel',
                    'service' => 'mymaster',
                    'parameters' => [
                        'database' => 0,
                        'password' => env('REDIS_PASSWORD', null),
                    ],
                ],
            ]
        ) : [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'cache' => env('REDIS_SENTINELS', false) ? array_merge(
            array_map(function ($host) {
                return "tcp://{$host}:26379?timeout=0.1";
            }, explode(',', env('REDIS_SENTINELS', ''))),
            [
                'options' => [
                    'replication' => 'sentinel',
                    'service' => 'mymaster',
                    'parameters' => [
                        'database' => 1,
                        'password' => env('REDIS_PASSWORD', null),
                    ],
                ],
            ]
        ) : [
            'url' => env('REDIS_URL'),
            'host' => env('REDIS_HOST', '127.0.0.1'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ],

    ],

And this is what I have in my .env:

REDIS_SENTINELS=10.62.0.5,10.62.0.9,10.62.0.11,10.62.0.12
REDIS_HOST=10.62.0.5
REDIS_PASSWORD=null
REDIS_PORT=6379

Summary of what it does:

  • Define REDIS_SENTINELS and it will use the Sentinel configuration.
  • Omit or set to false REDIS_SENTINELS and it will use the regular stand-alone Redis.
  • Both Sentinel and non-Sentinel Laravel instances can operate in a mixed environment due to sharing the same prefixes.
0 comments

niels / Software / #filament,#laravel

Auto-reloading Filament (v3) panels using Vite

When integrating a Filament panel into your Laravel project, you might find that Vite’s auto-reloading feature isn’t functioning as expected. This issue arises because the panel isn’t loading Vite-managed resources.

While a long-term solution might involve crafting your own Filament theme that incorporates Vite, there’s a straightforward workaround available. By tweaking the AdminPanelProvider class to inject a Vite resource, you can ensure Vite’s auto-reloading works smoothly:

class AdminPanelProvider extends PanelProvider
{
    public function register(): void
    {
        parent::register();

        FilamentView::registerRenderHook(
            'panels::body.end',
            fn (): string => Blade::render("@vite('resources/js/app.js')"),
        );
    }

    public function panel(Panel $panel): Panel
    {
		  // ... stuff
	}
}

This modification results in the Filament panel loading the standard app.js. Even though it’s not essential within the panel, given that it’s a cached asset, its presence has minimal impact on performance.

0 comments