@laravelui5/core
v5.0.1
Published
A reusable tools library for OpenUI5 applications, including session and HTTP utilities.
Readme
@laravelui5/core
Shared frontend utilities for UI5 applications in local development.
This package provides a small, stable communication layer for UI5 applications that are developed independently of a Laravel host application.
In a full LaravelUi5 setup, the library is exposed as a UI5 resource by the host. During local UI5 development, this is not possible. In that case, the same library is consumed as a npm package and served via the UI5 tooling middleware instead.
No local PHP runtime is required. No build steps are introduced.
What this library is
- A lightweight helper library for UI5 applications
- Focused on HTTP communication with a Laravel backend
- Designed for the UI5 Tooling ecosystem (
ui5 serve,ui5 build) - Safe to use without custom transpilation or bundling
- Maintained as a long-term stable foundation
What this library is NOT
- Not a UI framework
- Not a UI5 component library
- Not a TypeScript transpilation solution
- Not tied to SAP BTP, CAP, or Fiori Launchpad
If you are looking for UI controls, layouts, or application scaffolding, this library is intentionally not the right place.
Installation
To consume the tools library in a UI5 application:
npm install @laravelui5/core --saveOr for local development via workspace:
{
"dependencies": {
"@laravelui5/core": "file:../ui5-core-lib"
}
}Use a local workspace dependency only when developing the library itself.
Basic Usage Model
The library exposes a single facade (LaravelUi5) which internally manages:
- A shared
Connectioninstance - CSRF token lifecycle
- Unified fetch behavior
- Centralized error handling
UI5 controllers and services never talk to fetch directly.
All outbound communication goes through this layer.
Architecture & Design Decisions
This library is designed around UI5’s actual runtime constraints, not its ideal future.
Key principles:
- No transpilation
- No generated artifacts
- No hidden build steps
- No runtime indirection
What you develop locally is exactly what runs in production.
TypeScript Strategy
UI5 does not natively support TypeScript transpilation or .ts source loading for ui5-workspace.yaml related libraries.
We use the following approach:
- Source code is authored in vanilla JavaScript using
sap.ui.defineor ES6 modules. - IntelliSense and type safety are enabled via handwritten
.d.tsfiles. - This avoids the overhead of custom build steps (
tsc,ui5-tooling-transpile) while maintaining dev comfort. .tsand.d.tsfiles are not required at runtime, keeping output clean.
Why? Because:
ui5 serverequires.jsinsrc/ui5 buildonly considerssrc/, notdist/(unless layered)ui5-workspace.yamlcurrently does not supportresourcePathoverrides (RFC 6)
Conclusion: We develop for UI5’s reality, not its ideal future.
Typing call() Responses
The facade's call() is typed as:
call<P = Record<string, any>, R = unknown>(
name: string,
params?: P | null,
body?: any
): Promise<R>;R defaults to unknown (not any) so consumers must either pass an explicit response type or narrow via type guards. This forces compile-time visibility of the response shape at every call site — there's no silent any slipping through.
Idiomatic usage:
interface LoginResponse { message: string; redirect: string }
const response = await LaravelUi5.call<Record<string, unknown>, LoginResponse>(
"io.pragmatiqu.auth.actions.login",
{},
payload
);
// response.redirect is string, fully typed end-to-end.Why not R = any? Because any silently disables the @typescript-eslint/no-unsafe-* rule family at every .redirect, .message, etc. access downstream — a strict consuming project loses its type guarantees without any lint signal. R = unknown keeps the safety on by default; opting into typed responses costs one generic argument.
This was a deliberate breaking change in the 5.0 release line; pre-5.0 call sites that omitted the generic must add <P, R> annotations or assert.
Integration in a UI5 Component
In your Component.ts initialize the Facade.
import UIComponent from "sap/ui/core/UIComponent";
import LaravelUi5 from "com/laravelui5/core/LaravelUi5";
export default class Component extends UIComponent {
public async init(): Promise<void> {
// Call the base component's init function
super.init();
// Do the usual stuff…
// …and finally start the Facade and the Router
LaravelUi5.init(this).then(() => {
// Initialize router
this.getRouter().initialize();
}).catch((error) => {
console.error(error);
});
}
}That’s it. The facade must never be instantiated manually elsewhere.
All HTTP communication, CSRF handling and error normalization is now handled centrally by the library.
Versioning & Compatibility
This package's version line diverged from the PHP Core (laravelui5/core) in April 2026 when the PHP package was reset from 4.x to 0.9.x. npm forbids version downgrades, so the JS package kept incrementing forward.
Current mapping:
| @laravelui5/core (npm) | laravelui5/core (Composer) |
|:---|:---|
| 5.x | 0.10.x |
| 4.3.x | 4.3.x (pre-reset) |
A given @laravelui5/core major must be paired with the corresponding PHP Core minor. Skewing across these pairings is unsupported.
Within either line:
- Major versions may introduce breaking changes (TS contract changes, runtime behavior shifts).
- Minor versions may add new helpers.
- Patch versions contain bug fixes only.
When publishing, decide the bump on the npm package's history (the only one npm sees) — but in the changelog and PR text, name the PHP Core release that ships in the same window for traceability.
Developing this Library Locally
This repository contains no build step.
- Source code lives in src/
- Type definitions live in types/
- No transpilation is performed
- No generated artifacts are committed
To test changes locally:
- Link the package via a file: dependency
- Run ui5 serve in the consuming app
- Reload the browser
If it works there, it will work in production.
Publishing (Maintainers only)
Releases are performed manually and intentionally. There is no CI publish pipeline by design — npm publish is a public, irreversible event and we want a human in the loop.
Prerequisites (one-time per machine)
- npm account with publish rights on the
@laravelui5org. 2FA strongly recommended (and required by npm for orgs). npm loginsucceeds andnpm whoamireturns your username. The session token is good for ~14 days; you'll re-login periodically.
Step 1 — Decide the version
The version is the only contract between this package and the world. Pick using strict semver based on the actual change set since the last published version:
- Major — any change that breaks downstream typecheck or runtime behavior. Examples: flipping a generic default (
R = any→R = unknown), removing a method, renaming exports, raising thepeerDependenciesUI5 minimum. - Minor — additive only. New helpers, new optional parameters with safe defaults, new exported types.
- Patch — bug fixes, doc fixes, internal refactors with no API surface change.
Check the current published version before bumping:
npm view @laravelui5/core versionThe new version must be strictly greater than that. npm rejects downgrades unconditionally, and npm unpublish is only available within 72 hours of publish — assume you cannot rewind.
If unsure between minor and patch: a published version is permanent, so erring on the higher side is the safer mistake.
Step 2 — Bump package.json
npm version <new-version> --no-git-tag-version--no-git-tag-version skips the auto-tag — the tag goes in at step 7, after publish succeeds. Prevents a stale tag if publish blows up.
You can also edit package.json by hand; same effect.
Step 3 — (Optional) Update the changelog and the README mapping
If the repo grows a CHANGELOG.md, add an entry at the top with the date, version, and a short list of changes. Reference the corresponding PHP Core release (e.g. "Ships alongside laravelui5/core 0.10.0") for traceability — see Versioning & Compatibility for the version-line mapping.
If the bump changes the public API in a way the README documents (a code example, the call() signature in Typing call() Responses, etc.), update the README in the same commit.
Step 4 — Verify the package contents
npm pack --dry-runRead the file list and confirm:
- ✅
src/**/*.js,types/**/*.d.ts,README.md,LICENSE.txt,package.json - ❌ No
dist/, nonode_modules/, no.mapfiles, nowebapp/, no test artifacts
The allowlist lives in package.json's files field. If something unintended slipped in, fix the files array before publishing rather than relying on .npmignore.
Step 5 — Log in to npm
npm whoami # if this returns 401, you're logged out
npm login # browser-based flow on npm 9+; complete in browser, return to terminalStep 6 — Publish
npm publish --access public--access public is required for the first publish of any new scoped package (@laravelui5/core); for subsequent publishes it's redundant but harmless. Including it always avoids the surprise of a publish accidentally going to restricted (paid private) on a fresh package.
If 2FA is enabled, npm prompts for an OTP during publish. The publish itself is atomic and synchronous — the new version is queryable via the registry within seconds.
Step 7 — Verify the publish
npm view @laravelui5/core versionShould print the version you just published. If it lags, give the registry up to a minute to settle.
Step 8 — Tag and push
git add package.json README.md # plus changelog if you touched one
git commit -m "release: <new-version>"
git tag v<new-version>
git push origin master --tagsThe tag locks the source state of the published artifact. If you ever need to bisect a regression to a specific release, the v<version> tag is what you git checkout.
Step 9 — Bump consumers
After the publish, update consuming UI5 apps (ui5-auth, ui5-offers, ui5-partners, etc.):
cd <consuming-app>
npm install @laravelui5/core@^<new-version>
npm run ts-typecheck # or whatever the project's verification command isFor a major bump, expect typecheck or lint to flag downstream call sites that need adjustment. Fix those before merging the consumer-side bump.
Recovery from a botched publish
- Wrong files in the tarball: publish a patch version with the corrected
filesarray. The wrong tarball stays available forever (as a yanked-but-resolvable version) but the higher patch wins for^x.y.zconstraints. - Wrong version label: same — publish a higher version with correct label. Don't try to unpublish unless within the 72-hour window AND the version has zero downloads, both of which are rare.
- Broken code shipped: publish a patch with the fix. If the broken version is causing real harm and is still within 72 hours,
npm unpublish @laravelui5/core@<version>is available — but treat as last resort because it confuses lockfile resolvers in consuming apps.
Why this is manual
Three reasons:
- Reversibility — npm publishes don't unpublish cleanly past 72 hours. A human checkpoint catches "wait, did I bump CHANGELOG?" before it becomes immortal.
- Version-line decisions — major vs. minor is a judgment call on the change set; CI can't make it.
- Consumer coordination — a major bump should ship with consumer-side fixes ready to land, which a release agent can't reason about.
CI can lint and dry-run-pack on every PR. Publishing stays in human hands.
Related Resources
- UI5 Tooling Docs
- UI5 Workspace RFC
- UI5 Types on npm (@openui5/types)
- ui5-tooling-transpile (not used)
- Why TypeScript is hard in UI5
Credits
Developed by Michael Gerzabek
