Skip to content

TypeScript, Swift and Kotlin

Every namespace, method and type in the SDK API exists in all three languages:

LanguagePlatforms
TypeScriptWeb apps, desktop apps and the browser extension
SwiftiOS and macOS
KotlinAndroid

Only the syntax differs, by the rules in the rendering sheet. If you know one language’s SDK, you know the shape of the other two.

The rendering sheet

ConceptTypeScriptSwiftKotlin
Packagenpm install seald-sdkSPM .package(url: "https://github.com/seald-healthcare/seald-sdk", from: "1.0.0"), product SealdSDKGradle implementation("health.seald:sdk:1.0.0")
Importimport { create } from 'seald-sdk'import SealdSDKimport com.sealdhealthcare.sdk.*
Entryawait create({ kind: 'desktop', release: '1.4.0', adapters: { unlock, signIn } })try await SealdHealthcare.create(Config(kind: .mobile, release: "1.4.0", adapters: Adapters(unlock: unlock, signIn: signIn)))SealdHealthcare.create(Config(kind = ClientKind.MOBILE, release = "1.4.0", adapters = Adapters(unlock = unlock, signIn = signIn)))
AsyncPromise<T>async throws -> Tsuspend fun ...: T
Namesas writtenas written, enum cases lowerCamelCase (.notEntitled, .releaseBelowFloor, .accessRecord)as written, enum entries UPPER_SNAKE (DenyReason.NOT_ENTITLED, ErrorCode.RELEASE_BELOW_FLOOR)
Argumentspositional, option objectsfirst parameter unlabeled, later ones labeled with the TS parameter name. Option-object fields become trailing labeled parameters with defaults: open(_ ref: ObjectRef, action: OpenAction = .view)positional. Option fields become named parameters with defaults: open(ref: ObjectRef, action: OpenAction = OpenAction.VIEW)
Decided<T>union on outcomeenum Decided<T> { case allow(T, eventId: EventId); case deny(Denied); case challenge(Challenged<T>) }sealed interface Decided<out T> { data class Allow<T>(val value: T, val eventId: EventId); data class Deny(val eventId: EventId, val reason: DenyReason, val text: String); class Challenge<T>(val eventId: EventId) { suspend fun stepUp(): Decided<T> } }
Other unions (Opened, SaveOutcome, WorklistItem, ShareTarget, ShareInput, ExportScope, HoldTarget, Participation, Submitted)tag fieldenum with associated values, case per tag: .record(OpenedRecord), .file(OpenedFile), .saved(Saved), .baseMoved(BaseMoved), ShareTarget.person(p), .group("x")sealed interface, one class per tag: Opened.Record, Opened.File, SaveOutcome.Saved, SaveOutcome.BaseMoved, ShareTarget.ToPerson(p), ShareTarget.ToGroup("x")
save/create/saveDrafts result Decided<...> | Draftedcheck 'outcome' in resultenum SaveResult<T> { case decided(Decided<T>); case draft(Drafted) }sealed interface SaveResult<out T> { data class Decided<T>(val decided: com.sealdhealthcare.sdk.Decided<T>); data class Draft(val drafted: Drafted) }
ErrorsSealdHealthcareError with code, retryableenum SealdHealthcareError: Error one case per code, var retryable: Boolclass SealdHealthcareException(val code: ErrorCode, val retryable: Boolean) : Exception()
Bytes / streamsUint8Array / ReadableStream<Uint8Array>Data / AsyncThrowingStream<Data, Error>ByteArray / Flow<ByteArray>
Events client.onclient.on('session', ({ state }) => ...) returns Unsubscribefor await event in client.on(.session) { event.state } (an AsyncStream)client.on<ClientEvent.Session>().collect { event -> event.state } (a Flow)
DatesDate, Seconds numberDate, TimeIntervalInstant, Duration
Person{ iss, sub }Person(iss:sub:)Person(iss, sub)

Where the TypeScript API writes a shape inline, an unnamed union or an anonymous object, Swift and Kotlin give it a name: ObjectContent, DraftChoice, EnrollmentEvent, DomainScope, SaveResult for a result that may be a draft, SaveDraftsResult, DatasetRegistration, StorageBinding, S3Binding, DatabaseBinding, Contract, Change, MaskedField, RoleGrant, Times and Lifetimes. Each is declared on its namespace’s reference page.

A result that is an anonymous object with a single field unwraps to that field’s value in Swift and Kotlin:

  • Decided<{ escrowVersion: number }> is Decided<Int>.
  • Decided<{ root: Locator }> is Decided<Locator>.
  • Decided<{ lifted: boolean }> is Decided<Bool> in Swift and Decided<Boolean> in Kotlin.
  • Decided<{ ownerlessDomains: Locator[] }> is Decided<[Locator]> in Swift and Decided<List<Locator>> in Kotlin.
  • proveShare’s { held: boolean } is a plain Bool in Swift and Boolean in Kotlin.

TypeScript keeps the object. A result with more than one field keeps a named type, such as SaveDraftsResult.

A worked example

The same call, objects.open followed by the allowed helper, in all three languages:

const opened = await allowed(await client.objects.open({ locator }));

Each language calls open on objects with a locator. Only the syntax follows each language’s idiom. TypeScript’s option object becomes an unlabeled first parameter in Swift and Kotlin. Both wrap it in ObjectRef, which matches TypeScript’s { locator }.

A platform adds nothing to the surface. Platform-specific needs, such as a native key store, a share extension or a file provider, belong to that platform’s SDK. They are outside the SDK API.

Next