@independo/capacitor-inderun 1.1.0-dev.4 → 1.1.0-dev.5
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/Package.swift +18 -5
- package/README.md +98 -9
- package/android/build.gradle.kts +12 -6
- package/android/settings.gradle +7 -0
- package/android/src/main/kotlin/app/independo/inderun/capacitor/IndeRunCapacitorPlugin.kt +35 -0
- package/android/src/main/kotlin/app/independo/inderun/capacitor/IndeRunSerializer.kt +97 -0
- package/android/src/test/kotlin/app/independo/inderun/capacitor/IndeRunSerializerCapabilitiesTest.kt +253 -0
- package/android/src/test/kotlin/app/independo/inderun/capacitor/IndeRunSerializerTest.kt +79 -0
- package/dist/definitions.d.ts +122 -1
- package/dist/definitions.d.ts.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/web.d.ts +2 -1
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +66 -7
- package/ios/Sources/IndeRunCapacitorPlugin/IndeRunCapacitorBridge.swift +60 -0
- package/ios/Sources/IndeRunCapacitorPlugin/IndeRunCapacitorPlugin.swift +25 -4
- package/ios/Tests/IndeRunCapacitorTests/IndeRunCapacitorBridgeTests.swift +234 -0
- package/package.json +3 -3
|
@@ -142,6 +142,29 @@ class IndeRunSerializerTest {
|
|
|
142
142
|
|
|
143
143
|
// --- encodeError ---
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* `systemModel` and `onnx` are web-only bootstrap keys, like
|
|
147
|
+
* `allowDirectOpenAIEndpoint`. Android registers its own on-device provider, so it must
|
|
148
|
+
* ignore them rather than fail on the options object that carries them.
|
|
149
|
+
*/
|
|
150
|
+
@Test
|
|
151
|
+
fun `parseConfigureOptions ignores the web-only provider bootstrap keys`() {
|
|
152
|
+
val options = IndeRunSerializer.parseConfigureOptions(
|
|
153
|
+
JSONObject(
|
|
154
|
+
"""
|
|
155
|
+
{
|
|
156
|
+
"openAI": { "model": "gpt-5.2", "auth": "none" },
|
|
157
|
+
"systemModel": { "id": "local.system-model.web", "timeoutMs": 30000 },
|
|
158
|
+
"onnx": { "modelPackage": { "id": "demo", "format": "onnx" } }
|
|
159
|
+
}
|
|
160
|
+
""".trimIndent()
|
|
161
|
+
)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
assertEquals("gpt-5.2", options.openAI?.model)
|
|
165
|
+
assertEquals("none", options.openAI?.auth)
|
|
166
|
+
}
|
|
167
|
+
|
|
145
168
|
@Test
|
|
146
169
|
fun `encodeError produces correct shape with required fields only`() {
|
|
147
170
|
val encoded = IndeRunSerializer.encodeError(
|
|
@@ -177,4 +200,60 @@ class IndeRunSerializerTest {
|
|
|
177
200
|
assertEquals(2000L, encoded.getLong("retryAfterMs"))
|
|
178
201
|
assertEquals("run_abc", encoded.getString("runId"))
|
|
179
202
|
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* A routing refusal carries its plan diagnostics on the error's `details`, and since
|
|
206
|
+
* inderun 0.3.0 it does so on iOS and Android too, not just on the web SDK. The shape
|
|
207
|
+
* is nested — a `rejectedProviders` array of objects, each with its own `reasons`
|
|
208
|
+
* array — and `encodeError` hands the whole map to `JSONObject(Map)`, which deep-wraps
|
|
209
|
+
* via `wrap()`. Nothing asserted that before; this is the data a provider-refusal UI
|
|
210
|
+
* actually reads, so a regression here would be invisible until a demo showed an empty
|
|
211
|
+
* table.
|
|
212
|
+
*/
|
|
213
|
+
@Test
|
|
214
|
+
fun `encodeError preserves nested route-plan diagnostics in details`() {
|
|
215
|
+
val encoded = IndeRunSerializer.encodeError(
|
|
216
|
+
IndeRunError(
|
|
217
|
+
errorClass = IndeRunErrorClass.CapabilityMismatch,
|
|
218
|
+
message = "No eligible provider can stream this request.",
|
|
219
|
+
details = mapOf(
|
|
220
|
+
"failureCode" to "CapabilityMismatch",
|
|
221
|
+
"rejectedProviders" to listOf(
|
|
222
|
+
mapOf(
|
|
223
|
+
"providerId" to "android.mlkit.genai",
|
|
224
|
+
"reasons" to listOf(
|
|
225
|
+
mapOf(
|
|
226
|
+
"code" to "streaming_not_supported",
|
|
227
|
+
"message" to "Provider does not declare streaming."
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
),
|
|
231
|
+
mapOf(
|
|
232
|
+
"providerId" to "openai",
|
|
233
|
+
"reasons" to listOf(
|
|
234
|
+
mapOf("code" to "privacy_constraint", "message" to "local_required forbids cloud.")
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
)
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
val details = encoded.getJSONObject("details")
|
|
243
|
+
assertEquals("CapabilityMismatch", details.getString("failureCode"))
|
|
244
|
+
|
|
245
|
+
val rejected = details.getJSONArray("rejectedProviders")
|
|
246
|
+
assertEquals(2, rejected.length())
|
|
247
|
+
assertEquals("android.mlkit.genai", rejected.getJSONObject(0).getString("providerId"))
|
|
248
|
+
assertEquals(
|
|
249
|
+
"streaming_not_supported",
|
|
250
|
+
rejected.getJSONObject(0).getJSONArray("reasons").getJSONObject(0).getString("code")
|
|
251
|
+
)
|
|
252
|
+
assertEquals("openai", rejected.getJSONObject(1).getString("providerId"))
|
|
253
|
+
assertEquals(
|
|
254
|
+
"privacy_constraint",
|
|
255
|
+
rejected.getJSONObject(1).getJSONArray("reasons").getJSONObject(0).getString("code")
|
|
256
|
+
)
|
|
257
|
+
}
|
|
258
|
+
|
|
180
259
|
}
|
package/dist/definitions.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PluginListenerHandle } from "@capacitor/core";
|
|
2
|
-
import type { IndeRunError, StreamEvent, StreamRunHandle, TaskRequest, TaskResult } from "@independo/inderun-contracts";
|
|
2
|
+
import type { IndeRunError, ModelPackage, StreamEvent, StreamRunHandle, TaskRequest, TaskResult } from "@independo/inderun-contracts";
|
|
3
3
|
export interface OpenAIProviderBootstrapOptions {
|
|
4
4
|
model: string;
|
|
5
5
|
endpointUrl?: string;
|
|
@@ -7,8 +7,50 @@ export interface OpenAIProviderBootstrapOptions {
|
|
|
7
7
|
authContextRef?: string;
|
|
8
8
|
timeoutMs?: number;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Bootstrap options for the browser-managed on-device provider (Chrome's Prompt API).
|
|
12
|
+
*
|
|
13
|
+
* **Web only**, and ignored on iOS and Android, which register their own on-device
|
|
14
|
+
* providers — Apple Foundation Models and ML Kit GenAI — from `configure()` regardless.
|
|
15
|
+
*
|
|
16
|
+
* The browser owns model availability, download and execution, so there is nothing to
|
|
17
|
+
* configure: registering it is the whole point, and it is what makes
|
|
18
|
+
* `constraints.privacy = "local_required"` routable in a browser. Mode 1 only — this
|
|
19
|
+
* provider does not stream, so a `local_required` *stream* on the web is still refused at
|
|
20
|
+
* routing time.
|
|
21
|
+
*
|
|
22
|
+
* The web SDK's `runtime` injection seam is deliberately not exposed: it is a function,
|
|
23
|
+
* and `configure()` has to survive a JSON bridge hop on native.
|
|
24
|
+
*/
|
|
25
|
+
export interface SystemModelProviderBootstrapOptions {
|
|
26
|
+
id?: string;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Bootstrap options for the Web ONNX Runtime provider, for a developer-supplied local
|
|
31
|
+
* model.
|
|
32
|
+
*
|
|
33
|
+
* **Web only**, like `systemModel`, and Mode 1 only.
|
|
34
|
+
*
|
|
35
|
+
* Two caveats worth knowing before reaching for this. The consumer has to install the
|
|
36
|
+
* optional `@huggingface/transformers` peer dependency — this bridge does not declare it —
|
|
37
|
+
* and supply real model weights, because the web SDK's `runtime` seam is a function and so
|
|
38
|
+
* cannot cross the JSON bridge hop: only the default Transformers.js runtime is reachable
|
|
39
|
+
* from here, never the fixture runtime the upstream demos use offline. A registered
|
|
40
|
+
* provider that cannot load turns a clean routing refusal into a provider error, so
|
|
41
|
+
* register it only when the weights are actually there.
|
|
42
|
+
*/
|
|
43
|
+
export interface OnnxProviderBootstrapOptions {
|
|
44
|
+
id?: string;
|
|
45
|
+
modelPackage: ModelPackage;
|
|
46
|
+
timeoutMs?: number;
|
|
47
|
+
}
|
|
10
48
|
export interface ConfigureOptions {
|
|
11
49
|
openAI?: OpenAIProviderBootstrapOptions;
|
|
50
|
+
/** Web only; native registers its own on-device provider. */
|
|
51
|
+
systemModel?: SystemModelProviderBootstrapOptions;
|
|
52
|
+
/** Web only; native registers its own on-device provider. */
|
|
53
|
+
onnx?: OnnxProviderBootstrapOptions;
|
|
12
54
|
allowDirectOpenAIEndpoint?: boolean;
|
|
13
55
|
}
|
|
14
56
|
/**
|
|
@@ -53,9 +95,88 @@ export interface StreamRun {
|
|
|
53
95
|
events: AsyncIterable<StreamEvent>;
|
|
54
96
|
cancel(reason?: string): void;
|
|
55
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* A provider's static capability declaration.
|
|
100
|
+
*
|
|
101
|
+
* Declared here rather than imported, because — unlike `TaskRequest`, `StreamEvent` and
|
|
102
|
+
* the rest — this shape is *not* a generated contract. There is no schema for it in
|
|
103
|
+
* `@independo/inderun-contracts` and no validator; each SDK declares it independently
|
|
104
|
+
* (`core/provider.d.ts` in `@independo/inderun-web`, `IndeRunCore/Provider.swift`,
|
|
105
|
+
* `core/Provider.kt`), and this is the fourth copy. Importing it from
|
|
106
|
+
* `@independo/inderun-web` is not an option either: that would make the native
|
|
107
|
+
* platforms' plugin contract depend on the web SDK.
|
|
108
|
+
*
|
|
109
|
+
* The drift guard is in `web.ts`, which returns the web SDK's value into this type
|
|
110
|
+
* uncast — so `tsc` proves the shapes still match on every build, the same way the
|
|
111
|
+
* `StreamRun` mirror below is checked. See the upstream follow-up asking for a schema.
|
|
112
|
+
*/
|
|
113
|
+
export interface ProviderDescriptor {
|
|
114
|
+
id: string;
|
|
115
|
+
type: "local" | "edge" | "cloud";
|
|
116
|
+
transport: "in_process" | "system_service" | "http" | "sse" | "realtime";
|
|
117
|
+
streamingStyle?: "tokens" | "chunks" | "snapshots";
|
|
118
|
+
supports: {
|
|
119
|
+
run: boolean;
|
|
120
|
+
streaming: boolean;
|
|
121
|
+
realtime: boolean;
|
|
122
|
+
tools: boolean;
|
|
123
|
+
reasoningEvents: boolean;
|
|
124
|
+
structuredOutput: boolean;
|
|
125
|
+
multimodal: boolean;
|
|
126
|
+
};
|
|
127
|
+
cancel: "hard" | "soft" | "none";
|
|
128
|
+
tasks: string[];
|
|
129
|
+
limits?: {
|
|
130
|
+
maxInputTokens?: number;
|
|
131
|
+
maxOutputTokens?: number;
|
|
132
|
+
maxImageBytes?: number;
|
|
133
|
+
maxAudioSeconds?: number;
|
|
134
|
+
};
|
|
135
|
+
privacy?: {
|
|
136
|
+
dataLeavesDevice: boolean;
|
|
137
|
+
regions?: string[];
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A provider's live availability, as of the moment `checkCapabilities()` was called.
|
|
142
|
+
*
|
|
143
|
+
* `streamingAvailable` and `cancellationAvailable` are **absent**, not `null`, when the
|
|
144
|
+
* runtime has nothing to say: absence means *inherit the static declaration*
|
|
145
|
+
* (`descriptor.supports.streaming`, and `descriptor.cancel !== "none"`). Both native
|
|
146
|
+
* encoders omit the key rather than emitting null for exactly that reason.
|
|
147
|
+
*/
|
|
148
|
+
export interface ProviderDynamicCapabilities {
|
|
149
|
+
available: boolean;
|
|
150
|
+
reason?: string;
|
|
151
|
+
streamingAvailable?: boolean;
|
|
152
|
+
streamingUnavailableReason?: string;
|
|
153
|
+
cancellationAvailable?: boolean;
|
|
154
|
+
}
|
|
155
|
+
/** One registered provider's identity, static declaration, and live availability. */
|
|
156
|
+
export interface ProviderCapabilitySnapshot {
|
|
157
|
+
providerId: string;
|
|
158
|
+
descriptor: ProviderDescriptor;
|
|
159
|
+
capabilities: ProviderDynamicCapabilities;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Envelope for `checkCapabilities()`. The array is wrapped because a Capacitor plugin
|
|
163
|
+
* method must resolve an object on both native platforms — `PluginCall.resolve(JSObject)`
|
|
164
|
+
* and `call.resolve([String: Any])` cannot carry a top-level array. `IndeRunCapacitor`
|
|
165
|
+
* and `createIndeRunCapacitor()` unwrap it, so app code sees the same
|
|
166
|
+
* `ProviderCapabilitySnapshot[]` the three platform SDKs return.
|
|
167
|
+
*/
|
|
168
|
+
export interface CheckCapabilitiesResult {
|
|
169
|
+
providers: ProviderCapabilitySnapshot[];
|
|
170
|
+
}
|
|
56
171
|
export interface IndeRunCapacitorPlugin {
|
|
57
172
|
configure(options?: ConfigureOptions): Promise<void>;
|
|
58
173
|
run(request: TaskRequest): Promise<TaskResult>;
|
|
174
|
+
/**
|
|
175
|
+
* Live snapshot of every registered provider, without executing a task. Availability
|
|
176
|
+
* changes between calls — a local model can unload, cloud credentials can expire — so
|
|
177
|
+
* do not cache it across a `run()` or `stream()`.
|
|
178
|
+
*/
|
|
179
|
+
checkCapabilities(): Promise<CheckCapabilitiesResult>;
|
|
59
180
|
/**
|
|
60
181
|
* Unlike `run(request)`, which passes the request at the options root, this nests it
|
|
61
182
|
* under `request` so the envelope can also carry `streamId`. Both native decode sites
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,eAAe,EACf,WAAW,EACX,UAAU,EACX,MAAM,8BAA8B,CAAC;AAEtC,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,8BAA8B,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,6FAA6F;AAC7F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IACnC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,WAAW,CACT,SAAS,EAAE,oBAAoB,EAC/B,YAAY,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAC5D,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,WAAW,CACT,SAAS,EAAE,oBAAoB,EAC/B,YAAY,EAAE,CAAC,YAAY,EAAE,uBAAuB,KAAK,IAAI,GAC5D,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC"}
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../src/definitions.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import type { TaskRequest, TaskResult } from "@independo/inderun-contracts";
|
|
2
|
-
import type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPlugin as IndeRunCapacitorPluginContract, OpenAIProviderBootstrapOptions, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun } from "./definitions.js";
|
|
2
|
+
import type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPlugin as IndeRunCapacitorPluginContract, OnnxProviderBootstrapOptions, OpenAIProviderBootstrapOptions, ProviderCapabilitySnapshot, ProviderDescriptor, ProviderDynamicCapabilities, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, SystemModelProviderBootstrapOptions } from "./definitions.js";
|
|
3
3
|
/**
|
|
4
4
|
* The plugin contract plus the ergonomic Mode 2 entry point. `stream()` is not a
|
|
5
5
|
* plugin method — it is `startStream`, the event listeners, and `cancelStream`
|
|
6
6
|
* reassembled into the same shape the platform SDKs return from `stream()`.
|
|
7
7
|
*/
|
|
8
|
-
export interface IndeRunCapacitorApi extends IndeRunCapacitorPluginContract {
|
|
8
|
+
export interface IndeRunCapacitorApi extends Omit<IndeRunCapacitorPluginContract, "checkCapabilities"> {
|
|
9
9
|
stream(request: TaskRequest): Promise<StreamRun>;
|
|
10
|
+
/** The plugin's `{ providers }` envelope, unwrapped to match the platform SDKs. */
|
|
11
|
+
checkCapabilities(): Promise<ProviderCapabilitySnapshot[]>;
|
|
10
12
|
}
|
|
11
13
|
export declare const IndeRunCapacitor: IndeRunCapacitorApi;
|
|
12
14
|
export interface IndeRunCapacitorInstance {
|
|
13
15
|
run(request: TaskRequest): Promise<TaskResult>;
|
|
14
16
|
stream(request: TaskRequest): Promise<StreamRun>;
|
|
17
|
+
checkCapabilities(): Promise<ProviderCapabilitySnapshot[]>;
|
|
15
18
|
}
|
|
16
19
|
export declare function createIndeRunCapacitor(options?: ConfigureOptions): IndeRunCapacitorInstance;
|
|
17
20
|
export { STREAM_ERROR_NAME, STREAM_EVENT_NAME } from "./streaming.js";
|
|
18
|
-
export type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPluginContract as IndeRunCapacitorPlugin, OpenAIProviderBootstrapOptions, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, TaskRequest, TaskResult };
|
|
21
|
+
export type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPluginContract as IndeRunCapacitorPlugin, OnnxProviderBootstrapOptions, OpenAIProviderBootstrapOptions, ProviderCapabilitySnapshot, ProviderDescriptor, ProviderDynamicCapabilities, StartStreamOptions, StreamErrorNotification, StreamEventNotification, StreamRun, SystemModelProviderBootstrapOptions, TaskRequest, TaskResult };
|
|
19
22
|
export type * from "@independo/inderun-contracts";
|
|
20
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE7F,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,IAAI,8BAA8B,EACxD,8BAA8B,EAC9B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,WAAW,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE7F,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,IAAI,8BAA8B,EACxD,4BAA4B,EAC5B,8BAA8B,EAC9B,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACT,mCAAmC,EACpC,MAAM,kBAAkB,CAAC;AAQ1B;;;;GAIG;AACH,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,8BAA8B,EAAE,mBAAmB,CAAC;IACpG,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,mFAAmF;IACnF,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC;CAC5D;AAED,eAAO,MAAM,gBAAgB,EAAE,mBAqD9B,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjD,iBAAiB,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC;CAC5D;AAED,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,wBAAwB,CA4B3F;AAED,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,8BAA8B,IAAI,sBAAsB,EACxD,4BAA4B,EAC5B,8BAA8B,EAC9B,0BAA0B,EAC1B,kBAAkB,EAClB,2BAA2B,EAC3B,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,EACT,mCAAmC,EACnC,WAAW,EACX,UAAU,EACX,CAAC;AAEF,mBAAmB,8BAA8B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,15 @@ export const IndeRunCapacitor = {
|
|
|
21
21
|
throw normalizePluginError(error);
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
+
async checkCapabilities() {
|
|
25
|
+
try {
|
|
26
|
+
const result = await IndeRunCapacitorNative.checkCapabilities();
|
|
27
|
+
return result.providers;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw normalizePluginError(error);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
24
33
|
async startStream(options) {
|
|
25
34
|
try {
|
|
26
35
|
return await IndeRunCapacitorNative.startStream(options);
|
|
@@ -62,6 +71,11 @@ export function createIndeRunCapacitor(options) {
|
|
|
62
71
|
async stream(request) {
|
|
63
72
|
await ensureConfigured();
|
|
64
73
|
return IndeRunCapacitor.stream(request);
|
|
74
|
+
},
|
|
75
|
+
// Configures first: without a registry there are no providers to report on.
|
|
76
|
+
async checkCapabilities() {
|
|
77
|
+
await ensureConfigured();
|
|
78
|
+
return IndeRunCapacitor.checkCapabilities();
|
|
65
79
|
}
|
|
66
80
|
};
|
|
67
81
|
}
|
package/dist/web.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StreamRunHandle, TaskResult } from "@independo/inderun-contracts";
|
|
2
2
|
import { WebPlugin } from "@capacitor/core";
|
|
3
|
-
import type { CancelStreamOptions, ConfigureOptions, IndeRunCapacitorPlugin, StartStreamOptions } from "./definitions.js";
|
|
3
|
+
import type { CancelStreamOptions, CheckCapabilitiesResult, ConfigureOptions, IndeRunCapacitorPlugin, StartStreamOptions } from "./definitions.js";
|
|
4
4
|
import type { TaskRequest } from "@independo/inderun-contracts";
|
|
5
5
|
export declare class IndeRunWeb extends WebPlugin implements IndeRunCapacitorPlugin {
|
|
6
6
|
private engine;
|
|
@@ -9,6 +9,7 @@ export declare class IndeRunWeb extends WebPlugin implements IndeRunCapacitorPlu
|
|
|
9
9
|
private readonly pendingCancels;
|
|
10
10
|
configure(options?: ConfigureOptions): Promise<void>;
|
|
11
11
|
run(request: TaskRequest): Promise<TaskResult>;
|
|
12
|
+
checkCapabilities(): Promise<CheckCapabilitiesResult>;
|
|
12
13
|
/**
|
|
13
14
|
* The web path deliberately round-trips through `notifyListeners` rather than
|
|
14
15
|
* handing the engine's `StreamRun` straight back.
|
package/dist/web.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAIhE,qBAAa,UAAW,SAAQ,SAAU,YAAW,sBAAsB;IACzE,OAAO,CAAC,MAAM,CAAwB;IAItC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAElE,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAIhE,qBAAa,UAAW,SAAQ,SAAU,YAAW,sBAAsB;IACzE,OAAO,CAAC,MAAM,CAAwB;IAItC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyC;IAElE,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzD;IAEK,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAYnD;IAEK,iBAAiB,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAe1D;IAED;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8BvE;IAEK,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9D;YAEa,IAAI;CAenB"}
|
package/dist/web.js
CHANGED
|
@@ -10,13 +10,27 @@ export class IndeRunWeb extends WebPlugin {
|
|
|
10
10
|
startingStreams = new Set();
|
|
11
11
|
pendingCancels = new Map();
|
|
12
12
|
async configure(options) {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// The web SDK requires at least one provider, not specifically the cloud one. Held
|
|
14
|
+
// here as well as there so the failure is an `Unavailable` contract error rather than
|
|
15
|
+
// a raw SDK throw, which is what the facade's callers expect.
|
|
16
|
+
if (!options?.openAI && !options?.systemModel && !options?.onnx) {
|
|
17
|
+
throw createUnavailable("Capacitor web execution requires at least one provider registration. Configure with openAI, systemModel and/or onnx bootstrap options before calling run(request).").toContractError();
|
|
15
18
|
}
|
|
16
19
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
// The SDK's own option type, not a hand-written copy of it: an upstream rename
|
|
21
|
+
// then fails at the type level instead of silently dropping a field. This is
|
|
22
|
+
// deliberately the *outbound* shape only — `ConfigureOptions` stays a narrower,
|
|
23
|
+
// JSON-serializable subset, because it has to cross the native bridge hop.
|
|
24
|
+
const webOptions = {};
|
|
25
|
+
if (options.openAI !== undefined) {
|
|
26
|
+
webOptions.openAI = compactOpenAIOptions(options.openAI);
|
|
27
|
+
}
|
|
28
|
+
if (options.systemModel !== undefined) {
|
|
29
|
+
webOptions.systemModel = compactSystemModelOptions(options.systemModel);
|
|
30
|
+
}
|
|
31
|
+
if (options.onnx !== undefined) {
|
|
32
|
+
webOptions.onnx = compactOnnxOptions(options.onnx);
|
|
33
|
+
}
|
|
20
34
|
if (options.allowDirectOpenAIEndpoint !== undefined) {
|
|
21
35
|
webOptions.allowDirectOpenAIEndpoint = options.allowDirectOpenAIEndpoint;
|
|
22
36
|
}
|
|
@@ -37,6 +51,20 @@ export class IndeRunWeb extends WebPlugin {
|
|
|
37
51
|
throw toIndeRunException(error).toContractError();
|
|
38
52
|
}
|
|
39
53
|
}
|
|
54
|
+
async checkCapabilities() {
|
|
55
|
+
if (!this.engine) {
|
|
56
|
+
throw createUnavailable("Capacitor IndeRun has not been configured. Configure providers before calling checkCapabilities().").toContractError();
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Deliberately uncast: the engine's snapshots are assigned straight into the
|
|
60
|
+
// bridge's own `ProviderCapabilitySnapshot`, so the two declarations staying
|
|
61
|
+
// identical is a compile error rather than a convention. See definitions.ts.
|
|
62
|
+
return { providers: await this.engine.checkCapabilities() };
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw toIndeRunException(error).toContractError();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
40
68
|
/**
|
|
41
69
|
* The web path deliberately round-trips through `notifyListeners` rather than
|
|
42
70
|
* handing the engine's `StreamRun` straight back.
|
|
@@ -101,8 +129,17 @@ export class IndeRunWeb extends WebPlugin {
|
|
|
101
129
|
}
|
|
102
130
|
}
|
|
103
131
|
}
|
|
104
|
-
|
|
105
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Assigns only the fields the caller actually set. `exactOptionalPropertyTypes` makes
|
|
134
|
+
* this incremental style mandatory rather than cosmetic: assigning `undefined` to an
|
|
135
|
+
* optional property is an error, and an explicit `undefined` on the wire is not the same
|
|
136
|
+
* thing as an absent key to the provider that reads it.
|
|
137
|
+
*
|
|
138
|
+
* `id`, `healthCheckTimeoutMs` and `healthCheckCacheMs` are deliberately not bridged —
|
|
139
|
+
* all optional, and the bridge has no reason to expose provider-tuning knobs it cannot
|
|
140
|
+
* also offer on native.
|
|
141
|
+
*/
|
|
142
|
+
function compactOpenAIOptions(openAI) {
|
|
106
143
|
const result = {
|
|
107
144
|
model: openAI.model
|
|
108
145
|
};
|
|
@@ -120,3 +157,25 @@ function compactOpenAIOptions(options) {
|
|
|
120
157
|
}
|
|
121
158
|
return result;
|
|
122
159
|
}
|
|
160
|
+
function compactSystemModelOptions(systemModel) {
|
|
161
|
+
const result = {};
|
|
162
|
+
if (systemModel.id !== undefined) {
|
|
163
|
+
result.id = systemModel.id;
|
|
164
|
+
}
|
|
165
|
+
if (systemModel.timeoutMs !== undefined) {
|
|
166
|
+
result.timeoutMs = systemModel.timeoutMs;
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
function compactOnnxOptions(onnx) {
|
|
171
|
+
const result = {
|
|
172
|
+
modelPackage: onnx.modelPackage
|
|
173
|
+
};
|
|
174
|
+
if (onnx.id !== undefined) {
|
|
175
|
+
result.id = onnx.id;
|
|
176
|
+
}
|
|
177
|
+
if (onnx.timeoutMs !== undefined) {
|
|
178
|
+
result.timeoutMs = onnx.timeoutMs;
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
@@ -49,6 +49,22 @@ struct CapacitorCancelStreamOptions: Codable {
|
|
|
49
49
|
let reason: String?
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/// IndeRunCore's `ProviderCapabilitySnapshot` is `Sendable` but not `Codable`, even
|
|
53
|
+
/// though both of its members are. This mirror exists only to get it through
|
|
54
|
+
/// `JSONEncoder`; see the upstream follow-up asking for `Codable` (and a schema) on
|
|
55
|
+
/// the snapshot itself.
|
|
56
|
+
private struct EncodableCapabilitySnapshot: Encodable {
|
|
57
|
+
let providerId: String
|
|
58
|
+
let descriptor: ProviderDescriptor
|
|
59
|
+
let capabilities: ProviderDynamicCapabilities
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// A Capacitor plugin method must resolve an object, never a top-level array, so the
|
|
63
|
+
/// snapshots travel wrapped. `IndeRunCapacitor` unwraps them on the JS side.
|
|
64
|
+
private struct CapabilitiesEnvelope: Encodable {
|
|
65
|
+
let providers: [EncodableCapabilitySnapshot]
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
/// Called with an already-encoded event/error for one run. The plugin turns these
|
|
53
69
|
/// into `notifyListeners` calls; taking them as closures keeps the pump testable
|
|
54
70
|
/// without Capacitor.
|
|
@@ -82,6 +98,16 @@ final class IndeRunCapacitorBridge {
|
|
|
82
98
|
return try encode(result)
|
|
83
99
|
}
|
|
84
100
|
|
|
101
|
+
func checkCapabilities() async throws -> JSObject {
|
|
102
|
+
guard let registry = configuredRegistry, let hostServices = configuredHostServices else {
|
|
103
|
+
throw createUnavailable(message: "Capacitor IndeRun has not been configured. Configure providers before calling checkCapabilities().")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// IndeRun is a stateless coordinator; new per call is intentional — registry is cached above.
|
|
107
|
+
let engine = IndeRun(registry: registry, hostServices: hostServices)
|
|
108
|
+
return try encode(capabilities: await engine.checkCapabilities())
|
|
109
|
+
}
|
|
110
|
+
|
|
85
111
|
func startStream(
|
|
86
112
|
options: JSObject,
|
|
87
113
|
onEvent: @escaping StreamEventSink,
|
|
@@ -173,6 +199,24 @@ final class IndeRunCapacitorBridge {
|
|
|
173
199
|
try encodeObject(handle)
|
|
174
200
|
}
|
|
175
201
|
|
|
202
|
+
/// The descriptor's enums carry explicit raw values (`in_process`, not `inProcess`),
|
|
203
|
+
/// and JSONEncoder omits nil optionals — so an unset `streamingAvailable` arrives as
|
|
204
|
+
/// an absent key rather than a null, which is what lets the JS side read absence as
|
|
205
|
+
/// "inherit `descriptor.supports.streaming`".
|
|
206
|
+
func encode(capabilities: [ProviderCapabilitySnapshot]) throws -> JSObject {
|
|
207
|
+
try encodeObject(
|
|
208
|
+
CapabilitiesEnvelope(
|
|
209
|
+
providers: capabilities.map {
|
|
210
|
+
EncodableCapabilitySnapshot(
|
|
211
|
+
providerId: $0.providerId,
|
|
212
|
+
descriptor: $0.descriptor,
|
|
213
|
+
capabilities: $0.capabilities
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
|
|
176
220
|
private func makeRegistry(openAI: OpenAIProviderBootstrapOptions?) throws -> ProviderRegistry {
|
|
177
221
|
let registry = ProviderRegistry()
|
|
178
222
|
try registry.register(AppleFoundationModelsProvider())
|
|
@@ -222,10 +266,26 @@ final class IndeRunCapacitorBridge {
|
|
|
222
266
|
private func encodeObject<T: Encodable>(_ value: T) throws -> JSObject {
|
|
223
267
|
let data = try JSONEncoder().encode(value)
|
|
224
268
|
let object = try JSONSerialization.jsonObject(with: data, options: [])
|
|
269
|
+
|
|
270
|
+
#if canImport(Capacitor)
|
|
271
|
+
// Capacitor's JSObject is [String: any JSValue], and a plain `as?` cast cannot
|
|
272
|
+
// produce one: JSONSerialization hands back NSDictionary/NSArray values, which do
|
|
273
|
+
// not conform to JSValue, so anything with a nested object or array — a TaskResult's
|
|
274
|
+
// `output`, a stream event's `payload`, the providers array — failed the cast and
|
|
275
|
+
// surfaced as "Capacitor bridge failed to encode a JSON object". JSTypes coerces the
|
|
276
|
+
// tree recursively, which is what the cast was standing in for.
|
|
277
|
+
guard let dictionary = object as? [AnyHashable: Any],
|
|
278
|
+
let coerced = JSTypes.coerceDictionaryToJSObject(dictionary) else {
|
|
279
|
+
throw createInternal(message: "Capacitor bridge failed to encode a JSON object.")
|
|
280
|
+
}
|
|
281
|
+
return coerced
|
|
282
|
+
#else
|
|
283
|
+
// Standalone builds alias JSObject to [String: Any], where the cast is exact.
|
|
225
284
|
guard let dictionary = object as? JSObject else {
|
|
226
285
|
throw createInternal(message: "Capacitor bridge failed to encode a JSON object.")
|
|
227
286
|
}
|
|
228
287
|
return dictionary
|
|
288
|
+
#endif
|
|
229
289
|
}
|
|
230
290
|
|
|
231
291
|
func mapAuthMode(_ value: String?) -> OpenAIAuthMode {
|
|
@@ -10,6 +10,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
10
10
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
11
11
|
CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise),
|
|
12
12
|
CAPPluginMethod(name: "run", returnType: CAPPluginReturnPromise),
|
|
13
|
+
CAPPluginMethod(name: "checkCapabilities", returnType: CAPPluginReturnPromise),
|
|
13
14
|
CAPPluginMethod(name: "startStream", returnType: CAPPluginReturnPromise),
|
|
14
15
|
CAPPluginMethod(name: "cancelStream", returnType: CAPPluginReturnPromise)
|
|
15
16
|
]
|
|
@@ -25,7 +26,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
25
26
|
|
|
26
27
|
@objc func configure(_ call: CAPPluginCall) {
|
|
27
28
|
do {
|
|
28
|
-
try implementation.configure(options: call.
|
|
29
|
+
try implementation.configure(options: call.jsObjectRepresentation)
|
|
29
30
|
call.resolve()
|
|
30
31
|
} catch let error as IndeRunException {
|
|
31
32
|
let contractError = error.toContractError()
|
|
@@ -42,7 +43,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
42
43
|
@objc func run(_ call: CAPPluginCall) {
|
|
43
44
|
Task {
|
|
44
45
|
do {
|
|
45
|
-
let result = try await implementation.run(requestObject: call.
|
|
46
|
+
let result = try await implementation.run(requestObject: call.jsObjectRepresentation)
|
|
46
47
|
call.resolve(result)
|
|
47
48
|
} catch let error as IndeRunException {
|
|
48
49
|
let contractError = error.toContractError()
|
|
@@ -57,6 +58,26 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
/// Reports every registered provider's static declaration and live availability
|
|
62
|
+
/// without executing a task. Availability changes between calls — a local model can
|
|
63
|
+
/// unload, cloud credentials can expire — so callers must not cache it across a run.
|
|
64
|
+
@objc func checkCapabilities(_ call: CAPPluginCall) {
|
|
65
|
+
Task {
|
|
66
|
+
do {
|
|
67
|
+
call.resolve(try await implementation.checkCapabilities())
|
|
68
|
+
} catch let error as IndeRunException {
|
|
69
|
+
let contractError = error.toContractError()
|
|
70
|
+
let details = try? implementation.encode(error: contractError)
|
|
71
|
+
call.reject(contractError.message, contractError.errorClass.rawValue, error, details)
|
|
72
|
+
} catch {
|
|
73
|
+
let normalized = toIndeRunException(error)
|
|
74
|
+
let contractError = normalized.toContractError()
|
|
75
|
+
let details = try? implementation.encode(error: contractError)
|
|
76
|
+
call.reject(contractError.message, contractError.errorClass.rawValue, normalized, details)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
60
81
|
/// Resolves with the run handle. Only validation and route-selection failures
|
|
61
82
|
/// reject here; a provider failure, a cancellation, or completion all arrive as
|
|
62
83
|
/// the single terminal event on `indeRunStreamEvent`.
|
|
@@ -69,7 +90,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
69
90
|
guard let self else { return }
|
|
70
91
|
do {
|
|
71
92
|
let handle = try await self.implementation.startStream(
|
|
72
|
-
options: call.
|
|
93
|
+
options: call.jsObjectRepresentation,
|
|
73
94
|
onEvent: { [weak self] streamId, event in
|
|
74
95
|
self?.notifyListeners(
|
|
75
96
|
"indeRunStreamEvent",
|
|
@@ -103,7 +124,7 @@ public final class IndeRunCapacitorPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
103
124
|
/// is a no-op by contract, not an error.
|
|
104
125
|
@objc func cancelStream(_ call: CAPPluginCall) {
|
|
105
126
|
do {
|
|
106
|
-
try implementation.cancelStream(options: call.
|
|
127
|
+
try implementation.cancelStream(options: call.jsObjectRepresentation)
|
|
107
128
|
call.resolve()
|
|
108
129
|
} catch let error as IndeRunException {
|
|
109
130
|
let contractError = error.toContractError()
|