capacitor-launchdarkly 0.0.0-stage → 0.1.0
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/CapacitorLaunchdarkly.podspec +20 -0
- package/LICENSE +21 -0
- package/Package.swift +32 -0
- package/README.md +747 -2
- package/android/build.gradle +68 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/Json.kt +67 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/LaunchDarklyClient.kt +250 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/LaunchDarklyPlugin.kt +148 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/LdConfigFactory.kt +34 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/StartOptions.kt +76 -0
- package/android/src/main/kotlin/io/github/maximbelov/launchdarkly/StoredContext.kt +47 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +1174 -0
- package/dist/esm/definitions.d.ts +520 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +46 -0
- package/dist/esm/web.js +204 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +221 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +224 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/LaunchDarklyPlugin/ConfigFactory.swift +29 -0
- package/ios/Sources/LaunchDarklyPlugin/JSONValues.swift +68 -0
- package/ios/Sources/LaunchDarklyPlugin/LaunchDarklyClient.swift +165 -0
- package/ios/Sources/LaunchDarklyPlugin/LaunchDarklyPlugin.swift +169 -0
- package/ios/Sources/LaunchDarklyPlugin/PrivacyInfo.xcprivacy +23 -0
- package/ios/Sources/LaunchDarklyPlugin/StartOptions.swift +79 -0
- package/ios/Sources/LaunchDarklyPlugin/StoredContext.swift +43 -0
- package/ios/Tests/LaunchDarklyPluginTests/BillingSafetyTests.swift +53 -0
- package/ios/Tests/LaunchDarklyPluginTests/JSONValuesTests.swift +67 -0
- package/ios/Tests/LaunchDarklyPluginTests/LaunchDarklyPluginTests.swift +37 -0
- package/ios/Tests/LaunchDarklyPluginTests/PluginConfigurationTests.swift +52 -0
- package/ios/Tests/LaunchDarklyPluginTests/StartContextTests.swift +36 -0
- package/package.json +105 -4
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import type { PluginsConfig } from '@capacitor/cli';
|
|
2
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
3
|
+
declare module '@capacitor/cli' {
|
|
4
|
+
interface PluginsConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Starts the native LaunchDarkly client as the app launches, before the
|
|
7
|
+
* web view runs any app code. Leave `mobileKey` out to start it from
|
|
8
|
+
* JavaScript with `initialize()` instead. iOS and Android only.
|
|
9
|
+
*/
|
|
10
|
+
LaunchDarkly?: {
|
|
11
|
+
/**
|
|
12
|
+
* The mobile key of the LaunchDarkly environment. Without it there is
|
|
13
|
+
* no native start-up, and `initialize()` starts the client instead.
|
|
14
|
+
*
|
|
15
|
+
* @since 0.1.0
|
|
16
|
+
* @example "mob-00000000-0000-0000-0000-000000000000"
|
|
17
|
+
*/
|
|
18
|
+
mobileKey?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The context the native start-up uses when no context was stored by an
|
|
21
|
+
* earlier `identify()`.
|
|
22
|
+
*
|
|
23
|
+
* @since 0.1.0
|
|
24
|
+
* @default { kind: 'user', key: 'anonymous_user', anonymous: true }
|
|
25
|
+
* @example { "kind": "user", "key": "anonymous_user", "anonymous": true }
|
|
26
|
+
*/
|
|
27
|
+
initialContext?: LDContext;
|
|
28
|
+
/**
|
|
29
|
+
* Streams flag updates when `true`, polls when `false`.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.1.0
|
|
32
|
+
* @default true
|
|
33
|
+
* @example true
|
|
34
|
+
*/
|
|
35
|
+
streaming?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Asks LaunchDarkly for the reason behind each evaluation.
|
|
38
|
+
*
|
|
39
|
+
* @since 0.1.0
|
|
40
|
+
* @default false
|
|
41
|
+
* @example false
|
|
42
|
+
*/
|
|
43
|
+
evaluationReasons?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Starts the client offline, until `setOnline({ online: true })`.
|
|
46
|
+
*
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
* @default false
|
|
49
|
+
* @example false
|
|
50
|
+
*/
|
|
51
|
+
offline?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* How long the start waits for the first set of flags, in seconds.
|
|
54
|
+
*
|
|
55
|
+
* @since 0.1.0
|
|
56
|
+
* @default 5
|
|
57
|
+
* @example 5
|
|
58
|
+
*/
|
|
59
|
+
startWaitSeconds?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Application metadata sent to LaunchDarkly with every request.
|
|
62
|
+
*
|
|
63
|
+
* @since 0.1.0
|
|
64
|
+
* @example { "id": "com.example.plugin", "version": "1.0.0" }
|
|
65
|
+
*/
|
|
66
|
+
application?: LDApplicationInfo;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The `plugins.LaunchDarkly` block of `capacitor.config`.
|
|
72
|
+
*/
|
|
73
|
+
export type LaunchDarklyConfig = NonNullable<PluginsConfig['LaunchDarkly']>;
|
|
74
|
+
export interface LaunchDarklyPlugin {
|
|
75
|
+
/**
|
|
76
|
+
* Starts the client from JavaScript and waits for the first set of flags or
|
|
77
|
+
* `options.startWaitSeconds` (5 by default), whichever comes first.
|
|
78
|
+
*
|
|
79
|
+
* - **iOS, Android**: takes `mobileKey`. Needed only by an app that does not
|
|
80
|
+
* put a `mobileKey` in `capacitor.config`; with one there, the client is
|
|
81
|
+
* already running when the app's code starts, and this call only answers
|
|
82
|
+
* its state.
|
|
83
|
+
* - **Web**: takes `clientSideId`, and is the only way to start the client.
|
|
84
|
+
* Needs `@launchdarkly/js-client-sdk` installed (see the README).
|
|
85
|
+
*
|
|
86
|
+
* `context` plays the part of `initialContext`: when an earlier `identify()`
|
|
87
|
+
* stored a context, the client starts with the stored one instead, so the
|
|
88
|
+
* app does not flip to an anonymous context for a moment after a restart.
|
|
89
|
+
*
|
|
90
|
+
* There is one client per process (per page on the web). A second call with
|
|
91
|
+
* the same key, or a call after the native start-up already started a
|
|
92
|
+
* client with that key, changes nothing: the client is not created again,
|
|
93
|
+
* `context` and `options` are ignored, and the current state is answered.
|
|
94
|
+
* Use `identify()` to switch the context. A call with a different key closes
|
|
95
|
+
* the running client and starts a new one.
|
|
96
|
+
*
|
|
97
|
+
* @since 0.1.0
|
|
98
|
+
*/
|
|
99
|
+
initialize(options: InitializeOptions): Promise<LaunchDarklyState>;
|
|
100
|
+
/**
|
|
101
|
+
* Answers whether the client has received its first set of flags, waiting
|
|
102
|
+
* up to `timeoutSeconds` (5 by default) for that when it has not yet.
|
|
103
|
+
*
|
|
104
|
+
* Resolves `{ initialized: false }` straight away when no client was
|
|
105
|
+
* started, neither natively nor with `initialize()`.
|
|
106
|
+
*
|
|
107
|
+
* @since 0.1.0
|
|
108
|
+
*/
|
|
109
|
+
waitForInitialization(options?: WaitForInitializationOptions): Promise<WaitForInitializationResult>;
|
|
110
|
+
/**
|
|
111
|
+
* The state of the native client: whether it has its flags, the current
|
|
112
|
+
* context and the value of every flag, read from the native SDK's own
|
|
113
|
+
* store. Meant for bootstrapping the web layer at start without a second
|
|
114
|
+
* network round trip.
|
|
115
|
+
*
|
|
116
|
+
* While the native start-up is still running, this waits until it is done:
|
|
117
|
+
* until the first set of flags is in, or `startWaitSeconds` has passed.
|
|
118
|
+
* With no client at all it answers `initialized: false` and no flags.
|
|
119
|
+
*
|
|
120
|
+
* Reading the flags this way sends no evaluation events.
|
|
121
|
+
*
|
|
122
|
+
* @since 0.1.0
|
|
123
|
+
*/
|
|
124
|
+
getState(): Promise<LaunchDarklyState>;
|
|
125
|
+
/**
|
|
126
|
+
* Switches the client to another context and resolves when the flags for
|
|
127
|
+
* it are loaded, or when `timeoutSeconds` (5 by default) has passed.
|
|
128
|
+
*
|
|
129
|
+
* The context the SDK accepted is stored natively, under a key of the
|
|
130
|
+
* plugin's own, and the next native start-up begins with it instead of
|
|
131
|
+
* `initialContext`. So an app logs out by identifying its anonymous
|
|
132
|
+
* context, which then becomes the stored one; `clearStoredContext()`
|
|
133
|
+
* forgets it altogether.
|
|
134
|
+
*
|
|
135
|
+
* An anonymous context keeps the key it is given. The plugin never asks the
|
|
136
|
+
* SDK to generate one.
|
|
137
|
+
*
|
|
138
|
+
* @since 0.1.0
|
|
139
|
+
*/
|
|
140
|
+
identify(options: IdentifyOptions): Promise<IdentifyResult>;
|
|
141
|
+
/**
|
|
142
|
+
* Evaluates one flag for the current context and answers its value, of any
|
|
143
|
+
* JSON type, or `defaultValue` (`null` when left out) when the flag is
|
|
144
|
+
* unknown or the client has not started. Goes through the SDK's JSON
|
|
145
|
+
* variation call, so it records an evaluation event like any SDK call.
|
|
146
|
+
*
|
|
147
|
+
* @since 0.1.0
|
|
148
|
+
*/
|
|
149
|
+
variation(options: VariationOptions): Promise<VariationResult>;
|
|
150
|
+
/**
|
|
151
|
+
* The value of every flag for the current context, from the native SDK's
|
|
152
|
+
* store. Sends no evaluation events. Empty when the client has not started.
|
|
153
|
+
*
|
|
154
|
+
* @since 0.1.0
|
|
155
|
+
*/
|
|
156
|
+
allFlags(): Promise<AllFlagsResult>;
|
|
157
|
+
/**
|
|
158
|
+
* Switches between streaming and polling. Neither native SDK can change its
|
|
159
|
+
* data source while it runs, so the plugin closes the client and starts it
|
|
160
|
+
* again with the same mobile key, options and current context, then waits as
|
|
161
|
+
* at start-up. Flag listeners stay registered. The web SDK switches in place
|
|
162
|
+
* (`setStreaming()`).
|
|
163
|
+
*
|
|
164
|
+
* @since 0.1.0
|
|
165
|
+
*/
|
|
166
|
+
setStreaming(options: SetStreamingOptions): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* Takes the client online or offline (`setOnline()` / `setOffline()` on
|
|
169
|
+
* Android, `setOnline(_:)` on iOS). Offline, the client keeps answering the
|
|
170
|
+
* values it has.
|
|
171
|
+
*
|
|
172
|
+
* The web SDK has no offline mode. There, going offline closes the stream so
|
|
173
|
+
* no flag updates arrive, and going online opens it again if `streaming` is
|
|
174
|
+
* on; analytics events are still sent.
|
|
175
|
+
*
|
|
176
|
+
* @since 0.1.0
|
|
177
|
+
*/
|
|
178
|
+
setOnline(options: SetOnlineOptions): Promise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* Sends the analytics events the client has queued.
|
|
181
|
+
*
|
|
182
|
+
* @since 0.1.0
|
|
183
|
+
*/
|
|
184
|
+
flush(): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Closes the client. It can be started again with `initialize()`; until
|
|
187
|
+
* then, `variation()` answers the default value. The stored context is
|
|
188
|
+
* kept.
|
|
189
|
+
*
|
|
190
|
+
* @since 0.1.0
|
|
191
|
+
*/
|
|
192
|
+
close(): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Forgets the context `identify()` stored, so the next native start-up
|
|
195
|
+
* begins with `initialContext` again. The running client is not changed.
|
|
196
|
+
*
|
|
197
|
+
* @since 0.1.0
|
|
198
|
+
*/
|
|
199
|
+
clearStoredContext(): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* Called for every flag whose value changes: from the stream or a poll, and
|
|
202
|
+
* after `identify()` for each flag whose value differs for the new context.
|
|
203
|
+
*
|
|
204
|
+
* @since 0.1.0
|
|
205
|
+
*/
|
|
206
|
+
addListener(eventName: 'flagChange', listenerFunc: (change: FlagChange) => void): Promise<PluginListenerHandle>;
|
|
207
|
+
/**
|
|
208
|
+
* Called when the SDK's connection mode changes, for example from streaming
|
|
209
|
+
* to offline. iOS and Android only: the web SDK has no connection mode, and
|
|
210
|
+
* this is never called there.
|
|
211
|
+
*
|
|
212
|
+
* @since 0.1.0
|
|
213
|
+
*/
|
|
214
|
+
addListener(eventName: 'connectionModeChange', listenerFunc: (change: ConnectionModeChange) => void): Promise<PluginListenerHandle>;
|
|
215
|
+
/**
|
|
216
|
+
* Removes every listener of this plugin.
|
|
217
|
+
*
|
|
218
|
+
* @since 0.1.0
|
|
219
|
+
*/
|
|
220
|
+
removeAllListeners(): Promise<void>;
|
|
221
|
+
}
|
|
222
|
+
export interface LaunchDarklyOptions {
|
|
223
|
+
/**
|
|
224
|
+
* Streams flag updates when `true`, polls when `false`.
|
|
225
|
+
*
|
|
226
|
+
* @since 0.1.0
|
|
227
|
+
* @default true
|
|
228
|
+
*/
|
|
229
|
+
streaming?: boolean;
|
|
230
|
+
/**
|
|
231
|
+
* Asks LaunchDarkly for the reason behind each evaluation. The SDKs then
|
|
232
|
+
* attach it to their evaluation events.
|
|
233
|
+
*
|
|
234
|
+
* @since 0.1.0
|
|
235
|
+
* @default false
|
|
236
|
+
*/
|
|
237
|
+
evaluationReasons?: boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Starts the client offline: it answers cached or default values and does
|
|
240
|
+
* not connect until `setOnline({ online: true })`.
|
|
241
|
+
*
|
|
242
|
+
* The web SDK has no offline mode: there `offline: true` starts without a
|
|
243
|
+
* stream, and the first flags are still fetched once.
|
|
244
|
+
*
|
|
245
|
+
* @since 0.1.0
|
|
246
|
+
* @default false
|
|
247
|
+
*/
|
|
248
|
+
offline?: boolean;
|
|
249
|
+
/**
|
|
250
|
+
* How long the start waits for the first set of flags, in seconds.
|
|
251
|
+
*
|
|
252
|
+
* @since 0.1.0
|
|
253
|
+
* @default 5
|
|
254
|
+
*/
|
|
255
|
+
startWaitSeconds?: number;
|
|
256
|
+
/**
|
|
257
|
+
* Application metadata sent to LaunchDarkly with every request. It
|
|
258
|
+
* describes the app; it is not a context, and adds nothing to the contexts
|
|
259
|
+
* counted for billing.
|
|
260
|
+
*
|
|
261
|
+
* @since 0.1.0
|
|
262
|
+
*/
|
|
263
|
+
application?: LDApplicationInfo;
|
|
264
|
+
/**
|
|
265
|
+
* Web only: flags to start with before LaunchDarkly answers. `'localStorage'`
|
|
266
|
+
* starts from the flags the web SDK cached in `localStorage` for the context
|
|
267
|
+
* on an earlier visit, which the SDK does on its own; a flag object (for
|
|
268
|
+
* example rendered by your server) starts from those values. The native
|
|
269
|
+
* SDKs always start from their own cache and ignore this.
|
|
270
|
+
*
|
|
271
|
+
* @since 0.1.0
|
|
272
|
+
*/
|
|
273
|
+
bootstrap?: 'localStorage' | LDFlagSet;
|
|
274
|
+
}
|
|
275
|
+
export interface LDApplicationInfo {
|
|
276
|
+
/**
|
|
277
|
+
* @since 0.1.0
|
|
278
|
+
*/
|
|
279
|
+
id?: string;
|
|
280
|
+
/**
|
|
281
|
+
* @since 0.1.0
|
|
282
|
+
*/
|
|
283
|
+
name?: string;
|
|
284
|
+
/**
|
|
285
|
+
* @since 0.1.0
|
|
286
|
+
*/
|
|
287
|
+
version?: string;
|
|
288
|
+
/**
|
|
289
|
+
* @since 0.1.0
|
|
290
|
+
*/
|
|
291
|
+
versionName?: string;
|
|
292
|
+
}
|
|
293
|
+
export interface InitializeOptions {
|
|
294
|
+
/**
|
|
295
|
+
* The mobile key of the LaunchDarkly environment, used on iOS and Android.
|
|
296
|
+
*
|
|
297
|
+
* @since 0.1.0
|
|
298
|
+
*/
|
|
299
|
+
mobileKey?: string;
|
|
300
|
+
/**
|
|
301
|
+
* The client-side ID of the LaunchDarkly environment, used on the web.
|
|
302
|
+
*
|
|
303
|
+
* @since 0.1.0
|
|
304
|
+
*/
|
|
305
|
+
clientSideId?: string;
|
|
306
|
+
/**
|
|
307
|
+
* @since 0.1.0
|
|
308
|
+
*/
|
|
309
|
+
context: LDContext;
|
|
310
|
+
/**
|
|
311
|
+
* @since 0.1.0
|
|
312
|
+
*/
|
|
313
|
+
options?: LaunchDarklyOptions;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* A context in the JSON shape LaunchDarkly's SDKs use: a single-kind context
|
|
317
|
+
* or a multi-context.
|
|
318
|
+
*/
|
|
319
|
+
export type LDContext = LDSingleKindContext | LDMultiKindContext;
|
|
320
|
+
/**
|
|
321
|
+
* A context of one kind. Any other property is a custom attribute: a string,
|
|
322
|
+
* number, boolean, array or object.
|
|
323
|
+
*/
|
|
324
|
+
export interface LDSingleKindContext {
|
|
325
|
+
/**
|
|
326
|
+
* The context kind, for example `user` or `organization`.
|
|
327
|
+
*
|
|
328
|
+
* @since 0.1.0
|
|
329
|
+
*/
|
|
330
|
+
kind: string;
|
|
331
|
+
/**
|
|
332
|
+
* The key. An anonymous context keeps the key it is given.
|
|
333
|
+
*
|
|
334
|
+
* @since 0.1.0
|
|
335
|
+
*/
|
|
336
|
+
key: string;
|
|
337
|
+
/**
|
|
338
|
+
* @since 0.1.0
|
|
339
|
+
*/
|
|
340
|
+
name?: string;
|
|
341
|
+
/**
|
|
342
|
+
* Leaves the context out of the dashboard's context list. It is still
|
|
343
|
+
* counted for billing by its key.
|
|
344
|
+
*
|
|
345
|
+
* @since 0.1.0
|
|
346
|
+
*/
|
|
347
|
+
anonymous?: boolean;
|
|
348
|
+
/**
|
|
349
|
+
* @since 0.1.0
|
|
350
|
+
*/
|
|
351
|
+
_meta?: LDContextMeta;
|
|
352
|
+
[attribute: string]: unknown;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* One kind of a multi-context: the attributes of `LDSingleKindContext` without
|
|
356
|
+
* `kind`, which is the property name in the multi-context.
|
|
357
|
+
*/
|
|
358
|
+
export interface LDContextCommon {
|
|
359
|
+
/**
|
|
360
|
+
* @since 0.1.0
|
|
361
|
+
*/
|
|
362
|
+
key: string;
|
|
363
|
+
/**
|
|
364
|
+
* @since 0.1.0
|
|
365
|
+
*/
|
|
366
|
+
name?: string;
|
|
367
|
+
/**
|
|
368
|
+
* @since 0.1.0
|
|
369
|
+
*/
|
|
370
|
+
anonymous?: boolean;
|
|
371
|
+
/**
|
|
372
|
+
* @since 0.1.0
|
|
373
|
+
*/
|
|
374
|
+
_meta?: LDContextMeta;
|
|
375
|
+
[attribute: string]: unknown;
|
|
376
|
+
}
|
|
377
|
+
export interface LDContextMeta {
|
|
378
|
+
/**
|
|
379
|
+
* Attributes, by name or `/`-separated reference, that are not sent to
|
|
380
|
+
* LaunchDarkly in analytics events.
|
|
381
|
+
*
|
|
382
|
+
* @since 0.1.0
|
|
383
|
+
*/
|
|
384
|
+
privateAttributes?: string[];
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* A context made of several kinds: `{ kind: 'multi', user: {...}, organization: {...} }`.
|
|
388
|
+
* Each kind's object has no `kind` of its own.
|
|
389
|
+
*/
|
|
390
|
+
export interface LDMultiKindContext {
|
|
391
|
+
/**
|
|
392
|
+
* @since 0.1.0
|
|
393
|
+
*/
|
|
394
|
+
kind: 'multi';
|
|
395
|
+
[contextKind: string]: 'multi' | LDContextCommon;
|
|
396
|
+
}
|
|
397
|
+
export interface LDFlagSet {
|
|
398
|
+
[flagKey: string]: unknown;
|
|
399
|
+
}
|
|
400
|
+
export interface LaunchDarklyState {
|
|
401
|
+
/**
|
|
402
|
+
* Whether the client has received its first set of flags, from the network
|
|
403
|
+
* or, when it was started offline, from its cache.
|
|
404
|
+
*
|
|
405
|
+
* @since 0.1.0
|
|
406
|
+
*/
|
|
407
|
+
initialized: boolean;
|
|
408
|
+
/**
|
|
409
|
+
* The current context. Absent when no client was started.
|
|
410
|
+
*
|
|
411
|
+
* @since 0.1.0
|
|
412
|
+
*/
|
|
413
|
+
context?: LDContext;
|
|
414
|
+
/**
|
|
415
|
+
* The value of every flag for the current context.
|
|
416
|
+
*
|
|
417
|
+
* @since 0.1.0
|
|
418
|
+
*/
|
|
419
|
+
flags: LDFlagSet;
|
|
420
|
+
}
|
|
421
|
+
export interface WaitForInitializationOptions {
|
|
422
|
+
/**
|
|
423
|
+
* @since 0.1.0
|
|
424
|
+
* @default 5
|
|
425
|
+
*/
|
|
426
|
+
timeoutSeconds?: number;
|
|
427
|
+
}
|
|
428
|
+
export interface WaitForInitializationResult {
|
|
429
|
+
/**
|
|
430
|
+
* @since 0.1.0
|
|
431
|
+
*/
|
|
432
|
+
initialized: boolean;
|
|
433
|
+
}
|
|
434
|
+
export interface IdentifyOptions {
|
|
435
|
+
/**
|
|
436
|
+
* @since 0.1.0
|
|
437
|
+
*/
|
|
438
|
+
context: LDContext;
|
|
439
|
+
/**
|
|
440
|
+
* How long to wait for the flags of the new context, in seconds.
|
|
441
|
+
*
|
|
442
|
+
* @since 0.1.0
|
|
443
|
+
* @default 5
|
|
444
|
+
*/
|
|
445
|
+
timeoutSeconds?: number;
|
|
446
|
+
}
|
|
447
|
+
export interface IdentifyResult {
|
|
448
|
+
/**
|
|
449
|
+
* `true` when the flags of the new context did not arrive in time. The
|
|
450
|
+
* context is switched all the same, and the flags follow when they arrive.
|
|
451
|
+
*
|
|
452
|
+
* @since 0.1.0
|
|
453
|
+
*/
|
|
454
|
+
timedOut: boolean;
|
|
455
|
+
}
|
|
456
|
+
export interface VariationOptions {
|
|
457
|
+
/**
|
|
458
|
+
* @since 0.1.0
|
|
459
|
+
*/
|
|
460
|
+
key: string;
|
|
461
|
+
/**
|
|
462
|
+
* @since 0.1.0
|
|
463
|
+
* @default null
|
|
464
|
+
*/
|
|
465
|
+
defaultValue?: unknown;
|
|
466
|
+
}
|
|
467
|
+
export interface VariationResult {
|
|
468
|
+
/**
|
|
469
|
+
* @since 0.1.0
|
|
470
|
+
*/
|
|
471
|
+
value: unknown;
|
|
472
|
+
}
|
|
473
|
+
export interface AllFlagsResult {
|
|
474
|
+
/**
|
|
475
|
+
* @since 0.1.0
|
|
476
|
+
*/
|
|
477
|
+
flags: LDFlagSet;
|
|
478
|
+
}
|
|
479
|
+
export interface SetStreamingOptions {
|
|
480
|
+
/**
|
|
481
|
+
* @since 0.1.0
|
|
482
|
+
*/
|
|
483
|
+
enabled: boolean;
|
|
484
|
+
}
|
|
485
|
+
export interface SetOnlineOptions {
|
|
486
|
+
/**
|
|
487
|
+
* @since 0.1.0
|
|
488
|
+
*/
|
|
489
|
+
online: boolean;
|
|
490
|
+
}
|
|
491
|
+
export interface FlagChange {
|
|
492
|
+
/**
|
|
493
|
+
* @since 0.1.0
|
|
494
|
+
*/
|
|
495
|
+
key: string;
|
|
496
|
+
/**
|
|
497
|
+
* The new value; `null` when the flag was deleted.
|
|
498
|
+
*
|
|
499
|
+
* @since 0.1.0
|
|
500
|
+
*/
|
|
501
|
+
value: unknown;
|
|
502
|
+
/**
|
|
503
|
+
* The value before the change, when the plugin knew one.
|
|
504
|
+
*
|
|
505
|
+
* @since 0.1.0
|
|
506
|
+
*/
|
|
507
|
+
previous?: unknown;
|
|
508
|
+
}
|
|
509
|
+
export interface ConnectionModeChange {
|
|
510
|
+
/**
|
|
511
|
+
* The SDK's own name for the mode, which differs between the platforms:
|
|
512
|
+
* on iOS `streaming`, `polling`, `offline` or
|
|
513
|
+
* `establishingStreamingConnection`; on Android the name of the SDK's
|
|
514
|
+
* `ConnectionMode`, such as `STREAMING`, `POLLING`, `OFFLINE`,
|
|
515
|
+
* `SET_OFFLINE` or `BACKGROUND_POLLING`.
|
|
516
|
+
*
|
|
517
|
+
* @since 0.1.0
|
|
518
|
+
*/
|
|
519
|
+
mode: string;
|
|
520
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginsConfig } from '@capacitor/cli';\nimport type { PluginListenerHandle } from '@capacitor/core';\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * Starts the native LaunchDarkly client as the app launches, before the\n * web view runs any app code. Leave `mobileKey` out to start it from\n * JavaScript with `initialize()` instead. iOS and Android only.\n */\n LaunchDarkly?: {\n /**\n * The mobile key of the LaunchDarkly environment. Without it there is\n * no native start-up, and `initialize()` starts the client instead.\n *\n * @since 0.1.0\n * @example \"mob-00000000-0000-0000-0000-000000000000\"\n */\n mobileKey?: string;\n\n /**\n * The context the native start-up uses when no context was stored by an\n * earlier `identify()`.\n *\n * @since 0.1.0\n * @default { kind: 'user', key: 'anonymous_user', anonymous: true }\n * @example { \"kind\": \"user\", \"key\": \"anonymous_user\", \"anonymous\": true }\n */\n initialContext?: LDContext;\n\n /**\n * Streams flag updates when `true`, polls when `false`.\n *\n * @since 0.1.0\n * @default true\n * @example true\n */\n streaming?: boolean;\n\n /**\n * Asks LaunchDarkly for the reason behind each evaluation.\n *\n * @since 0.1.0\n * @default false\n * @example false\n */\n evaluationReasons?: boolean;\n\n /**\n * Starts the client offline, until `setOnline({ online: true })`.\n *\n * @since 0.1.0\n * @default false\n * @example false\n */\n offline?: boolean;\n\n /**\n * How long the start waits for the first set of flags, in seconds.\n *\n * @since 0.1.0\n * @default 5\n * @example 5\n */\n startWaitSeconds?: number;\n\n /**\n * Application metadata sent to LaunchDarkly with every request.\n *\n * @since 0.1.0\n * @example { \"id\": \"com.example.plugin\", \"version\": \"1.0.0\" }\n */\n application?: LDApplicationInfo;\n };\n }\n}\n\n/**\n * The `plugins.LaunchDarkly` block of `capacitor.config`.\n */\nexport type LaunchDarklyConfig = NonNullable<PluginsConfig['LaunchDarkly']>;\n\nexport interface LaunchDarklyPlugin {\n /**\n * Starts the client from JavaScript and waits for the first set of flags or\n * `options.startWaitSeconds` (5 by default), whichever comes first.\n *\n * - **iOS, Android**: takes `mobileKey`. Needed only by an app that does not\n * put a `mobileKey` in `capacitor.config`; with one there, the client is\n * already running when the app's code starts, and this call only answers\n * its state.\n * - **Web**: takes `clientSideId`, and is the only way to start the client.\n * Needs `@launchdarkly/js-client-sdk` installed (see the README).\n *\n * `context` plays the part of `initialContext`: when an earlier `identify()`\n * stored a context, the client starts with the stored one instead, so the\n * app does not flip to an anonymous context for a moment after a restart.\n *\n * There is one client per process (per page on the web). A second call with\n * the same key, or a call after the native start-up already started a\n * client with that key, changes nothing: the client is not created again,\n * `context` and `options` are ignored, and the current state is answered.\n * Use `identify()` to switch the context. A call with a different key closes\n * the running client and starts a new one.\n *\n * @since 0.1.0\n */\n initialize(options: InitializeOptions): Promise<LaunchDarklyState>;\n\n /**\n * Answers whether the client has received its first set of flags, waiting\n * up to `timeoutSeconds` (5 by default) for that when it has not yet.\n *\n * Resolves `{ initialized: false }` straight away when no client was\n * started, neither natively nor with `initialize()`.\n *\n * @since 0.1.0\n */\n waitForInitialization(options?: WaitForInitializationOptions): Promise<WaitForInitializationResult>;\n\n /**\n * The state of the native client: whether it has its flags, the current\n * context and the value of every flag, read from the native SDK's own\n * store. Meant for bootstrapping the web layer at start without a second\n * network round trip.\n *\n * While the native start-up is still running, this waits until it is done:\n * until the first set of flags is in, or `startWaitSeconds` has passed.\n * With no client at all it answers `initialized: false` and no flags.\n *\n * Reading the flags this way sends no evaluation events.\n *\n * @since 0.1.0\n */\n getState(): Promise<LaunchDarklyState>;\n\n /**\n * Switches the client to another context and resolves when the flags for\n * it are loaded, or when `timeoutSeconds` (5 by default) has passed.\n *\n * The context the SDK accepted is stored natively, under a key of the\n * plugin's own, and the next native start-up begins with it instead of\n * `initialContext`. So an app logs out by identifying its anonymous\n * context, which then becomes the stored one; `clearStoredContext()`\n * forgets it altogether.\n *\n * An anonymous context keeps the key it is given. The plugin never asks the\n * SDK to generate one.\n *\n * @since 0.1.0\n */\n identify(options: IdentifyOptions): Promise<IdentifyResult>;\n\n /**\n * Evaluates one flag for the current context and answers its value, of any\n * JSON type, or `defaultValue` (`null` when left out) when the flag is\n * unknown or the client has not started. Goes through the SDK's JSON\n * variation call, so it records an evaluation event like any SDK call.\n *\n * @since 0.1.0\n */\n variation(options: VariationOptions): Promise<VariationResult>;\n\n /**\n * The value of every flag for the current context, from the native SDK's\n * store. Sends no evaluation events. Empty when the client has not started.\n *\n * @since 0.1.0\n */\n allFlags(): Promise<AllFlagsResult>;\n\n /**\n * Switches between streaming and polling. Neither native SDK can change its\n * data source while it runs, so the plugin closes the client and starts it\n * again with the same mobile key, options and current context, then waits as\n * at start-up. Flag listeners stay registered. The web SDK switches in place\n * (`setStreaming()`).\n *\n * @since 0.1.0\n */\n setStreaming(options: SetStreamingOptions): Promise<void>;\n\n /**\n * Takes the client online or offline (`setOnline()` / `setOffline()` on\n * Android, `setOnline(_:)` on iOS). Offline, the client keeps answering the\n * values it has.\n *\n * The web SDK has no offline mode. There, going offline closes the stream so\n * no flag updates arrive, and going online opens it again if `streaming` is\n * on; analytics events are still sent.\n *\n * @since 0.1.0\n */\n setOnline(options: SetOnlineOptions): Promise<void>;\n\n /**\n * Sends the analytics events the client has queued.\n *\n * @since 0.1.0\n */\n flush(): Promise<void>;\n\n /**\n * Closes the client. It can be started again with `initialize()`; until\n * then, `variation()` answers the default value. The stored context is\n * kept.\n *\n * @since 0.1.0\n */\n close(): Promise<void>;\n\n /**\n * Forgets the context `identify()` stored, so the next native start-up\n * begins with `initialContext` again. The running client is not changed.\n *\n * @since 0.1.0\n */\n clearStoredContext(): Promise<void>;\n\n /**\n * Called for every flag whose value changes: from the stream or a poll, and\n * after `identify()` for each flag whose value differs for the new context.\n *\n * @since 0.1.0\n */\n addListener(eventName: 'flagChange', listenerFunc: (change: FlagChange) => void): Promise<PluginListenerHandle>;\n\n /**\n * Called when the SDK's connection mode changes, for example from streaming\n * to offline. iOS and Android only: the web SDK has no connection mode, and\n * this is never called there.\n *\n * @since 0.1.0\n */\n addListener(\n eventName: 'connectionModeChange',\n listenerFunc: (change: ConnectionModeChange) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Removes every listener of this plugin.\n *\n * @since 0.1.0\n */\n removeAllListeners(): Promise<void>;\n}\n\nexport interface LaunchDarklyOptions {\n /**\n * Streams flag updates when `true`, polls when `false`.\n *\n * @since 0.1.0\n * @default true\n */\n streaming?: boolean;\n\n /**\n * Asks LaunchDarkly for the reason behind each evaluation. The SDKs then\n * attach it to their evaluation events.\n *\n * @since 0.1.0\n * @default false\n */\n evaluationReasons?: boolean;\n\n /**\n * Starts the client offline: it answers cached or default values and does\n * not connect until `setOnline({ online: true })`.\n *\n * The web SDK has no offline mode: there `offline: true` starts without a\n * stream, and the first flags are still fetched once.\n *\n * @since 0.1.0\n * @default false\n */\n offline?: boolean;\n\n /**\n * How long the start waits for the first set of flags, in seconds.\n *\n * @since 0.1.0\n * @default 5\n */\n startWaitSeconds?: number;\n\n /**\n * Application metadata sent to LaunchDarkly with every request. It\n * describes the app; it is not a context, and adds nothing to the contexts\n * counted for billing.\n *\n * @since 0.1.0\n */\n application?: LDApplicationInfo;\n\n /**\n * Web only: flags to start with before LaunchDarkly answers. `'localStorage'`\n * starts from the flags the web SDK cached in `localStorage` for the context\n * on an earlier visit, which the SDK does on its own; a flag object (for\n * example rendered by your server) starts from those values. The native\n * SDKs always start from their own cache and ignore this.\n *\n * @since 0.1.0\n */\n bootstrap?: 'localStorage' | LDFlagSet;\n}\n\nexport interface LDApplicationInfo {\n /**\n * @since 0.1.0\n */\n id?: string;\n\n /**\n * @since 0.1.0\n */\n name?: string;\n\n /**\n * @since 0.1.0\n */\n version?: string;\n\n /**\n * @since 0.1.0\n */\n versionName?: string;\n}\n\nexport interface InitializeOptions {\n /**\n * The mobile key of the LaunchDarkly environment, used on iOS and Android.\n *\n * @since 0.1.0\n */\n mobileKey?: string;\n\n /**\n * The client-side ID of the LaunchDarkly environment, used on the web.\n *\n * @since 0.1.0\n */\n clientSideId?: string;\n\n /**\n * @since 0.1.0\n */\n context: LDContext;\n\n /**\n * @since 0.1.0\n */\n options?: LaunchDarklyOptions;\n}\n\n/**\n * A context in the JSON shape LaunchDarkly's SDKs use: a single-kind context\n * or a multi-context.\n */\nexport type LDContext = LDSingleKindContext | LDMultiKindContext;\n\n/**\n * A context of one kind. Any other property is a custom attribute: a string,\n * number, boolean, array or object.\n */\nexport interface LDSingleKindContext {\n /**\n * The context kind, for example `user` or `organization`.\n *\n * @since 0.1.0\n */\n kind: string;\n\n /**\n * The key. An anonymous context keeps the key it is given.\n *\n * @since 0.1.0\n */\n key: string;\n\n /**\n * @since 0.1.0\n */\n name?: string;\n\n /**\n * Leaves the context out of the dashboard's context list. It is still\n * counted for billing by its key.\n *\n * @since 0.1.0\n */\n anonymous?: boolean;\n\n /**\n * @since 0.1.0\n */\n _meta?: LDContextMeta;\n\n [attribute: string]: unknown;\n}\n\n/**\n * One kind of a multi-context: the attributes of `LDSingleKindContext` without\n * `kind`, which is the property name in the multi-context.\n */\nexport interface LDContextCommon {\n /**\n * @since 0.1.0\n */\n key: string;\n\n /**\n * @since 0.1.0\n */\n name?: string;\n\n /**\n * @since 0.1.0\n */\n anonymous?: boolean;\n\n /**\n * @since 0.1.0\n */\n _meta?: LDContextMeta;\n\n [attribute: string]: unknown;\n}\n\nexport interface LDContextMeta {\n /**\n * Attributes, by name or `/`-separated reference, that are not sent to\n * LaunchDarkly in analytics events.\n *\n * @since 0.1.0\n */\n privateAttributes?: string[];\n}\n\n/**\n * A context made of several kinds: `{ kind: 'multi', user: {...}, organization: {...} }`.\n * Each kind's object has no `kind` of its own.\n */\nexport interface LDMultiKindContext {\n /**\n * @since 0.1.0\n */\n kind: 'multi';\n\n [contextKind: string]: 'multi' | LDContextCommon;\n}\n\nexport interface LDFlagSet {\n [flagKey: string]: unknown;\n}\n\nexport interface LaunchDarklyState {\n /**\n * Whether the client has received its first set of flags, from the network\n * or, when it was started offline, from its cache.\n *\n * @since 0.1.0\n */\n initialized: boolean;\n\n /**\n * The current context. Absent when no client was started.\n *\n * @since 0.1.0\n */\n context?: LDContext;\n\n /**\n * The value of every flag for the current context.\n *\n * @since 0.1.0\n */\n flags: LDFlagSet;\n}\n\nexport interface WaitForInitializationOptions {\n /**\n * @since 0.1.0\n * @default 5\n */\n timeoutSeconds?: number;\n}\n\nexport interface WaitForInitializationResult {\n /**\n * @since 0.1.0\n */\n initialized: boolean;\n}\n\nexport interface IdentifyOptions {\n /**\n * @since 0.1.0\n */\n context: LDContext;\n\n /**\n * How long to wait for the flags of the new context, in seconds.\n *\n * @since 0.1.0\n * @default 5\n */\n timeoutSeconds?: number;\n}\n\nexport interface IdentifyResult {\n /**\n * `true` when the flags of the new context did not arrive in time. The\n * context is switched all the same, and the flags follow when they arrive.\n *\n * @since 0.1.0\n */\n timedOut: boolean;\n}\n\nexport interface VariationOptions {\n /**\n * @since 0.1.0\n */\n key: string;\n\n /**\n * @since 0.1.0\n * @default null\n */\n defaultValue?: unknown;\n}\n\nexport interface VariationResult {\n /**\n * @since 0.1.0\n */\n value: unknown;\n}\n\nexport interface AllFlagsResult {\n /**\n * @since 0.1.0\n */\n flags: LDFlagSet;\n}\n\nexport interface SetStreamingOptions {\n /**\n * @since 0.1.0\n */\n enabled: boolean;\n}\n\nexport interface SetOnlineOptions {\n /**\n * @since 0.1.0\n */\n online: boolean;\n}\n\nexport interface FlagChange {\n /**\n * @since 0.1.0\n */\n key: string;\n\n /**\n * The new value; `null` when the flag was deleted.\n *\n * @since 0.1.0\n */\n value: unknown;\n\n /**\n * The value before the change, when the plugin knew one.\n *\n * @since 0.1.0\n */\n previous?: unknown;\n}\n\nexport interface ConnectionModeChange {\n /**\n * The SDK's own name for the mode, which differs between the platforms:\n * on iOS `streaming`, `polling`, `offline` or\n * `establishingStreamingConnection`; on Android the name of the SDK's\n * `ConnectionMode`, such as `STREAMING`, `POLLING`, `OFFLINE`,\n * `SET_OFFLINE` or `BACKGROUND_POLLING`.\n *\n * @since 0.1.0\n */\n mode: string;\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
const LaunchDarkly = registerPlugin('LaunchDarkly', {
|
|
3
|
+
web: () => import('./web').then((m) => new m.LaunchDarklyWeb()),
|
|
4
|
+
});
|
|
5
|
+
export * from './definitions';
|
|
6
|
+
export { LaunchDarkly };
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,YAAY,GAAG,cAAc,CAAqB,cAAc,EAAE;IACtE,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;CAChE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { LaunchDarklyPlugin } from './definitions';\n\nconst LaunchDarkly = registerPlugin<LaunchDarklyPlugin>('LaunchDarkly', {\n web: () => import('./web').then((m) => new m.LaunchDarklyWeb()),\n});\n\nexport * from './definitions';\nexport { LaunchDarkly };\n"]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { LDClient, LDOptions } from '@launchdarkly/js-client-sdk';
|
|
3
|
+
import type { AllFlagsResult, IdentifyOptions, IdentifyResult, InitializeOptions, LaunchDarklyPlugin, LaunchDarklyState, LDContext, SetOnlineOptions, SetStreamingOptions, VariationOptions, VariationResult, WaitForInitializationOptions, WaitForInitializationResult } from './definitions';
|
|
4
|
+
/** The part of `@launchdarkly/js-client-sdk` the plugin uses. */
|
|
5
|
+
export interface WebSdk {
|
|
6
|
+
createClient(clientSideId: string, context: LDContext, options?: LDOptions): LDClient;
|
|
7
|
+
}
|
|
8
|
+
/** The key the plugin keeps the context of the last `identify()` under in `localStorage`. */
|
|
9
|
+
export declare const STORED_CONTEXT_KEY = "CapacitorLaunchDarkly.context";
|
|
10
|
+
export declare const MISSING_SDK_MESSAGE = "The LaunchDarkly web SDK is not installed. To use this plugin on the web, run: npm install @launchdarkly/js-client-sdk";
|
|
11
|
+
/**
|
|
12
|
+
* The web implementation, on LaunchDarkly's browser SDK. It follows the native rules: one client per page, a context the
|
|
13
|
+
* caller gave with its key (an anonymous context without a key is refused rather than given a generated one), and a context
|
|
14
|
+
* stored by `identify()` that wins over the one `initialize()` is given.
|
|
15
|
+
*/
|
|
16
|
+
export declare class LaunchDarklyWeb extends WebPlugin implements LaunchDarklyPlugin {
|
|
17
|
+
private readonly loadSdk;
|
|
18
|
+
private client?;
|
|
19
|
+
private clientSideId?;
|
|
20
|
+
private options;
|
|
21
|
+
private context?;
|
|
22
|
+
private initialized;
|
|
23
|
+
private starting?;
|
|
24
|
+
private lastValues;
|
|
25
|
+
constructor(loadSdk?: () => Promise<WebSdk>);
|
|
26
|
+
initialize(options: InitializeOptions): Promise<LaunchDarklyState>;
|
|
27
|
+
waitForInitialization(options?: WaitForInitializationOptions): Promise<WaitForInitializationResult>;
|
|
28
|
+
getState(): Promise<LaunchDarklyState>;
|
|
29
|
+
identify(options: IdentifyOptions): Promise<IdentifyResult>;
|
|
30
|
+
variation(options: VariationOptions): Promise<VariationResult>;
|
|
31
|
+
allFlags(): Promise<AllFlagsResult>;
|
|
32
|
+
setStreaming(options: SetStreamingOptions): Promise<void>;
|
|
33
|
+
setOnline(options: SetOnlineOptions): Promise<void>;
|
|
34
|
+
flush(): Promise<void>;
|
|
35
|
+
close(): Promise<void>;
|
|
36
|
+
clearStoredContext(): Promise<void>;
|
|
37
|
+
private sdk;
|
|
38
|
+
private started;
|
|
39
|
+
private state;
|
|
40
|
+
private flagsChanged;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Refuses a context whose key (or the key of any kind in a multi-context) is missing or empty. The browser SDK would generate
|
|
44
|
+
* one for an anonymous context, stored per browser, and every browser would then count as a context of its own.
|
|
45
|
+
*/
|
|
46
|
+
export declare function requireKeys(context: LDContext | undefined): void;
|