feat: registerPage types, ability registry, member and invoice readers (module_api 1.3.0) - #8
Merged
Merged
Conversation
…aders Introduces module_api 1.3.0: PageContribution and registerPage on the frontend extension API (and fixes the settings-page return types), Registry::registerAbility with slug-namespaced ability ids that the host merges into its ability catalogue, and CompanyDataReader::companyMembers and existingInvoiceIds for modules that assign work to members or stamp entries against invoices. Stubs now target SDK ^3.4 and dist/init.js.
The scaffold's module.json now declares php ^8.4.0 to match the composer stub, and the ability registry docblock uses plain punctuation.
6 tasks
registerMenu and registerUserMenu now reject a non-integer priority or an empty group, and the README explains how group and priority place an entry among the core sidebar groups.
gdarko
force-pushed
the
feat/page-route-abilities-members
branch
from
September 14, 2026 21:56
9ca7eab to
84bbfcf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Raises the module contract to
module_api1.3.0 with three additions the next batch of official modules needs.1.
registerPageand page route types (frontend/index.d.ts)New
PageRouteMeta,PageChildContribution, andPageContributioninterfaces, plusregisterPage(contribution: PageContribution): () => voidonInvoiceShelfExtensionApi.A page mounts at
/admin/modules/{module}/{path}where{module}is themodule.jsonslug;settingsstays reserved for the host's schema-rendered settings page.meta.abilitycarries thenamespaced ability id(s) the host route guard checks, and
childrendeclares sub-routes relative tothe page.
2.
Registry::registerAbility(src/Registry.php)A new
Registry::$abilitiesbucket (slug => namespacedId => entry) lets a module contribute its ownpermissions to the host ability catalogue instead of reusing host ones. Entries are stored namespaced
as
{slug}:{ability}so modules can never collide with host abilities or with each other:The normalised entry is exactly
['ability', 'name', 'model', 'depends_on', 'owner_only']in that keyorder, which is what the host role editor and
CompanyService::setupRolesread. Validation follows theregisterAiDriverprecedent: validate first, re-registering an identical entry is a no-op, a conflictingredefinition throws an
InvalidArgumentExceptionnaming the slug.depends_onaccepts host abilities inplain form and the module's own in namespaced form;
modelmust be absent or null (module abilities arenever model-scoped).
flush()now clears abilities alongside the other module-contributed state.New public API:
Registry::registerAbility(string $slug, array $entry): voidRegistry::abilitiesFor(string $slug): arrayRegistry::allAbilities(): arrayRegistry::abilityId(string $slug, string $ability): string3.
CompanyDataReader::companyMembers/existingInvoiceIdsFor modules that assign work to company members or stamp their entries against invoices. The interface
docblock no longer claims to be the AI assistant's "twelve built-in queries" — it now describes the
boundary generically and notes the reader also serves other official modules.
findCustomerandsearchCustomersnow document thecurrency_id/currencypayload they already return.Settings-page return types
The brief called for fixing
registerCompanySettingsPage/registerAdminSettingsPageto return() => void. No change was needed — both already declare() => voidonmaster(fixed in0a536f0). The commit message mentions the fix; the declaration was already correct.
Stubs
stubs/json.stub:module_api^1.2.0->^1.3.0,assets->["dist/init.js", "dist/style.css"]stubs/composer.stub:php^8.3->^8.4,invoiceshelf/modules^3.3->^3.4tests/ManifestTest.phpstub assertions updated to match (and now also pin the stubassetsvalue)Tests
composer run test: OK (145 tests, 378 assertions) — 17 new, all green.composer run lint: pass.New coverage in
RegistryTest: ability round trip (exact stored shape and key order, namespaced id,abilitiesFor,allAbilitiesordering across two slugs),abilityId(), idempotent re-registration,conflicting duplicate (asserts the slug appears in the message and the first registration survives),
depends_onwith both plain and namespaced ids, a 10-case DataProvider of invalid registrations, unknownslug, and
flush().AiContractsTest's exact-method-list assertion now includes the two new reader methods.Follow-ups
Host (InvoiceShelf 3.x):
registerPagein the extension runtime: mount/admin/modules/{slug}/{path}with children, guard onmeta.ability, and reject the reservedsettingspath.companyMembers()andexistingInvoiceIds()on the host'sCompanyDataReader(currently the only implementor — this is a breaking interface change for it).Registry::allAbilities()into the ability catalogue the role editor renders andCompanyService::setupRolesconsumes.module_apirange to include 1.3.0.SDK:
invoiceshelf/modules: ^3.4, which does not exist yet.stubs/json.stub'scompatibility.phpshould move to^8.4.0. It still says^8.3.0whilecomposer.stubnow requires^8.4, so a freshly scaffolded module is internally inconsistent. Left as-is because it was out of scope for this change.RELEASING.mdstill pins the reusable workflow example at@3.3.0; update when 3.4.0 is tagged.Modules:
registerPage+registerAbilityend to end to validate the contract before 3.4.0 ships.https://claude.ai/code/session_01DCf36XDKprZifej8dc2r1E