Search by

nawasara / search

pringgojsnawasara

Cross-domain search orchestrator for the Nawasara command palette (⌘K). Discovers per-package search providers and aggregates results behind one permission-aware endpoint.

Package info

github.com/nawasara/search

pkg:composer/nawasara/search

Statistics

Installs: 305

Dependents: 6

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-09-14 02:17 UTC

This package is auto-updated.

Last update: 2026-09-14 02:28:19 UTC


README

Cross-domain search orchestrator for Nawasara's command palette (⌘K). It collects providers from the data packages, filters them by the user's permissions, then runs them for each query.

Status v0.1.0

Feature Status
SearchProvider contract ready
Provider discovery via container binding ready
Permission filtering before a provider runs ready
Search endpoint for the palette ready
Cross-domain relevance ranking not built yet
Separate search index (instead of live queries) not built yet

How it works

This package stores no data of its own. It is only a broker: each data package registers its own provider, and SearchManager runs them all and merges the results.

The pattern follows WorkspaceManager in nawasara/ui. A new package just registers itself, without touching any code here.

Adding a provider from another package

Write a class that implements Nawasara\Search\Contracts\SearchProvider:

namespace Nawasara\Registry\Search;

use Nawasara\Search\Contracts\SearchProvider;

class OpdSearchProvider implements SearchProvider
{
    public function key(): string   { return 'opd'; }
    public function label(): string { return 'OPD'; }

    // null means visible to anyone who is logged in.
    public function permission(): ?string { return 'registry.opd.view'; }

    public function search(string $term, int $limit): array
    {
        return Opd::where('name', 'like', "%{$term}%")
            ->limit($limit)
            ->get()
            ->map(fn ($o) => [
                'label' => $o->name,
                'sublabel' => $o->code,
                'url' => route('nawasara-registry.opd.show', $o),
            ])
            ->all();
    }
}

Then register it in your package's ServiceProvider through the nawasara.search-providers binding.

search() runs on every keystroke

The palette calls it with a debounce, but it is still synchronous and still frequent. A slow provider slows down the whole palette, not just its own section.

So:

  • Search on indexed columns. LIKE %term% on an unindexed column scans the entire table every time someone types.
  • Respect $limit. It is a hard cap, not a suggestion.
  • Do not eager-load relations the result never uses.

Permissions are checked before a provider runs

SearchManager checks permission() first and skips any provider the user is not allowed to see, so its query never runs.

That is not only a performance win: search results reveal that data exists even when the content is not shown. Someone who types a name and sees "1 result in OPD" already knows the record is there.

Do not rely on filtering inside search() itself; that kind of filtering is easy to miss later when the query changes.

Roadmap

  • Cross-domain relevance ranking (results are currently grouped per provider)
  • A separate search index for large tables
  • Per-user search history

Author

Pringgo J. Saputro, Dinas Kominfo Kabupaten Ponorogo

License

MIT