Changelog
Patch releases without an entry track backend contract updates: the clients and models are regenerated, and there are no SDK-level API changes. A contract update can bring new subtypes and enum values, and an older SDK can fail on a response that carries one it does not know, so upgrade regularly; see Compatibility. Contract changes and deprecations are listed on the developer portal’s API changes page.
Unreleased
- A refresh token the server refuses now ends the session: the SDK clears the stored tokens and calls
onRefreshFailureinstead of retrying the same token on every 401. The server’s reason decides when it sends one (NO_SESSIONorCREDENTIAL_REJECTED); otherwise a 400, 404, or 422 does. Other statuses, server errors, and network failures keep the session. - With token auth,
auth.refresh()throws aSoliboSDKErrorwhen the server refuses the refresh token, after ending the session. A 401 from the refresh endpoint now throws too, where it used to return. - When Cognito issues a device key and registering the device fails, sign-in fails with
DeviceRegistrationExceptionand the tokens it had stored are cleared, so nobody is left signed in without a registered device. A push token that cannot be fetched no longer fails sign-in; the device is registered without one. - Added
usePublicDocumentURL(params), the cached query form of the public document URL, andusePublicConversationDocumentURL(params)with its factorypublicConversationDocumentURLQueryOptions(sdk, params)for public conversation documents. Components that show the same picture share one request, and the hooks stay idle until every id is set. The conversation variant always asks for the URL, because that endpoint redirects by default.usePublicGetDocumentURLremains for downloads; every call is a new request. showDocumentUrlsandshowPublicDocumentUrlsonapi.documentssign up to 100 document URLs in one request and return them as a paged list, each with itsexpiresAt; passautoPaginate: trueto get them all at once.documentURLsQueryOptions/useDocumentURLsandpublicDocumentURLsQueryOptions/usePublicDocumentURLswrap them, andMockHomeApianswers both.useGetDocumentURL,usePublicDocumentURL, andusePublicGetDocumentURLsend the lookups a screen makes together as one of those requests per company and image rendition, so a page of pictures costs one request instead of one each. Their cache keys are unchanged. A lookup made alone, or withfields, keeps the single-document endpoint, and a document the batch leaves out fails with a 404 as before.FailureReason.DEVICE_REJECTED, sent when device sign-in cannot verify the remembered device, is classified as aDEFECT, as the bare 404 it replaces was. Sign-in then fails withDeviceRejectedException: the SDK forgets the device, and the next email or SMS sign-in sendshasDeviceSecret: false, so it finishes without a device challenge and registers a fresh device.FailureReason.INVOICING_NOT_ACTIVE, sent by the company invoicing routes when invoicing is not activated, is classified as the newFailureKind.FEATURE_OFFrather than aDEFECT: the app should show that invoicing is off. Kotlin code with an exhaustivewhenoverFailureKindneeds a branch for it.- The client no longer retries mutations. A
POST,PUT, orDELETEthat fails with a 5xx or a network error is sent once, because the server may already have applied it: retrying could send a letter or an invoice twice, or replay a one-time code. Reads are retried as before, and so is a request with anIdempotency-Keyheader (invoice direct send) or a 429 response, which the server did not process. After a failed write, read the resource before you try again. - Added
pushNotificationTypesQueryOptions/usePushNotificationTypesfor the newapi.communication.indexPushNotificationTypes, which lists every push notification type with the payload fields it carries. Push inbox items have a typedpayload,nullwhen the server matches no type:NewOppslagPushPayload,NewPracticalInfoPushPayload,NewMessageInConversationPushPayload,NewNeighborhoodPostPushPayload, orNewCommunicationCommentPushPayload.MockHomeApianswers the inbox and the type list. - The optimistic updates of
useCreateIssueToMeetinganduseRemoveIssueFromMeeting(and their*MutationOptions) now reach the datauseMeetinganduseIssuesshow: the issue enters or leaves every cached copy of the meeting, and its status changes on every loaded page of the company’s issue lists. They used to write to cache keys no query reads, and adding an issue withwithoutOptimisticUpdate: falsefailed with aTypeErrorbefore the request was sent. WithoutbeforeIndex, the new issue shows last. If the request fails, the queries are refetched as before. - Breaking for
useSectionStatusreaders:sectionStatusQueryOptions/useSectionStatusreturn the section’s statuses keyed by section id and then by status state (SectionStatusesBySection), as the backend now sends them, sodata[state]becomesdata[sectionId][state].api.sections.showSectionStatusreturns the matching nestedMap. upcomingInvoicingQueryOptions/useUpcomingInvoicingtakecompanyIdsto limit the invoicing preview to some housing communities; leave it out to include every one you can access. Kotlin’sindexUpcomingInvoicingtakescompanyIdsas its last argument, so positional calls keep their meaning.- The optimistic update of
useCreateConversationMessage(andcreateConversationMessageMutationOptions) now reaches the datauseConversationshows: the message appears at once in every cached copy of the conversation, whatever itstranslateToCountryIdorfields, anduseConversationMessageHistoryis left alone. It used to look for a cache key no query reads. The message has the shape of a fetchedMessageInConversationfrom the current user (sentByCurrentUser: true, andsentByIdfromuseUser, or-1before the user has loaded), with a negative placeholderidandsentAtas an ISO 8601 string. What only the server knows, such astype,sentBy, anddocuments, isnulluntil the refetch replaces the message. If the request fails, the conversation is refetched as before. conversationQueryOptionsanduseConversation()no longer retry a conversation the server refuses with a 4xx other than 408, 425, or 429. The check compared the error itself to404rather than itsstatus, so a missing conversation was requested four times per refetch.Homepageno longer hasfeedorpracticalInformation, because the backend stopped sending them:showHomepage/useHomepagereturn the company and itsimage. Load the posts withuseHomepageFeedanduseHomepagePracticalInformation, oruseOpenHomepageFeedanduseOpenHomepagePracticalInformationfor an open homepage.- Requests are no longer cut off at 30 s; the host in front of the backend decides how long one may run. A request may now take 500 s and go 500 s without data (15 s before, on Android, iOS and the JVM); connecting may still take 5 s. Shorten them per client with
install(HttpTimeout)inhttpClientConfig. A read is no longer retried after a read timeout or a 504, because the server may still be working on it; failed connections and other 5xx responses are retried as before. - Conversation attachments can be kept in the internal (board-only) thread: pass
visibility: 'INTERNAL'touseUploadDocumentBelongsTo(),useMultiUploadDocument(), oruseCreateDocumentReference()(and their...MutationOptionsfactories). Without it the backend treats the upload asPUBLIC, so files added to an internal message showed up in the public conversation. - An integrated document mutation that the backend refuses during finalization (a 4xx other than 408, 425 or 429) now fails at once with
outcomeUnknown = falseand removes its uploads. ThroughHomeApi.integratedDocumentssuch a refusal used to be retried and then reported as an unknown outcome with the uploads kept, because the client’s response validator threwSoliboSDKErrorbefore the helper could read the status.IntegratedDocumentMutationExceptionnow hasstatusCode, the status of the refusal, and itscauseis theSoliboSDKErrorwith the backend’s error details.
1.20.2 (2026-09-25)
- The JavaScript packages (
@solibo/solibo-sdkand@solibo/home-api) shipws8.21.3 for GHSA-96hv-2xvq-fx4p.
1.20.0 (2026-09-24)
- JavaScript behaviour change for
client.rawcallers: the JavaScript package converts collections at its boundary everywhere, so callers only use JS values. Arrays,Maps, and plain objects go intoclient.raw.api.*methods, model constructors, and setters; arrays andMaps come back from getters,HttpResponse.body(),HttpResponse.headers, callbacks, and helpers such ascreateUploadHeaders. A model constructed from JS reads back as JS, and a model received from the SDK can be handed back unchanged. No API signature refers toKtListorKtMapany more;KtList.fromJsArray/KtMap.fromJsMapremain exported for backwards compatibility but are never required. *WithDocumentsMutationOptionsanduse*WithDocuments()no longer fail withattachments.iterator_... is not a function, andclient.api.accounting.*acceptscompanyIds,accountNumbers,projectIds,departmentIds, andsupplierIdsagain.
1.19.0
- No API changes since 1.18.0.
- Public documentation now links to the developer portal and documents the telemetry bridges.
1.18.0
- Published the Sentry artifact,
no.solibo.oss:sdk-sentry, for Android and iOS. - Exported the route templates used by telemetry to the JavaScript package.
1.17.1
- Wrapped the bank account lists and the meeting summons PDF.
- Added
spamConversationandspamMultipleConversations, and theirunspam*counterparts, so a caller can flag a conversation as spam. - Decoded the server’s refusal reason into the contract’s enum.
- Built the iOS Sentry framework as a static framework.
1.17.0
- Instrumented every API call in OpenTelemetry’s terms. Install a provider with
SoliboOpenTelemetry.install(openTelemetry); the SDK bundles only theapiandnoopartifacts. - Added the
sdk-sentryartifact, which enriches the host application’s Sentry with the SDK’s spans (installSoliboSentryTelemetry()). SoliboSDKErrornow carries the kind of failure and the server’s reason, so callers can switch on why the server refused.- Optional fields tolerate values they did not expect instead of failing the whole response.
1.16.18
- Updated Kotlin, Fabrikt, Ktor, the Android Gradle plugin, AWS and logging dependencies.
1.16.17
- Generation converts the backend’s OpenAPI 3.1 contract to 3.0 before code generation, matching the backend’s move to OpenAPI 3.1.1.
1.16.15
- Query key factories trim trailing
undefinedarguments, fixing invalidation of keys built with optional parameters.
1.16.14
- Every OpenAPI parameter is forwarded through the
solibo-queryandsolibo-reactwrappers; callers now control parameters the wrappers previously pinned.
1.16.9
- Fixed the serialization test contract.
1.16.4
- Added supplier comment edit and delete wrappers.
1.16.0
- Toolchain and contract compatibility updates.
1.15.13
- Shared enum compatibility fixes.
1.14.0
- Fixed direct-password and SRP login returning
NEW_PASSWORDas failed credentials instead of a pending challenge. - Preserved reset-code and MFA flows and the Boolean confirmation API. Log in again after confirmation, and call
Auth.clearSession()when cancelling the challenge UI.
1.13.0
- Added company and multi-company accounting reads for overviews, projects and entries through
HomeApi.accountingandSoliboClient.api.accounting. - Added five dedicated query factories and React hooks with scoped cache keys, cursor pagination and field selection.
- Preserved exact monetary strings and company coverage metadata, including in Kotlin response projections.
1.10.0
- Added generated SDK, query-option, and React-hook coverage for homepage comments and neighborhood communication.
- Added atomic document convenience helpers for neighborhood posts and homepage/neighborhood comments, including cover-image retention and document removal on post updates.
- Added a dedicated homepage feed-post query for refreshing comment and reaction state.
1.9.0
Layered JavaScript API
The npm packages now expose one abstraction layer each:
@solibo/solibo-sdkowns the JavaScript client, generated models, authentication, event bus, and raw Kotlin interop.@solibo/solibo-queryowns framework-independent TanStack Query option factories, query keys, pagination helpers, and mutation definitions.@solibo/solibo-reactownsSoliboProvider,useSdk(), and React hooks.
SoliboClient is the JavaScript-native SDK surface. Its generated API methods take one named-parameter object and return the decoded response body. The unchanged Kotlin-generated client is available through client.raw and the @solibo/solibo-sdk/interop entry point when response status, headers, redirects, downloads, or another low-level capability is required.
import { createSoliboClient } from '@solibo/solibo-sdk'
const client = createSoliboClient({
baseUrl: 'https://home.solibo.no',
auth: {
kind: 'browser',
userPoolId: '...',
clientId: '...',
},
})
const company = await client.api.companies.showCompany({ companyId })
// Explicit escape hatch: positional parameters and HttpResponse<T>.
const response = await client.raw.api.companies.showCompany(BigInt(companyId))
JavaScript migration list
| Before | Now |
|---|---|
sdk.api.companies.showCompany(BigInt(companyId)).then(r => r.body()) | client.api.companies.showCompany({ companyId }) |
Pass a raw SoliboSDK to a query factory | Pass fromRawSdk(rawSdk), or the client returned by createSoliboClient(...) |
Import SDK models from @solibo/solibo-query or @solibo/solibo-react | Import them from @solibo/solibo-sdk |
Import query factories or keys from @solibo/solibo-react | Import them from @solibo/solibo-query |
| Import hooks from a lower package | Import hooks from @solibo/solibo-react |
| Use a facade call when status or headers matter | Use client.raw, which preserves HttpResponse<T> and request-header controls |
Import low-level Kotlin bridge or upload helpers from @solibo/solibo-query | Use the SDK facade/raw DocumentsApi, or a query mutation factory for the complete flow |
Import toIntegratedDocumentInput or prepareIntegratedDocumentSources from @solibo/solibo-query | Pass document sources to a *WithDocumentsMutationOptions factory, or use client.raw.api.integratedDocuments for the low-level composite API |
The root @solibo/solibo-sdk entry point retains its previous raw KMP exports, so existing direct SDK imports and positional calls continue to compile. The explicit client.raw property makes the low-level boundary visible in new code.