generator-pninja 1.2.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -10
- package/generators/app/index.js +49 -13
- package/generators/app/templates/package.json.ejs +23 -22
- package/generators/auth/index.js +27 -7
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/composer.json +39 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/config/keycloak.php +134 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/Exceptions/InvalidTokenException.php +50 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/JwksFetcher.php +271 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/KeycloakGuard.php +254 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/KeycloakGuardServiceProvider.php +52 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/Testing/ActingAsKeycloakUser.php +98 -0
- package/generators/auth/templates/packages/pninja/laravel-keycloak-guard/src/TokenDecoder.php +163 -0
- package/generators/client/index.js +39 -7
- package/generators/client/react.inc.js +142 -116
- package/generators/client/templates/react/.env.ejs +2 -1
- package/generators/client/templates/react/package-lock.json.ejs +7 -6
- package/generators/client/templates/react/package.json.ejs +1 -1
- package/generators/client/templates/react/public/locales/entities/entities.json.ejs +2 -2
- package/generators/client/templates/react/public/locales/migrations/am.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ar.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/az.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/bg.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/bn.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ca.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/cs.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/cy.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/da.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/de.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/el.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/en.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/es.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/et.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/eu.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/fa.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/fi.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/fr.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/fy.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ga.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/gl.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/gu.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ha.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/he.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/hi.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/hr.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ht.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/hu.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/hy.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/id.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/is.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/it.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ja.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/kk.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ko.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/lt.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/lv.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/mi.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ms.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/mt.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/nl.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/no.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/om.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/pl.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/pt.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ro.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ru.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/rw.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sk.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sl.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sq.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sr.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sv.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/sw.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ta.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/tr.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/uk.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/ur.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/uz.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/vi.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/yo.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/zh.json +43 -0
- package/generators/client/templates/react/public/locales/migrations/zu.json +43 -0
- package/generators/client/templates/react/public/locales/searchReindex/am.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ar.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/az.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/bg.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/bn.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ca.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/cs.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/cy.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/da.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/de.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/el.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/en.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/es.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/et.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/eu.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/fa.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/fi.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/fr.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/fy.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ga.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/gl.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/gu.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ha.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/he.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/hi.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/hr.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ht.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/hu.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/hy.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/id.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/is.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/it.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ja.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/kk.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ko.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/lt.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/lv.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/mi.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ms.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/mt.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/nl.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/no.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/om.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/pl.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/pt.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ro.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ru.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/rw.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sk.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sl.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sq.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sr.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sv.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/sw.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ta.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/tr.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/uk.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/ur.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/uz.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/vi.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/yo.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/zh.json +60 -0
- package/generators/client/templates/react/public/locales/searchReindex/zu.json +60 -0
- package/generators/client/templates/react/public/locales/seeder/am.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ar.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/az.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/bg.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/bn.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ca.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/cs.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/cy.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/da.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/de.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/el.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/en.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/es.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/et.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/eu.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/fa.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/fi.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/fr.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/fy.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ga.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/gl.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/gu.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ha.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/he.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/hi.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/hr.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ht.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/hu.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/hy.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/id.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/is.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/it.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ja.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/kk.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ko.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/lt.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/lv.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/mi.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ms.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/mt.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/nl.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/no.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/om.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/pl.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/pt.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ro.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ru.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/rw.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sk.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sl.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sq.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sr.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sv.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/sw.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ta.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/tr.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/uk.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/ur.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/uz.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/vi.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/yo.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/zh.json +32 -0
- package/generators/client/templates/react/public/locales/seeder/zu.json +32 -0
- package/generators/client/templates/react/src/App.tsx.ejs +40 -3
- package/generators/client/templates/react/src/components/LangSelect.tsx.ejs +1 -1
- package/generators/client/templates/react/src/components/Menu.tsx.ejs +40 -9
- package/generators/client/templates/react/src/components/Toast.tsx.ejs +3 -3
- package/generators/client/templates/react/src/components/entities/EntityForm.tsx.ejs +21 -21
- package/generators/client/templates/react/src/components/formElements/RadioGroup.tsx.ejs +1 -1
- package/generators/client/templates/react/src/i18n.js.ejs +1 -1
- package/generators/client/templates/react/src/index.css.ejs +1 -5
- package/generators/client/templates/react/src/pages/admin/Migrations.tsx.ejs +427 -0
- package/generators/client/templates/react/src/pages/search-reindex/SearchReindexList.tsx.ejs +716 -0
- package/generators/client/templates/react/src/pages/seeder/SeederList.tsx.ejs +478 -0
- package/generators/client/templates/react/src/shared/entitiesIcons.tsx.ejs +1 -3
- package/generators/client/templates/react/src/shared/model/entity.model.ts.ejs +4 -4
- package/generators/client/utils/getEntityFillableProperties.js +6 -6
- package/generators/client/utils/getModelForeignIds.js +16 -16
- package/generators/client/utils/getModelRelatedEntities.js +39 -43
- package/generators/entities/index.js +114 -117
- package/generators/entities/templates/EntityFactory.php.ejs +0 -11
- package/generators/entities/templates/database/seeders/AcRuleSeeder.php.ejs +83 -0
- package/generators/entities/templates/database/seeders/DatabaseSeeder.php.ejs +28 -0
- package/generators/entities/templates/database/seeders/EntitySeeder.php.ejs +30 -0
- package/generators/entities/templates/database/seeders/ManyToManySeeder.php.ejs +20 -0
- package/generators/entities/templates/database/seeders/csv/.gitkeep +0 -0
- package/generators/entities/templates/migration_add_columns_to_table.php.ejs +27 -0
- package/generators/entities/templates/migration_create_table.php.ejs +1 -1
- package/generators/entities/templates/migration_remove_columns_from_table.php.ejs +27 -0
- package/generators/entities/templates/migration_remove_pivot_table.php.ejs +24 -0
- package/generators/entities/utils/controllers-generator.js +151 -180
- package/generators/entities/utils/entity-splitter.js +204 -0
- package/generators/entities/utils/factories-generator.js +79 -73
- package/generators/entities/utils/migrations-generator.js +285 -149
- package/generators/entities/utils/models-generator.js +189 -199
- package/generators/entities/utils/routers-generator.js +15 -14
- package/generators/entities/utils/validateJDL.js +139 -0
- package/generators/entity/index.js +1016 -0
- package/generators/final/index.js +3 -1
- package/generators/final/templates/README.md.ejs +109 -1
- package/generators/search/index.js +112 -82
- package/generators/server/index.js +121 -0
- package/generators/server/templates/.gitkeep.ejs +0 -0
- package/generators/server/templates/ApiErrorHandler.php.ejs +31 -0
- package/generators/server/templates/DatabaseErrorHandler.php.ejs +154 -0
- package/generators/server/templates/NotFoundErrorHandler.php.ejs +41 -0
- package/generators/server/templates/Providers/AppServiceProvider.php.ejs +53 -0
- package/generators/server/templates/ValidationErrorHandler.php.ejs +27 -0
- package/generators/server/templates/app/Http/Controllers/MigrationsController.php.ejs +56 -0
- package/generators/server/templates/app/Http/Controllers/SearchReindexController.php.ejs +133 -0
- package/generators/server/templates/app/Http/Controllers/SeederController.php.ejs +75 -0
- package/generators/{entities → server}/templates/app/Http/Middleware/AccessControl.php.ejs +3 -0
- package/generators/server/templates/app/Http/Requests/ReindexRequest.php.ejs +32 -0
- package/generators/server/templates/app/Http/Requests/SeedCsvRequest.php.ejs +13 -0
- package/generators/server/templates/app/Http/Requests/SeedRequest.php.ejs +34 -0
- package/generators/server/templates/app/Jobs/ReindexEntityJob.php.ejs +63 -0
- package/generators/server/templates/app/Jobs/RunMigrationsJob.php.ejs +46 -0
- package/generators/server/templates/app/Jobs/RunSeederJob.php.ejs +43 -0
- package/generators/server/templates/app/Resolvers/Keycloak__UserResolver.php.ejs +34 -0
- package/generators/server/templates/app/Traits/HandlesApiErrors.php.ejs +39 -0
- package/generators/server/templates/app/Traits/HandlesUserRoles.php.ejs +90 -0
- package/generators/server/templates/app/Traits/SeederHelpers.php.ejs +56 -0
- package/generators/server/templates/app.php.ejs +31 -0
- package/generators/server/templates/config/audit.php.ejs +202 -0
- package/generators/server/templates/config/lauthz-rbac-model.conf +14 -0
- package/generators/server/templates/config/lauthz.php +70 -0
- package/generators/server/templates/database/migrations/create_ac_rules_table.php.ejs +28 -0
- package/generators/server/templates/database/migrations/create_audits_table.php.ejs +52 -0
- package/generators/server/templates/filesystems.php.ejs +81 -0
- package/generators/{entities → server}/templates/routes/api.php.ejs +39 -2
- package/generators/{entities → server}/templates/routes/console.php.ejs +1 -1
- package/generators/utils/AcRule.js +44 -2
- package/generators/utils/entities-utils.js +114 -0
- package/generators/utils/getWiths.js +21 -24
- package/generators/utils/hello.js +2 -2
- package/generators/utils/reserved-words.js +39 -0
- package/package.json +1 -1
- package/generators/entities/templates/DatabaseSeeder.php.ejs +0 -179
- package/generators/entities/templates/app/Http/Controllers/AcRuleController.php.ejs +0 -151
- package/generators/entities/templates/app/Models/AcRule.php.ejs +0 -37
- package/generators/entities/templates/database/seeders/csv/AcRule.csv.ejs +0 -7
- package/generators/router/index.js +0 -12
- /package/generators/{entities → client}/templates/blobs/dummy.pdf +0 -0
- /package/generators/{entities → client}/templates/blobs/dummy.png +0 -0
- /package/generators/{entities → server}/templates/Casts/Base64BinaryCast.php.ejs +0 -0
- /package/generators/{entities → server}/templates/Rules/Base64MaxSize.php.ejs +0 -0
- /package/generators/{entities → server}/templates/Rules/Base64MinSize.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/AuditController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/FileController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/KeycloakProxyController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/LogController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/ScoutQuerySanitizer.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/SessionAuthController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Controllers/UserRoleController.php.ejs +0 -0
- /package/generators/{entities → server}/templates/app/Http/Middleware/SessionAuth.php.ejs +0 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# generator-pninja
|
|
6
6
|
|
|
7
7
|
Generate a full **Laravel + React + Vite** application from a single **JDL model**.
|
|
8
|
-
Backend + Frontend + Docker + Database
|
|
8
|
+
Backend + Frontend + Docker + Database – ready in seconds ⚡
|
|
9
9
|
|
|
10
10
|
[![License][license-badge]][license-url]
|
|
11
11
|
[![npm version][npm-version-badge]][npm-version-url]
|
|
@@ -15,7 +15,7 @@ Backend + Frontend + Docker + Database — ready in seconds ⚡
|
|
|
15
15
|
|
|
16
16
|
## License
|
|
17
17
|
|
|
18
|
-
This project is licensed under the Apache License 2.0
|
|
18
|
+
This project is licensed under the Apache License 2.0 – see the [LICENSE.txt](LICENSE.txt) file for details.
|
|
19
19
|
|
|
20
20
|
## What is PNinja?
|
|
21
21
|
|
|
@@ -27,7 +27,7 @@ This project is licensed under the Apache License 2.0 — see the [LICENSE.txt](
|
|
|
27
27
|
- **Search engine:** Database, Algolia, Elasticsearch, Meilisearch, Typesense, Solr
|
|
28
28
|
- **Docker Compose**
|
|
29
29
|
|
|
30
|
-
All based on
|
|
30
|
+
All based on **JDL files** describing your domain!
|
|
31
31
|
|
|
32
32
|
## Installation
|
|
33
33
|
|
|
@@ -39,6 +39,18 @@ npm install -g yo generator-pninja
|
|
|
39
39
|
|
|
40
40
|
## Usage
|
|
41
41
|
|
|
42
|
+
### 1. Create the Application
|
|
43
|
+
|
|
44
|
+
Generate the base application structure (server + client without entities):
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
yo pninja
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Answer a few prompts** ... and you're ready ⚡
|
|
51
|
+
|
|
52
|
+
### 2. Generate Entities from JDL
|
|
53
|
+
|
|
42
54
|
**Create your entity definition file using JDL:**
|
|
43
55
|
|
|
44
56
|
```bash
|
|
@@ -48,13 +60,34 @@ touch entities.jdl # or any other name of your choice
|
|
|
48
60
|
and edit it using this guide:
|
|
49
61
|
https://www.jhipster.tech/jdl/intro/
|
|
50
62
|
|
|
51
|
-
**Run the generator:**
|
|
63
|
+
**Run the entities generator:**
|
|
52
64
|
|
|
53
65
|
```bash
|
|
54
|
-
yo pninja
|
|
66
|
+
yo pninja:entities entities.jdl
|
|
55
67
|
```
|
|
56
68
|
|
|
57
|
-
|
|
69
|
+
You can run this command multiple times with different JDL files:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
yo pninja:entities core-entities.jdl
|
|
73
|
+
yo pninja:entities additional-entities.jdl
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 3. Interactive Entity Creation (Alternative)
|
|
77
|
+
|
|
78
|
+
For incremental development or to modify entities individually, use the **entity sub-generator**:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
yo pninja:entity [EntityName]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This interactive command allows you to:
|
|
85
|
+
|
|
86
|
+
- Create new entities step by step
|
|
87
|
+
- Add or remove fields and relationships
|
|
88
|
+
- Update existing entities (regenerate, add, or remove)
|
|
89
|
+
|
|
90
|
+
All entity configurations are stored in `.pninja/<EntityName>.json` files.
|
|
58
91
|
|
|
59
92
|
## What you get
|
|
60
93
|
|
|
@@ -63,6 +96,7 @@ my-app/
|
|
|
63
96
|
├── client/ # React + Vite app
|
|
64
97
|
├── docker/ # Docker compose
|
|
65
98
|
├── server/ # Laravel project
|
|
99
|
+
├── .pninja/ # Entity configurations
|
|
66
100
|
├── package.json # With commands
|
|
67
101
|
└── README.md
|
|
68
102
|
```
|
|
@@ -80,15 +114,19 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
|
|
|
80
114
|
### Data Management
|
|
81
115
|
|
|
82
116
|
- **Soft Delete Support** - Logical deletion with `deleted_at` timestamps (use `@softDelete` annotation in JDL)
|
|
83
|
-
|
|
117
|
+
|
|
118
|
+
```jdl
|
|
84
119
|
@softDelete
|
|
85
120
|
entity MyEntity {
|
|
86
121
|
name String required
|
|
87
122
|
description String
|
|
88
123
|
}
|
|
89
|
-
|
|
124
|
+
```
|
|
125
|
+
|
|
90
126
|
- **CSV Database Seeding** - Populate your database from CSV files
|
|
91
127
|
- **Audit Logging** - Complete change tracking for all entity modifications
|
|
128
|
+
- **Interactive Entity Generator** - Create and modify entities through CLI prompts
|
|
129
|
+
- **Incremental Migrations** - Automatic database migrations for entity changes
|
|
92
130
|
|
|
93
131
|
### Search & Indexing
|
|
94
132
|
|
|
@@ -112,13 +150,15 @@ Fully wired together: auth, routing, forms, CRUD, migrations.
|
|
|
112
150
|
- **Responsive Design** - Mobile-first approach
|
|
113
151
|
- **Tailwind CSS** - Utility-first styling
|
|
114
152
|
- **Material Symbols Icons** - Associate icons to entities using `@icon` annotation in JDL
|
|
115
|
-
|
|
153
|
+
|
|
154
|
+
```jdl
|
|
116
155
|
@icon("star")
|
|
117
156
|
entity MyEntity {
|
|
118
157
|
name String required
|
|
119
158
|
description String
|
|
120
159
|
}
|
|
121
|
-
|
|
160
|
+
```
|
|
161
|
+
|
|
122
162
|
- **Component Library** - Pre-built accessible components
|
|
123
163
|
|
|
124
164
|
### DevOps Ready
|
package/generators/app/index.js
CHANGED
|
@@ -12,13 +12,37 @@ const __dirname = path.dirname(__filename);
|
|
|
12
12
|
export default class extends Generator {
|
|
13
13
|
constructor(args, opts) {
|
|
14
14
|
super(args, opts);
|
|
15
|
-
this.option('
|
|
16
|
-
type:
|
|
17
|
-
|
|
15
|
+
this.option('name', {
|
|
16
|
+
type: String,
|
|
17
|
+
description: 'Your project name'
|
|
18
18
|
});
|
|
19
|
+
this.option('dmbs', {
|
|
20
|
+
type: String,
|
|
21
|
+
description: 'Your DBMS'
|
|
22
|
+
});
|
|
23
|
+
this.option('authentication', {
|
|
24
|
+
type: String,
|
|
25
|
+
description: 'The type of authentication to use',
|
|
26
|
+
});
|
|
27
|
+
this.option('clientType', {
|
|
28
|
+
type: String,
|
|
29
|
+
description: 'The type of client to use',
|
|
30
|
+
});
|
|
31
|
+
this.option('nativeLanguage', {
|
|
32
|
+
type: String,
|
|
33
|
+
description: 'The native language of the application',
|
|
34
|
+
});
|
|
35
|
+
this.option('languages', {
|
|
36
|
+
type: String,
|
|
37
|
+
description: 'Additional languages to install (comma separated)',
|
|
38
|
+
});
|
|
39
|
+
this.option('searchEngine', {
|
|
40
|
+
type: String,
|
|
41
|
+
description: 'The search engine to use (database, algolia, elastic, meilisearch, typesense, solr, null)',
|
|
42
|
+
})
|
|
19
43
|
}
|
|
20
44
|
async initializing() {
|
|
21
|
-
hello(this.log);
|
|
45
|
+
hello(this.log, true);
|
|
22
46
|
this.log(`\n${colors.whiteBright('Application files will be generated in folder:')} ${colors.yellow(process.env.PWD)}\n`);
|
|
23
47
|
|
|
24
48
|
// sub generator Auth
|
|
@@ -31,22 +55,23 @@ export default class extends Generator {
|
|
|
31
55
|
}, {
|
|
32
56
|
fromMain: true,
|
|
33
57
|
env: this.env,
|
|
58
|
+
authentication: this.options.authentication,
|
|
34
59
|
resolved: authGeneratorPath,
|
|
35
60
|
namespace: 'pninja:auth'
|
|
36
61
|
});
|
|
37
62
|
|
|
38
|
-
// sub generator
|
|
39
|
-
const
|
|
40
|
-
const { default:
|
|
63
|
+
// sub generator Server
|
|
64
|
+
const serverGeneratorPath = path.resolve(__dirname, '../server/index.js');
|
|
65
|
+
const { default: ServerGenerator } = await import(serverGeneratorPath);
|
|
41
66
|
|
|
42
67
|
await this.composeWith({
|
|
43
|
-
Generator:
|
|
44
|
-
path: path.dirname(
|
|
68
|
+
Generator: ServerGenerator,
|
|
69
|
+
path: path.dirname(serverGeneratorPath)
|
|
45
70
|
}, {
|
|
46
71
|
fromMain: true,
|
|
47
72
|
env: this.env,
|
|
48
|
-
resolved:
|
|
49
|
-
namespace: 'pninja:
|
|
73
|
+
resolved: serverGeneratorPath,
|
|
74
|
+
namespace: 'pninja:server'
|
|
50
75
|
});
|
|
51
76
|
|
|
52
77
|
// sub generator Client
|
|
@@ -58,6 +83,9 @@ export default class extends Generator {
|
|
|
58
83
|
}, {
|
|
59
84
|
fromMain: true,
|
|
60
85
|
env: this.env,
|
|
86
|
+
clientType: this.options.clientType,
|
|
87
|
+
nativeLanguage: this.options.nativeLanguage,
|
|
88
|
+
languages: this.options.languages,
|
|
61
89
|
resolved: clientGeneratorPath,
|
|
62
90
|
namespace: 'pninja:client'
|
|
63
91
|
});
|
|
@@ -73,6 +101,7 @@ export default class extends Generator {
|
|
|
73
101
|
fromMain: true,
|
|
74
102
|
env: this.env,
|
|
75
103
|
resolved: searchGeneratorPath,
|
|
104
|
+
searchEngine: this.options.searchEngine,
|
|
76
105
|
namespace: 'pninja:search'
|
|
77
106
|
});
|
|
78
107
|
|
|
@@ -105,18 +134,25 @@ export default class extends Generator {
|
|
|
105
134
|
});
|
|
106
135
|
}
|
|
107
136
|
async prompting() {
|
|
137
|
+
if (this.options.name && this.options.dbms) {
|
|
138
|
+
this.answers = {
|
|
139
|
+
name: this.options.name,
|
|
140
|
+
dbms: this.options.dbms
|
|
141
|
+
};
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
108
144
|
this.answers = await this.prompt([
|
|
109
145
|
{
|
|
110
146
|
type: "input",
|
|
111
147
|
name: "name",
|
|
112
148
|
message: "Your project name",
|
|
113
|
-
default: this.config.get('name') || this.appname // Default to current folder name
|
|
149
|
+
default: this.options.name || this.config.get('name') || this.appname // Default to current folder name
|
|
114
150
|
}, {
|
|
115
151
|
store: true,
|
|
116
152
|
type: "list",
|
|
117
153
|
name: "dbms",
|
|
118
154
|
message: "Your DBMS",
|
|
119
|
-
default: this.config.get('dbms') || 'sqlite',
|
|
155
|
+
default: this.options.dbms || this.config.get('dbms') || 'sqlite',
|
|
120
156
|
choices: [
|
|
121
157
|
{
|
|
122
158
|
name: `SQLite ${colors.dim('(Lightweight, serverless, file-based)')}`,
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"db:seed": "cd server && php artisan db:seed",
|
|
2
|
+
"name": "<%= packageName %>",
|
|
3
|
+
"description": "<%= projectDescription %>",
|
|
4
|
+
"version": "<%= projectVersion %>",
|
|
5
|
+
"author": "<%= authorName %>",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"dependencies": {},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "concurrently \"npm run server\" \"npm run queue:listen\" \"npm run client\"",
|
|
10
|
+
"client": "cd client && npm i --loglevel=error && npm run dev",
|
|
11
|
+
"dump-server": "cd server && php artisan dump-server",
|
|
12
|
+
"migrate": "cd server && php artisan migrate",
|
|
13
|
+
"migrate:fresh": "cd server && php artisan migrate:fresh",
|
|
14
|
+
"migrate:fresh:seed": "cd server && php artisan migrate:fresh --seed",
|
|
15
|
+
"migrate:seed": "cd server && php artisan migrate --seed",
|
|
16
|
+
"db:seed": "cd server && php artisan db:seed",
|
|
18
17
|
<% if (searchEngine === 'elastic') { -%>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
"elastic:migrate": "cd server && php artisan elastic:migrate",
|
|
19
|
+
"elastic:migrate:reset": "cd server && php artisan elastic:migrate:reset",
|
|
20
|
+
"elastic:migrate:refresh": "cd server && php artisan elastic:migrate:refresh",
|
|
22
21
|
<% } -%>
|
|
23
22
|
<% if (searchEngine === 'meilisearch') { -%>
|
|
24
|
-
|
|
23
|
+
"scout:sync-index-settings": "cd server && php artisan scout:sync-index-settings",
|
|
25
24
|
<% } -%>
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
"seed": "cd server && php artisan db:seed",
|
|
26
|
+
"server": "cd server && php artisan serve",
|
|
27
|
+
"queue:listen": "cd server && php artisan queue:listen",
|
|
28
|
+
"queue:work": "cd server && php artisan queue:work"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"concurrently": "^9.2.1"
|
package/generators/auth/index.js
CHANGED
|
@@ -14,9 +14,17 @@ export default class AuthGenerator extends Generator {
|
|
|
14
14
|
type: Boolean,
|
|
15
15
|
default: false
|
|
16
16
|
});
|
|
17
|
+
this.option('authentication', {
|
|
18
|
+
type: String,
|
|
19
|
+
description: 'The type of authentication to use',
|
|
20
|
+
});
|
|
17
21
|
}
|
|
18
22
|
|
|
19
23
|
async prompting() {
|
|
24
|
+
if (this.options.authentication) {
|
|
25
|
+
this.answers = { authentication: this.options.authentication };
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
20
28
|
let prompts = [];
|
|
21
29
|
if (this.options["fromMain"]) {
|
|
22
30
|
prompts = [...prompts, ...[{
|
|
@@ -24,6 +32,7 @@ export default class AuthGenerator extends Generator {
|
|
|
24
32
|
type: "list",
|
|
25
33
|
name: "authentication",
|
|
26
34
|
message: `Which ${colors.yellow('*type*')} of authentication would you like to use?`,
|
|
35
|
+
default: this.options.authentication || this.config.get('authentication') || 'keycloak',
|
|
27
36
|
choices: [
|
|
28
37
|
{ name: 'Keycloak', value: 'keycloak' },
|
|
29
38
|
{ name: 'Sanctum', value: 'sanctum', disabled: "Not implemented yet" },
|
|
@@ -46,9 +55,10 @@ export default class AuthGenerator extends Generator {
|
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
48
57
|
if (this.answers.authentication === 'keycloak') {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
this.fs.copy(
|
|
59
|
+
this.templatePath('packages/pninja/laravel-keycloak-guard/**'),
|
|
60
|
+
this.destinationPath('server/packages/pninja/laravel-keycloak-guard')
|
|
61
|
+
);
|
|
52
62
|
const envContent = this.fs.read(this.destinationPath(`server/.env`));
|
|
53
63
|
this.fs.write(this.destinationPath('server/.env'), envContent + `
|
|
54
64
|
FRONTEND_URL=http://localhost:5173
|
|
@@ -57,16 +67,13 @@ KEYCLOAK_BASE_URL=https://sso.yourkeycloakbaseurl.net/auth
|
|
|
57
67
|
KEYCLOAK_REALM=yourrealm
|
|
58
68
|
KEYCLOAK_CLIENT_ID=yourclientid
|
|
59
69
|
KEYCLOAK_CLIENT_SECRET=yourclientsecret
|
|
60
|
-
KEYCLOAK_REALM_PUBLIC_KEY="yourrealmpublickey"
|
|
70
|
+
# KEYCLOAK_REALM_PUBLIC_KEY="yourrealmpublickey"
|
|
61
71
|
KEYCLOAK_LOAD_USER_FROM_DATABASE=false
|
|
62
72
|
KEYCLOAK_USER_PROVIDER_CREDENTIAL=username
|
|
63
73
|
KEYCLOAK_TOKEN_PRINCIPAL_ATTRIBUTE=preferred_username
|
|
64
74
|
KEYCLOAK_IGNORE_RESOURCES_VALIDATION=true
|
|
65
75
|
KEYCLOAK_USE_SERVICE_ACCOUNT=true`, { encoding: 'utf8', flag: 'w' });
|
|
66
76
|
|
|
67
|
-
if (this.fs.exists(`${this.destinationPath('server')}/config/auth.php`)) {
|
|
68
|
-
fs.unlinkSync(`${this.destinationPath('server')}/config/auth.php`);
|
|
69
|
-
}
|
|
70
77
|
this.fs.copyTpl(this.templatePath("keycloak.auth.php.ejs"), `${this.destinationPath('server')}/config/auth.php`);
|
|
71
78
|
let bootstrapAppFileContents = fs.readFileSync(`${this.destinationPath('server')}/bootstrap/app.php`, { encoding: 'utf8', flag: 'r' });
|
|
72
79
|
const regexprBootstrapAppUse = /(?=use Illuminate\\Foundation\\Application;)/gmis;
|
|
@@ -86,4 +93,17 @@ KEYCLOAK_USE_SERVICE_ACCOUNT=true`, { encoding: 'utf8', flag: 'w' });
|
|
|
86
93
|
fs.writeFileSync(`${this.destinationPath('server')}/bootstrap/app.php`, bootstrapAppFileContents, { encoding: 'utf8', flag: 'w' });
|
|
87
94
|
}
|
|
88
95
|
}
|
|
96
|
+
async install() {
|
|
97
|
+
if (this.config.get('authentication') === 'keycloak') {
|
|
98
|
+
const composerPath = this.destinationPath('server/composer.json');
|
|
99
|
+
const composerContent = JSON.parse(fs.readFileSync(composerPath, { encoding: 'utf8' }));
|
|
100
|
+
composerContent.repositories = composerContent.repositories || [];
|
|
101
|
+
composerContent.repositories.push({
|
|
102
|
+
type: "path",
|
|
103
|
+
url: "./packages/pninja/laravel-keycloak-guard"
|
|
104
|
+
});
|
|
105
|
+
fs.writeFileSync(composerPath, JSON.stringify(composerContent, null, 2), { encoding: 'utf8' });
|
|
106
|
+
await this.spawn('composer', ['require', 'pninja/laravel-keycloak-guard:@dev'], { cwd: 'server' });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
89
109
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pninja/laravel-keycloak-guard",
|
|
3
|
+
"description": "Keycloak JWT Guard for Laravel — without firebase/php-jwt",
|
|
4
|
+
"type": "library",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"require": {
|
|
7
|
+
"php": "^8.2",
|
|
8
|
+
"ext-openssl": "*",
|
|
9
|
+
"lcobucci/jwt": "^5.4",
|
|
10
|
+
"lcobucci/clock": "^3.3",
|
|
11
|
+
"illuminate/auth": "^11.0",
|
|
12
|
+
"illuminate/support": "^11.0",
|
|
13
|
+
"illuminate/http": "^11.0"
|
|
14
|
+
},
|
|
15
|
+
"require-dev": {
|
|
16
|
+
"orchestra/testbench": "^9.0",
|
|
17
|
+
"pestphp/pest": "^3.0",
|
|
18
|
+
"phpunit/phpunit": "^11.0"
|
|
19
|
+
},
|
|
20
|
+
"autoload": {
|
|
21
|
+
"psr-4": {
|
|
22
|
+
"Pninja\\KeycloakGuard\\": "src/"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"autoload-dev": {
|
|
26
|
+
"psr-4": {
|
|
27
|
+
"Pninja\\KeycloakGuard\\Tests\\": "tests/"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"extra": {
|
|
31
|
+
"laravel": {
|
|
32
|
+
"providers": [
|
|
33
|
+
"Pninja\\KeycloakGuard\\KeycloakGuardServiceProvider"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"minimum-stability": "stable",
|
|
38
|
+
"prefer-stable": true
|
|
39
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
return [
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
|--------------------------------------------------------------------------
|
|
7
|
+
| Keycloak Server URL
|
|
8
|
+
|--------------------------------------------------------------------------
|
|
9
|
+
| Base URL of your Keycloak instance, e.g. https://keycloak.example.com
|
|
10
|
+
| Required when using JWKS discovery (realm_public_key left empty).
|
|
11
|
+
*/
|
|
12
|
+
'base_url' => env('KEYCLOAK_BASE_URL', ''),
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
|--------------------------------------------------------------------------
|
|
16
|
+
| Keycloak Realm
|
|
17
|
+
|--------------------------------------------------------------------------
|
|
18
|
+
*/
|
|
19
|
+
'realm' => env('KEYCLOAK_REALM', 'master'),
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
|--------------------------------------------------------------------------
|
|
23
|
+
| Realm Public Key (static)
|
|
24
|
+
|--------------------------------------------------------------------------
|
|
25
|
+
| The RS256 public key copied from:
|
|
26
|
+
| Realm Settings → Keys → RS256 row → Public Key button
|
|
27
|
+
|
|
|
28
|
+
| If left empty, the guard will fetch keys dynamically from the JWKS
|
|
29
|
+
| endpoint: {base_url}/realms/{realm}/protocol/openid-connect/certs
|
|
30
|
+
|
|
|
31
|
+
| Example (without BEGIN/END headers):
|
|
32
|
+
| KEYCLOAK_REALM_PUBLIC_KEY=MIIBIjANBgkqhk...
|
|
33
|
+
*/
|
|
34
|
+
'realm_public_key' => env('KEYCLOAK_REALM_PUBLIC_KEY', ''),
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
|--------------------------------------------------------------------------
|
|
38
|
+
| Token Encryption Algorithm
|
|
39
|
+
|--------------------------------------------------------------------------
|
|
40
|
+
| Supported: RS256, RS384, RS512, ES256, ES384, ES512, HS256, HS384, HS512
|
|
41
|
+
*/
|
|
42
|
+
'token_encryption_algorithm' => env('KEYCLOAK_TOKEN_ENCRYPTION_ALGORITHM', 'RS256'),
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
|--------------------------------------------------------------------------
|
|
46
|
+
| Load User From Database
|
|
47
|
+
|--------------------------------------------------------------------------
|
|
48
|
+
| When true the guard calls Auth::user() retrieving the user from DB.
|
|
49
|
+
| When false it builds a user object directly from the JWT claims.
|
|
50
|
+
*/
|
|
51
|
+
'load_user_from_database' => env('KEYCLOAK_LOAD_USER_FROM_DATABASE', true),
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
|--------------------------------------------------------------------------
|
|
55
|
+
| User Provider Custom Method
|
|
56
|
+
|--------------------------------------------------------------------------
|
|
57
|
+
| When set, this method is called on the UserProvider instead of
|
|
58
|
+
| retrieveByCredentials(). It receives the full decoded token.
|
|
59
|
+
*/
|
|
60
|
+
'user_provider_custom_retrieve_method' => env('KEYCLOAK_USER_PROVIDER_CUSTOM_METHOD', null),
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
|--------------------------------------------------------------------------
|
|
64
|
+
| User Provider Credential (DB field)
|
|
65
|
+
|--------------------------------------------------------------------------
|
|
66
|
+
| The column in your users table used to look up the user.
|
|
67
|
+
*/
|
|
68
|
+
'user_provider_credential' => env('KEYCLOAK_USER_PROVIDER_CREDENTIAL', 'username'),
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
|--------------------------------------------------------------------------
|
|
72
|
+
| Token Principal Attribute (JWT claim)
|
|
73
|
+
|--------------------------------------------------------------------------
|
|
74
|
+
| The claim in the JWT token that maps to user_provider_credential.
|
|
75
|
+
*/
|
|
76
|
+
'token_principal_attribute' => env('KEYCLOAK_TOKEN_PRINCIPAL_ATTRIBUTE', 'preferred_username'),
|
|
77
|
+
|
|
78
|
+
/*
|
|
79
|
+
|--------------------------------------------------------------------------
|
|
80
|
+
| Append Decoded Token
|
|
81
|
+
|--------------------------------------------------------------------------
|
|
82
|
+
| When true the decoded token claims are appended to the user object
|
|
83
|
+
| as the `token` attribute.
|
|
84
|
+
*/
|
|
85
|
+
'append_decoded_token' => env('KEYCLOAK_APPEND_DECODED_TOKEN', false),
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
|--------------------------------------------------------------------------
|
|
89
|
+
| Allowed Resources
|
|
90
|
+
|--------------------------------------------------------------------------
|
|
91
|
+
| Comma-separated list of Keycloak client IDs whose resource_access
|
|
92
|
+
| must be present in the token. Leave empty to skip resource validation.
|
|
93
|
+
|
|
|
94
|
+
| Example: KEYCLOAK_ALLOWED_RESOURCES=my-api,another-api
|
|
95
|
+
*/
|
|
96
|
+
'allowed_resources' => env('KEYCLOAK_ALLOWED_RESOURCES', ''),
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
|--------------------------------------------------------------------------
|
|
100
|
+
| Ignore Resources Validation
|
|
101
|
+
|--------------------------------------------------------------------------
|
|
102
|
+
| Set to true to completely skip resource_access validation.
|
|
103
|
+
*/
|
|
104
|
+
'ignore_resources_validation' => env('KEYCLOAK_IGNORE_RESOURCES_VALIDATION', false),
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
|--------------------------------------------------------------------------
|
|
108
|
+
| Leeway (seconds)
|
|
109
|
+
|--------------------------------------------------------------------------
|
|
110
|
+
| Clock skew tolerance between your server and Keycloak.
|
|
111
|
+
| Useful when you get "token not yet valid" / "token expired" errors.
|
|
112
|
+
*/
|
|
113
|
+
'leeway' => env('KEYCLOAK_LEEWAY', 0),
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
|--------------------------------------------------------------------------
|
|
117
|
+
| Input Key
|
|
118
|
+
|--------------------------------------------------------------------------
|
|
119
|
+
| When set, the guard also looks for a token in this request parameter
|
|
120
|
+
| in addition to the Authorization: Bearer header.
|
|
121
|
+
| Example: KEYCLOAK_INPUT_KEY=api_token
|
|
122
|
+
*/
|
|
123
|
+
'input_key' => env('KEYCLOAK_INPUT_KEY', ''),
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
|--------------------------------------------------------------------------
|
|
127
|
+
| JWKS Cache TTL (seconds)
|
|
128
|
+
|--------------------------------------------------------------------------
|
|
129
|
+
| How long to cache the remote JWKS response.
|
|
130
|
+
| Set to 0 to disable caching (not recommended in production).
|
|
131
|
+
*/
|
|
132
|
+
'jwks_cache_ttl' => env('KEYCLOAK_JWKS_CACHE_TTL', 300),
|
|
133
|
+
|
|
134
|
+
];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace Pninja\KeycloakGuard\Exceptions;
|
|
6
|
+
|
|
7
|
+
use Exception;
|
|
8
|
+
|
|
9
|
+
class InvalidTokenException extends Exception
|
|
10
|
+
{
|
|
11
|
+
public static function missingToken(): self
|
|
12
|
+
{
|
|
13
|
+
return new self('No token provided in request.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public static function invalidSignature(): self
|
|
17
|
+
{
|
|
18
|
+
return new self('Token signature verification failed.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static function expired(): self
|
|
22
|
+
{
|
|
23
|
+
return new self('Token has expired.');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static function notYetValid(): self
|
|
27
|
+
{
|
|
28
|
+
return new self('Token is not yet valid.');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public static function invalidResource(): self
|
|
32
|
+
{
|
|
33
|
+
return new self('Token does not contain any of the allowed resources.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static function jwksFetchFailed(string $url, string $reason): self
|
|
37
|
+
{
|
|
38
|
+
return new self("Failed to fetch JWKS from {$url}: {$reason}");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public static function publicKeyNotResolved(): self
|
|
42
|
+
{
|
|
43
|
+
return new self('Could not resolve a public key for the token.');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public static function unsupportedAlgorithm(string $alg): self
|
|
47
|
+
{
|
|
48
|
+
return new self("Unsupported token algorithm: {$alg}");
|
|
49
|
+
}
|
|
50
|
+
}
|