ventureleap/leap-one-storage-sdk
A PHP SDK for integrating the LeapOne Storage service into your applications, offering a simple client for managing and accessing stored files and assets. Install via Composer and configure credentials to add storage support to your Laravel or PHP project with minimal setup.
Install and inspect before you code.
composer require ventureleap/leap-one-storage-sdk
You will almost certainly also need a PSR-18 HTTP client and PSR-17 factories — the SDK is an OpenAPI-generated (Jane-style) client and does not ship its own transport:
composer require symfony/http-client nyholm/psr7
Where to look first, in this order:
vendor/ventureleap/leap-one-storage-sdk/README.md — usually the only human-written file; it documents host/JWT setup.vendor/ventureleap/leap-one-storage-sdk/src/ — the generated surface. The Api (or per-tag) classes are the real contract: every public method maps 1:1 to a storage endpoint (upload, list, download, delete, metadata). Treat the method signatures there as the documentation, not the README.vendor/ventureleap/leap-one-storage-sdk/src/Model/ — the DTOs you will actually pass around (File, Folder, StorageObject, pagination envelopes). Read the constructor signatures; most fields are nullable and validated only server-side.Credentials come from your LEAP ONE instance: a base host (e.g. https://<tenant>.leap-one.com) and a JWT. The token is normally obtained via ventureleap/leap-one-core-sdk (login) or provisioned as a service-account token for server-to-server use. Configure the client once, in a service provider:
use VentureLeap\LeapOneStorageSdk\Configuration;
$config = (new Configuration())
->setHost(config('services.leap_one.host'))
->setAccessToken(config('services.leap_one.token'));
First use case: upload a file and persist the returned identifier/URL against one of your own models. That single flow exercises auth, multipart handling, the response DTO shape, and the error path — which is 80% of what you'll hit day-to-day.
Wrap the client; never inject it raw. Generated clients are wide, unstable surfaces. Put a thin adapter behind an interface so your domain code doesn't import VentureLeap\... types:
interface AssetStorage
{
public function put(string $path, string $contents, string $mime): StoredAsset;
public function url(string $id): string;
public function delete(string $id): void;
}
Bind the concrete implementation in a service provider as a singleton — the client holds configuration and is safe to reuse, and rebuilding it per call is a needless token/host round-trip.
Configuration per environment. Drive host and token from config/services.php and .env. Never hardcode. In multi-tenant setups, build one client per tenant (keyed by tenant id) rather than mutating a shared config object — mutating is a classic source of cross-tenant leaks under Octane/queue workers.
Upload patterns. Two shapes dominate:
Token lifecycle. A JWT will expire mid-request eventually. Two options: mint a short-lived token per job from the core SDK, or install a PSR-18 middleware that catches 401, refreshes, and retries once. Do the retry at the transport layer, not scattered through call sites.
Pagination. LEAP ONE list endpoints are page/limit style. Write one iterator helper that loops until the returned collection is shorter than the limit; don't hand-roll for loops per endpoint.
Testing. Because the adapter is an interface, unit tests mock AssetStorage and never touch the SDK. For the adapter itself, use symfony/http-client's MockHttpClient and assert on the outgoing request (path, auth header, content type) and a canned JSON fixture — that's the only way to test generated code without a live tenant.
It is generated code — do not edit it in vendor/. Any patch vanishes on composer update. If the SDK is missing an endpoint or has a wrong type, fork it, or bypass the SDK for that one call with your own PSR-18 request. Pinning an exact version ("ventureleap/leap-one-storage-sdk": "1.2.3") matters more than usual here — with zero stars and zero dependents, a regeneration that renames a method will not be caught by anyone but you.
Error handling is coarse. Jane-style clients throw a single ApiException (or equivalent) carrying the HTTP status and raw body; you get no typed errors. Wrap every call, decode the body, and map 401/403/404/413 to domain exceptions yourself. A bare catch (\Throwable) around your whole upload path will hide genuine bugs.
Multipart + content-type quirks. Auto-generated multipart bodies often set the wrong or duplicate Content-Type header, and strict servers reject it. If uploads fail with a 400 that makes no sense, dump the raw request (PSR-18 logger middleware) before assuming your file is bad.
Large file / memory. The default Symfony HTTP client and cURL will happily buffer responses to disk or memory depending on config. For downloads, stream to a temp file and pass the stream on; never ->getContents() on a media response.
Silent nullability. Model DTOs are mostly nullable and won't validate locally. A missing required field surfaces as a server-side 422 with a body you must parse to know which field. Add a small assertion layer in your adapter for the two or three fields that are always required in practice.
Version drift against the tenant. The SDK is generated from one spec revision; your LEAP ONE instance may be older or newer. Symptoms: 404 on a method that exists in src/Api, or fields silently dropped from responses. Log the SDK version alongside the tenant on startup so this is diagnosable in five minutes rather than an afternoon.
Debugging. Register a logger middleware on the PSR-18 client (redacting the Authorization header) and keep it behind a config flag. With generated SDKs, the request log is your only real introspection — you cannot add breakpoints to code you didn't write.
Extension points are thin by design. There is no plugin system, no event dispatcher, no retry policy built in. Everything you want — retries, logging, auth refresh, caching of metadata — goes in the PSR-18 middleware stack or your adapter. Budget for that; it is the actual implementation work.
How can I help you explore Laravel packages today?