@launchdarkly/o11y 1.3.1 → 1.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.0](https://github.com/launchdarkly/observability-sdk/compare/o11y-1.3.1...o11y-1.4.0) (2026-10-28)
4
+
5
+
6
+ ### Features
7
+
8
+ * **o11y:** add sessionCookieDomain option and session docs ([#848](https://github.com/launchdarkly/observability-sdk/issues/848)) ([4ac4ccb](https://github.com/launchdarkly/observability-sdk/commit/4ac4ccb24b270f910c20b6e434569e507405e510))
9
+ * **o11y:** deprecate H.addSessionFeedback and ReportDialog ([#843](https://github.com/launchdarkly/observability-sdk/issues/843)) ([6d0273d](https://github.com/launchdarkly/observability-sdk/commit/6d0273d21cec5fba528f74dae89db53d38126f2a))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **o11y:** buffer telemetry until start() with manualStart ([#846](https://github.com/launchdarkly/observability-sdk/issues/846)) ([b851d78](https://github.com/launchdarkly/observability-sdk/commit/b851d7832bd5905d77c9ca2d41a2de6064ed364b))
15
+ * **o11y:** export metrics with delta temporality ([#845](https://github.com/launchdarkly/observability-sdk/issues/845)) ([22e7201](https://github.com/launchdarkly/observability-sdk/commit/22e7201d29eaefe22c286272fd250a07dce421ff))
16
+ * **o11y:** refresh observe-only sessions on telemetry activity ([#847](https://github.com/launchdarkly/observability-sdk/issues/847)) ([7799eb3](https://github.com/launchdarkly/observability-sdk/commit/7799eb368a2ca1d3dda01e8517d650ccfbe6f450))
17
+
3
18
  ## [1.3.1](https://github.com/launchdarkly/observability-sdk/compare/o11y-1.3.0...o11y-1.3.1) (2026-10-21)
4
19
 
5
20
 
@@ -0,0 +1,130 @@
1
+ var i = (e, r, t) => new Promise((a, s) => {
2
+ var n = (o) => {
3
+ try {
4
+ l(t.next(o));
5
+ } catch (d) {
6
+ s(d);
7
+ }
8
+ }, b = (o) => {
9
+ try {
10
+ l(t.throw(o));
11
+ } catch (d) {
12
+ s(d);
13
+ }
14
+ }, l = (o) => o.done ? a(o.value) : Promise.resolve(o.value).then(n, b);
15
+ l((t = t.apply(e, r)).next());
16
+ });
17
+ import { B as _, d as h } from "./buffer-CwCRPuMA.js";
18
+ const f = () => {
19
+ const e = {
20
+ end: () => {
21
+ },
22
+ spanContext: () => ({
23
+ traceId: "",
24
+ spanId: "",
25
+ traceFlags: 0
26
+ }),
27
+ setAttribute: (r, t) => e,
28
+ setAttributes: (r) => e,
29
+ addEvent: (r, t, a) => e,
30
+ addLinks: (r) => e,
31
+ setStatus: (r) => e,
32
+ recordException: () => {
33
+ },
34
+ addLink: () => e,
35
+ updateName: () => e,
36
+ isRecording: () => !1
37
+ };
38
+ return e;
39
+ };
40
+ function c(e, r, t) {
41
+ if (typeof t == "function")
42
+ return t;
43
+ if (typeof r == "function")
44
+ return r;
45
+ if (typeof e == "function")
46
+ return e;
47
+ }
48
+ class p extends _ {
49
+ _startSdk() {
50
+ return i(this, null, function* () {
51
+ yield this._sdk.start();
52
+ });
53
+ }
54
+ // Never buffered: with `manualStart`, `start()` may run before the plugin
55
+ // has attached an SDK. It then stays pending and resolves once `load`
56
+ // attaches and starts the SDK.
57
+ start() {
58
+ return i(this, null, function* () {
59
+ return this._start();
60
+ });
61
+ }
62
+ // Never buffered, and never throws: before an SDK is attached it just
63
+ // cancels a start that has not run yet.
64
+ stop() {
65
+ return i(this, null, function* () {
66
+ yield this._stop(() => this._sdk.stop());
67
+ });
68
+ }
69
+ recordGauge(r) {
70
+ return this._bufferCall("recordGauge", [r]);
71
+ }
72
+ recordCount(r) {
73
+ return this._bufferCall("recordCount", [r]);
74
+ }
75
+ recordIncr(r) {
76
+ return this._bufferCall("recordIncr", [r]);
77
+ }
78
+ recordHistogram(r) {
79
+ return this._bufferCall("recordHistogram", [r]);
80
+ }
81
+ recordUpDownCounter(r) {
82
+ return this._bufferCall("recordUpDownCounter", [r]);
83
+ }
84
+ // The callback holds the caller's own work, so it must never be buffered:
85
+ // deferring it would replay that work at an arbitrary later time, or drop it.
86
+ startSpan(r, t, a, s) {
87
+ var n;
88
+ return this._isReady ? this._bufferCall("startSpan", [r, t, a, s]) : (this._logNoopSpanWarning(), (n = c(t, a, s)) == null ? void 0 : n(f()));
89
+ }
90
+ startManualSpan(r, t, a, s) {
91
+ var n;
92
+ return this._isReady ? this._bufferCall("startManualSpan", [r, t, a, s]) : (this._logNoopSpanWarning(), (n = c(t, a, s)) == null ? void 0 : n(f()));
93
+ }
94
+ _logNoopSpanWarning() {
95
+ h(
96
+ "startSpan/startManualSpan called before start()",
97
+ "span-before-start",
98
+ "warn",
99
+ "The span callback runs on a no-op span and the span is not recorded."
100
+ );
101
+ }
102
+ register(r, t) {
103
+ return this._bufferCall("register", [r, t]);
104
+ }
105
+ recordLog(r, t, a) {
106
+ return this._bufferCall("recordLog", [r, t, a]);
107
+ }
108
+ recordError(r, t, a, s, n) {
109
+ return this._bufferCall("recordError", [
110
+ r,
111
+ t,
112
+ a,
113
+ s,
114
+ n
115
+ ]);
116
+ }
117
+ setLDContextKeyAttributes(r) {
118
+ return this._bufferCall("setLDContextKeyAttributes", [r]);
119
+ }
120
+ getLDContextKeyAttributes() {
121
+ return this._isLoaded ? this._callSdk("getLDContextKeyAttributes", []) : void 0;
122
+ }
123
+ }
124
+ let u;
125
+ typeof globalThis != "undefined" ? globalThis.LDObserve ? u = globalThis.LDObserve : (u = new p(), globalThis.LDObserve = u) : u = new p();
126
+ export {
127
+ u as L,
128
+ f as g
129
+ };
130
+ //# sourceMappingURL=LDObserve-BQr7RYVC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LDObserve-BQr7RYVC.js","sources":["../src/client/otel/utils.ts","../src/sdk/LDObserve.ts"],"sourcesContent":["import {\n\tAttributes,\n\tAttributeValue,\n\tLink,\n\tSpan,\n\tSpanStatus,\n\tTimeInput,\n} from '@opentelemetry/api'\n\nexport const getNoopSpan = () => {\n\tconst noopSpan: Span = {\n\t\tend: () => {},\n\t\tspanContext: () => ({\n\t\t\ttraceId: '',\n\t\t\tspanId: '',\n\t\t\ttraceFlags: 0,\n\t\t}),\n\t\tsetAttribute: (_key: string, _value: AttributeValue) => noopSpan,\n\t\tsetAttributes: (_attributes: Attributes) => noopSpan,\n\t\taddEvent: (\n\t\t\t_name: string,\n\t\t\t_attributesOrStartTime?: Attributes | TimeInput,\n\t\t\t_startTime?: TimeInput,\n\t\t) => noopSpan,\n\t\taddLinks: (_links: Link[]) => noopSpan,\n\t\tsetStatus: (_status: SpanStatus) => noopSpan,\n\t\trecordException: () => {},\n\t\taddLink: () => noopSpan,\n\t\tupdateName: () => noopSpan,\n\t\tisRecording: () => false,\n\t}\n\n\treturn noopSpan\n}\n","import type { Observe } from '../api/observe'\nimport type { LDClient } from '../integrations/launchdarkly'\nimport type { ErrorMessageType } from '../client/types/shared-types'\nimport type { OTelMetric as Metric } from '../client/types/types'\nimport type { Attributes, Context, Span, SpanOptions } from '@opentelemetry/api'\nimport type { LDPluginEnvironmentMetadata } from '../plugins/plugin'\nimport { BufferedClass } from './buffer'\nimport { getNoopSpan } from '../client/otel/utils'\nimport { ConsoleMethods } from '../client/types/client'\nimport { internalLogOnce } from './util'\n\n/**\n * Resolves the span callback from whichever argument position it was passed in,\n * matching the overloads `startSpan` and `startManualSpan` accept.\n */\nfunction resolveSpanCallback(\n\toptions: unknown,\n\tcontext: unknown,\n\tfn: unknown,\n): ((span: Span) => any) | undefined {\n\tif (typeof fn === 'function') {\n\t\treturn fn as (span: Span) => any\n\t}\n\tif (typeof context === 'function') {\n\t\treturn context as (span: Span) => any\n\t}\n\tif (typeof options === 'function') {\n\t\treturn options as (span: Span) => any\n\t}\n\treturn undefined\n}\n\nclass _LDObserve extends BufferedClass<Observe> implements Observe {\n\tprotected async _startSdk() {\n\t\tawait this._sdk.start()\n\t}\n\n\t// Never buffered: with `manualStart`, `start()` may run before the plugin\n\t// has attached an SDK. It then stays pending and resolves once `load`\n\t// attaches and starts the SDK.\n\tasync start() {\n\t\treturn this._start()\n\t}\n\n\t// Never buffered, and never throws: before an SDK is attached it just\n\t// cancels a start that has not run yet.\n\tasync stop() {\n\t\tawait this._stop(() => this._sdk.stop())\n\t}\n\n\trecordGauge(metric: Metric) {\n\t\treturn this._bufferCall('recordGauge', [metric])\n\t}\n\n\trecordCount(metric: Metric) {\n\t\treturn this._bufferCall('recordCount', [metric])\n\t}\n\n\trecordIncr(metric: Omit<Metric, 'value'>) {\n\t\treturn this._bufferCall('recordIncr', [metric])\n\t}\n\n\trecordHistogram(metric: Metric) {\n\t\treturn this._bufferCall('recordHistogram', [metric])\n\t}\n\n\trecordUpDownCounter(metric: Metric) {\n\t\treturn this._bufferCall('recordUpDownCounter', [metric])\n\t}\n\n\t// The callback holds the caller's own work, so it must never be buffered:\n\t// deferring it would replay that work at an arbitrary later time, or drop it.\n\tstartSpan(\n\t\tname: string,\n\t\toptions: SpanOptions | ((span?: Span) => any),\n\t\tcontext?: Context | ((span?: Span) => any),\n\t\tfn?: (span?: Span) => any,\n\t) {\n\t\tif (!this._isReady) {\n\t\t\tthis._logNoopSpanWarning()\n\t\t\treturn resolveSpanCallback(options, context, fn)?.(getNoopSpan())\n\t\t}\n\t\treturn this._bufferCall('startSpan', [name, options, context, fn])\n\t}\n\n\tstartManualSpan(\n\t\tname: string,\n\t\toptions: SpanOptions | ((span: Span) => any),\n\t\tcontext?: Context | ((span: Span) => any),\n\t\tfn?: (span: Span) => any,\n\t) {\n\t\tif (!this._isReady) {\n\t\t\tthis._logNoopSpanWarning()\n\t\t\treturn resolveSpanCallback(options, context, fn)?.(getNoopSpan())\n\t\t}\n\t\treturn this._bufferCall('startManualSpan', [name, options, context, fn])\n\t}\n\n\tprivate _logNoopSpanWarning() {\n\t\tinternalLogOnce(\n\t\t\t'startSpan/startManualSpan called before start()',\n\t\t\t'span-before-start',\n\t\t\t'warn',\n\t\t\t'The span callback runs on a no-op span and the span is not recorded.',\n\t\t)\n\t}\n\n\tregister(\n\t\tclient: LDClient,\n\t\tenvironmentMetadata: LDPluginEnvironmentMetadata,\n\t) {\n\t\treturn this._bufferCall('register', [client, environmentMetadata])\n\t}\n\n\trecordLog(message: any, level: ConsoleMethods, metadata?: Attributes) {\n\t\treturn this._bufferCall('recordLog', [message, level, metadata])\n\t}\n\n\trecordError(\n\t\terror: Error,\n\t\tmessage?: string,\n\t\tpayload?: { [key: string]: string },\n\t\tsource?: string,\n\t\ttype?: ErrorMessageType,\n\t) {\n\t\treturn this._bufferCall('recordError', [\n\t\t\terror,\n\t\t\tmessage,\n\t\t\tpayload,\n\t\t\tsource,\n\t\t\ttype,\n\t\t])\n\t}\n\n\tsetLDContextKeyAttributes(contextKeys: Attributes) {\n\t\treturn this._bufferCall('setLDContextKeyAttributes', [contextKeys])\n\t}\n\n\tgetLDContextKeyAttributes(): Attributes | undefined {\n\t\t// A getter: read directly once attached rather than buffering.\n\t\treturn this._isLoaded\n\t\t\t? this._callSdk('getLDContextKeyAttributes', [])\n\t\t\t: undefined\n\t}\n}\n\ninterface GlobalThis {\n\tLDObserve?: _LDObserve\n}\ndeclare var globalThis: GlobalThis\n\nexport let LDObserve!: _LDObserve\nif (typeof globalThis !== 'undefined') {\n\tif (globalThis.LDObserve) {\n\t\tLDObserve = globalThis.LDObserve\n\t} else {\n\t\tLDObserve = new _LDObserve()\n\t\tglobalThis.LDObserve = LDObserve\n\t}\n} else {\n\tLDObserve = new _LDObserve()\n}\n"],"names":["getNoopSpan","noopSpan","_key","_value","_attributes","_name","_attributesOrStartTime","_startTime","_links","_status","resolveSpanCallback","options","context","fn","_LDObserve","BufferedClass","__async","metric","name","_a","internalLogOnce","client","environmentMetadata","message","level","metadata","error","payload","source","type","contextKeys","LDObserve"],"mappings":"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"}
@@ -25,15 +25,80 @@ declare type AttributeValue = string | number | boolean | Array<null | undefined
25
25
 
26
26
  declare class BufferedClass<T extends object> {
27
27
  protected _sdk: T;
28
+ /** True once an SDK instance has been attached via `load`. */
28
29
  protected _isLoaded: boolean;
30
+ /** True once the attached SDK has started and the buffer has drained. */
31
+ protected _isReady: boolean;
29
32
  protected _callBuffer: Array<Event_2>;
30
33
  protected _capacity: number;
31
34
  protected _droppedEvents: number;
32
35
  protected _exceededCapacity: boolean;
33
36
  protected _logger: Logger;
37
+ private _pendingStart?;
38
+ /**
39
+ * The last start or stop queued on the attached SDK while it runs. Starts
40
+ * and stops run in call order, so the final state follows the last call.
41
+ */
42
+ private _lastOp?;
34
43
  protected _bufferCall(method: string, args: any[]): any;
44
+ /** Calls the attached SDK directly, logging instead of throwing. */
45
+ protected _callSdk(method: string, args: any[]): any;
35
46
  protected _enqueue(event: Event_2): void;
36
- load(sdk: T): void;
47
+ /**
48
+ * Attach an SDK implementation. With `ready: false` (e.g. `manualStart`
49
+ * mode, or an SDK whose `start` is still running), telemetry keeps
50
+ * buffering until `markReady()` is called.
51
+ */
52
+ load(sdk: T, { ready, started }?: BufferedLoadOptions): void;
53
+ private _runPendingStart;
54
+ /**
55
+ * Starts the attached SDK and drains the buffer. Before `load` the start
56
+ * is deferred. Starts and stops run in call order: a start made while a
57
+ * stop is queued runs after that stop, while overlapping starts with no
58
+ * stop between them share one SDK start.
59
+ */
60
+ protected _start(): Promise<void>;
61
+ /**
62
+ * Stops the attached SDK. Before `load` it cancels a deferred start. Once
63
+ * attached, every stop is queued: it waits for an earlier start or stop,
64
+ * and a later start waits for the SDK's stop (including any async
65
+ * shutdown) to finish. Errors are logged rather than thrown.
66
+ */
67
+ protected _stop(stopSdk: () => unknown): Promise<void>;
68
+ /** Runs `op` once the previously queued start or stop has settled. */
69
+ private _queueOp;
70
+ /**
71
+ * Starts the attached SDK. Subclasses whose SDK owns a `start` method
72
+ * override this so a deferred start reaches the real implementation.
73
+ */
74
+ protected _startSdk(): Promise<void>;
75
+ /**
76
+ * Drains the buffered calls into the attached SDK and lets subsequent
77
+ * calls run directly.
78
+ */
79
+ protected markReady(): void;
80
+ /**
81
+ * Defers a start until `load` attaches an SDK. Returns a promise that
82
+ * resolves once the SDK has been attached, started and drained.
83
+ */
84
+ protected _deferStart(): Promise<void>;
85
+ /** Cancels a deferred start so it never runs; awaiting callers resolve. */
86
+ protected _cancelPendingStart(): void;
87
+ }
88
+
89
+ declare interface BufferedLoadOptions {
90
+ /**
91
+ * Whether the attached SDK has already been started.
92
+ * When `false` (e.g. `manualStart` mode), calls keep buffering until the
93
+ * SDK is started; a `start()` made before `load` runs at `load` time.
94
+ */
95
+ ready?: boolean;
96
+ /**
97
+ * With `ready: true`, the attached SDK's own start while it is still
98
+ * running. It is queued like a `start()`, so a `stop()` made meanwhile
99
+ * waits for it instead of being undone by it.
100
+ */
101
+ started?: Promise<unknown>;
37
102
  }
38
103
 
39
104
  declare type ConsoleMethods = ConsoleMethodsTuple[number];
@@ -161,6 +226,7 @@ declare interface LDClientMin {
161
226
  export declare let LDObserve: _LDObserve;
162
227
 
163
228
  declare class _LDObserve extends BufferedClass<Observe> implements Observe {
229
+ protected _startSdk(): Promise<void>;
164
230
  start(): Promise<void>;
165
231
  stop(): Promise<void>;
166
232
  recordGauge(metric: OTelMetric): any;
@@ -170,6 +236,7 @@ declare class _LDObserve extends BufferedClass<Observe> implements Observe {
170
236
  recordUpDownCounter(metric: OTelMetric): any;
171
237
  startSpan(name: string, options: SpanOptions | ((span?: Span) => any), context?: Context | ((span?: Span) => any), fn?: (span?: Span) => any): any;
172
238
  startManualSpan(name: string, options: SpanOptions | ((span: Span) => any), context?: Context | ((span: Span) => any), fn?: (span: Span) => any): any;
239
+ private _logNoopSpanWarning;
173
240
  register(client: LDClientMin, environmentMetadata: LDPluginEnvironmentMetadata): any;
174
241
  recordLog(message: any, level: ConsoleMethods, metadata?: Attributes): any;
175
242
  recordError(error: Error, message?: string, payload?: {
@@ -219,10 +286,15 @@ declare class Logger {
219
286
  declare interface Observe {
220
287
  /**
221
288
  * Start the observability data capture when running in `manualStart` mode.
289
+ * Can safely be called before the SDK has initialized (e.g. before the
290
+ * plugin registers): the call resolves once the SDK is attached and
291
+ * started, without throwing.
222
292
  */
223
293
  start: () => Promise<void>;
224
294
  /**
225
295
  * Stop the observability data capture.
296
+ * Can safely be called before the SDK has initialized; before `start()`
297
+ * it cancels a pending start instead of throwing.
226
298
  */
227
299
  stop: () => Promise<void>;
228
300
  /**
package/dist/LDObserve.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./buffer-BjzLorpP.js";
2
- import { L as m } from "./LDObserve-DhF3vCDR.js";
1
+ import "./buffer-CwCRPuMA.js";
2
+ import { L as m } from "./LDObserve-BQr7RYVC.js";
3
3
  export {
4
4
  m as LDObserve
5
5
  };
@@ -7,15 +7,80 @@ import { LDPluginEnvironmentMetadata } from '@launchdarkly/js-client-sdk';
7
7
 
8
8
  declare class BufferedClass<T extends object> {
9
9
  protected _sdk: T;
10
+ /** True once an SDK instance has been attached via `load`. */
10
11
  protected _isLoaded: boolean;
12
+ /** True once the attached SDK has started and the buffer has drained. */
13
+ protected _isReady: boolean;
11
14
  protected _callBuffer: Array<Event_2>;
12
15
  protected _capacity: number;
13
16
  protected _droppedEvents: number;
14
17
  protected _exceededCapacity: boolean;
15
18
  protected _logger: Logger;
19
+ private _pendingStart?;
20
+ /**
21
+ * The last start or stop queued on the attached SDK while it runs. Starts
22
+ * and stops run in call order, so the final state follows the last call.
23
+ */
24
+ private _lastOp?;
16
25
  protected _bufferCall(method: string, args: any[]): any;
26
+ /** Calls the attached SDK directly, logging instead of throwing. */
27
+ protected _callSdk(method: string, args: any[]): any;
17
28
  protected _enqueue(event: Event_2): void;
18
- load(sdk: T): void;
29
+ /**
30
+ * Attach an SDK implementation. With `ready: false` (e.g. `manualStart`
31
+ * mode, or an SDK whose `start` is still running), telemetry keeps
32
+ * buffering until `markReady()` is called.
33
+ */
34
+ load(sdk: T, { ready, started }?: BufferedLoadOptions): void;
35
+ private _runPendingStart;
36
+ /**
37
+ * Starts the attached SDK and drains the buffer. Before `load` the start
38
+ * is deferred. Starts and stops run in call order: a start made while a
39
+ * stop is queued runs after that stop, while overlapping starts with no
40
+ * stop between them share one SDK start.
41
+ */
42
+ protected _start(): Promise<void>;
43
+ /**
44
+ * Stops the attached SDK. Before `load` it cancels a deferred start. Once
45
+ * attached, every stop is queued: it waits for an earlier start or stop,
46
+ * and a later start waits for the SDK's stop (including any async
47
+ * shutdown) to finish. Errors are logged rather than thrown.
48
+ */
49
+ protected _stop(stopSdk: () => unknown): Promise<void>;
50
+ /** Runs `op` once the previously queued start or stop has settled. */
51
+ private _queueOp;
52
+ /**
53
+ * Starts the attached SDK. Subclasses whose SDK owns a `start` method
54
+ * override this so a deferred start reaches the real implementation.
55
+ */
56
+ protected _startSdk(): Promise<void>;
57
+ /**
58
+ * Drains the buffered calls into the attached SDK and lets subsequent
59
+ * calls run directly.
60
+ */
61
+ protected markReady(): void;
62
+ /**
63
+ * Defers a start until `load` attaches an SDK. Returns a promise that
64
+ * resolves once the SDK has been attached, started and drained.
65
+ */
66
+ protected _deferStart(): Promise<void>;
67
+ /** Cancels a deferred start so it never runs; awaiting callers resolve. */
68
+ protected _cancelPendingStart(): void;
69
+ }
70
+
71
+ declare interface BufferedLoadOptions {
72
+ /**
73
+ * Whether the attached SDK has already been started.
74
+ * When `false` (e.g. `manualStart` mode), calls keep buffering until the
75
+ * SDK is started; a `start()` made before `load` runs at `load` time.
76
+ */
77
+ ready?: boolean;
78
+ /**
79
+ * With `ready: true`, the attached SDK's own start while it is still
80
+ * running. It is queued like a `start()`, so a `stop()` made meanwhile
81
+ * waits for it instead of being undone by it.
82
+ */
83
+ started?: Promise<unknown>;
19
84
  }
20
85
 
21
86
  declare type Event_2 = {
@@ -71,7 +136,9 @@ declare interface LDClientMin {
71
136
  export declare let LDRecord: _LDRecord;
72
137
 
73
138
  declare class _LDRecord extends BufferedClass<Record_2> implements Record_2 {
139
+ private _deferredStartOptions?;
74
140
  getSession(): SessionDetails | null;
141
+ protected _startSdk(): Promise<void>;
75
142
  start(options?: StartOptions): Promise<void>;
76
143
  stop(): void;
77
144
  addSessionProperties(properties: {
@@ -99,11 +166,16 @@ declare interface Record_2 {
99
166
  /**
100
167
  * Start the session when running in `manualStart` mode.
101
168
  * Can be used to force start a new session.
169
+ * Can safely be called before the SDK has initialized (e.g. before the
170
+ * plugin registers): the call resolves once the SDK is attached and
171
+ * started, without throwing.
102
172
  * @param options the session start options.
103
173
  */
104
174
  start: (options?: StartOptions) => Promise<void>;
105
175
  /**
106
176
  * Stop the session recording.
177
+ * Can safely be called before the SDK has initialized; before `start()`
178
+ * it cancels a pending start instead of throwing.
107
179
  */
108
180
  stop: () => void;
109
181
  /**
package/dist/LDRecord.js CHANGED
@@ -1,48 +1,67 @@
1
- var a = (l, e, r) => new Promise((f, d) => {
2
- var h = (s) => {
1
+ var p = Object.defineProperty;
2
+ var S = (s, t, e) => t in s ? p(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e;
3
+ var h = (s, t, e) => S(s, typeof t != "symbol" ? t + "" : t, e);
4
+ var n = (s, t, e) => new Promise((o, l) => {
5
+ var c = (r) => {
3
6
  try {
4
- i(r.next(s));
5
- } catch (o) {
6
- d(o);
7
+ d(e.next(r));
8
+ } catch (a) {
9
+ l(a);
7
10
  }
8
- }, u = (s) => {
11
+ }, f = (r) => {
9
12
  try {
10
- i(r.throw(s));
11
- } catch (o) {
12
- d(o);
13
+ d(e.throw(r));
14
+ } catch (a) {
15
+ l(a);
13
16
  }
14
- }, i = (s) => s.done ? f(s.value) : Promise.resolve(s.value).then(h, u);
15
- i((r = r.apply(l, e)).next());
17
+ }, d = (r) => r.done ? o(r.value) : Promise.resolve(r.value).then(c, f);
18
+ d((e = e.apply(s, t)).next());
16
19
  });
17
- import { B as g } from "./buffer-BjzLorpP.js";
18
- class n extends g {
20
+ import { B as g } from "./buffer-CwCRPuMA.js";
21
+ class _ extends g {
22
+ constructor() {
23
+ super(...arguments);
24
+ h(this, "_deferredStartOptions");
25
+ }
19
26
  getSession() {
20
- return this._isLoaded ? this._bufferCall("getSession", []) : null;
27
+ return this._isLoaded ? this._callSdk("getSession", []) : null;
28
+ }
29
+ _startSdk() {
30
+ return n(this, null, function* () {
31
+ const e = this._deferredStartOptions;
32
+ this._deferredStartOptions = void 0, yield this._sdk.start(e);
33
+ });
21
34
  }
35
+ // Never buffered: with `manualStart`, `start()` may run before the plugin
36
+ // has attached an SDK. It then stays pending and resolves once `load`
37
+ // attaches and starts the SDK.
22
38
  start(e) {
23
- return a(this, null, function* () {
24
- return this._sdk.start(e);
39
+ return n(this, null, function* () {
40
+ return this._deferredStartOptions = e, this._start();
25
41
  });
26
42
  }
43
+ // Never buffered, and never throws: before an SDK is attached it just
44
+ // cancels a start that has not run yet. Once attached, the stop is queued
45
+ // after any running start or stop, so it may complete asynchronously.
27
46
  stop() {
28
- return this._sdk.stop();
47
+ this._stop(() => this._sdk.stop());
29
48
  }
30
49
  addSessionProperties(e) {
31
50
  return this._bufferCall("addSessionProperties", [e]);
32
51
  }
33
52
  getRecordingState() {
34
- return this._isLoaded ? this._bufferCall("getRecordingState", []) : "NotRecording";
53
+ return this._isLoaded ? this._callSdk("getRecordingState", []) : "NotRecording";
35
54
  }
36
55
  snapshot(e) {
37
- return this._isLoaded ? this._bufferCall("snapshot", [e]) : Promise.resolve(void 0);
56
+ return this._isLoaded ? this._callSdk("snapshot", [e]) : Promise.resolve(void 0);
38
57
  }
39
- register(e, r) {
40
- return this._bufferCall("register", [e, r]);
58
+ register(e, o) {
59
+ return this._bufferCall("register", [e, o]);
41
60
  }
42
61
  }
43
- let t;
44
- typeof globalThis != "undefined" ? globalThis.LDRecord ? t = globalThis.LDRecord : (t = new n(), globalThis.LDRecord = t) : t = new n();
62
+ let i;
63
+ typeof globalThis != "undefined" ? globalThis.LDRecord ? i = globalThis.LDRecord : (i = new _(), globalThis.LDRecord = i) : i = new _();
45
64
  export {
46
- t as LDRecord
65
+ i as LDRecord
47
66
  };
48
67
  //# sourceMappingURL=LDRecord.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LDRecord.js","sources":["../src/sdk/LDRecord.ts"],"sourcesContent":["import type { Record } from '../api/record'\nimport type { SessionDetails } from '../client'\nimport type { LDClient } from '../integrations/launchdarkly'\nimport type { StartOptions } from '../client/types/types'\nimport type { LDPluginEnvironmentMetadata } from '../plugins/plugin'\nimport { BufferedClass } from './buffer'\n\nclass _LDRecord extends BufferedClass<Record> implements Record {\n\tgetSession(): SessionDetails | null {\n\t\treturn this._isLoaded ? this._bufferCall('getSession', []) : null\n\t}\n\n\tasync start(options?: StartOptions) {\n\t\t// avoid buffering the start call\n\t\treturn this._sdk.start(options)\n\t}\n\n\tstop() {\n\t\t// avoid buffering the stop call\n\t\treturn this._sdk.stop()\n\t}\n\n\taddSessionProperties(properties: { [key: string]: any }) {\n\t\treturn this._bufferCall('addSessionProperties', [properties])\n\t}\n\n\tgetRecordingState() {\n\t\treturn this._isLoaded\n\t\t\t? this._bufferCall('getRecordingState', [])\n\t\t\t: ('NotRecording' as const)\n\t}\n\n\tsnapshot(element: HTMLCanvasElement) {\n\t\treturn this._isLoaded\n\t\t\t? this._bufferCall('snapshot', [element])\n\t\t\t: Promise.resolve(undefined)\n\t}\n\n\tregister(\n\t\tclient: LDClient,\n\t\tenvironmentMetadata: LDPluginEnvironmentMetadata,\n\t) {\n\t\treturn this._bufferCall('register', [client, environmentMetadata])\n\t}\n}\n\ninterface GlobalThis {\n\tLDRecord?: _LDRecord\n}\ndeclare var globalThis: GlobalThis\n\nexport let LDRecord!: _LDRecord\nif (typeof globalThis !== 'undefined') {\n\tif (globalThis.LDRecord) {\n\t\tLDRecord = globalThis.LDRecord\n\t} else {\n\t\tLDRecord = new _LDRecord()\n\t\tglobalThis.LDRecord = LDRecord\n\t}\n} else {\n\tLDRecord = new _LDRecord()\n}\n"],"names":["_LDRecord","BufferedClass","options","__async","properties","element","client","environmentMetadata","LDRecord"],"mappings":";;;;;;;;;;;;;;;;;AAOA,MAAMA,UAAkBC,EAAwC;AAAA,EAC/D,aAAoC;AACnC,WAAO,KAAK,YAAY,KAAK,YAAY,cAAc,CAAA,CAAE,IAAI;AAAA,EAC9D;AAAA,EAEM,MAAMC,GAAwB;AAAA,WAAAC,EAAA;AAEnC,aAAO,KAAK,KAAK,MAAMD,CAAO;AAAA,IAC/B;AAAA;AAAA,EAEA,OAAO;AAEN,WAAO,KAAK,KAAK,KAAA;AAAA,EAClB;AAAA,EAEA,qBAAqBE,GAAoC;AACxD,WAAO,KAAK,YAAY,wBAAwB,CAACA,CAAU,CAAC;AAAA,EAC7D;AAAA,EAEA,oBAAoB;AACnB,WAAO,KAAK,YACT,KAAK,YAAY,qBAAqB,CAAA,CAAE,IACvC;AAAA,EACL;AAAA,EAEA,SAASC,GAA4B;AACpC,WAAO,KAAK,YACT,KAAK,YAAY,YAAY,CAACA,CAAO,CAAC,IACtC,QAAQ,QAAQ,MAAS;AAAA,EAC7B;AAAA,EAEA,SACCC,GACAC,GACC;AACD,WAAO,KAAK,YAAY,YAAY,CAACD,GAAQC,CAAmB,CAAC;AAAA,EAClE;AACD;AAOO,IAAIC;AACP,OAAO,cAAe,cACrB,WAAW,WACdA,IAAW,WAAW,YAEtBA,IAAW,IAAIR,EAAA,GACf,WAAW,WAAWQ,KAGvBA,IAAW,IAAIR,EAAA;"}
1
+ {"version":3,"file":"LDRecord.js","sources":["../src/sdk/LDRecord.ts"],"sourcesContent":["import type { Record } from '../api/record'\nimport type { SessionDetails } from '../client'\nimport type { LDClient } from '../integrations/launchdarkly'\nimport type { StartOptions } from '../client/types/types'\nimport type { LDPluginEnvironmentMetadata } from '../plugins/plugin'\nimport { BufferedClass } from './buffer'\n\nclass _LDRecord extends BufferedClass<Record> implements Record {\n\tprivate _deferredStartOptions?: StartOptions\n\n\tgetSession(): SessionDetails | null {\n\t\treturn this._isLoaded ? this._callSdk('getSession', []) : null\n\t}\n\n\tprotected async _startSdk() {\n\t\t// Take the options before awaiting so a start queued meanwhile keeps\n\t\t// its own options.\n\t\tconst options = this._deferredStartOptions\n\t\tthis._deferredStartOptions = undefined\n\t\tawait this._sdk.start(options)\n\t}\n\n\t// Never buffered: with `manualStart`, `start()` may run before the plugin\n\t// has attached an SDK. It then stays pending and resolves once `load`\n\t// attaches and starts the SDK.\n\tasync start(options?: StartOptions) {\n\t\tthis._deferredStartOptions = options\n\t\treturn this._start()\n\t}\n\n\t// Never buffered, and never throws: before an SDK is attached it just\n\t// cancels a start that has not run yet. Once attached, the stop is queued\n\t// after any running start or stop, so it may complete asynchronously.\n\tstop() {\n\t\tvoid this._stop(() => this._sdk.stop())\n\t}\n\n\taddSessionProperties(properties: { [key: string]: any }) {\n\t\treturn this._bufferCall('addSessionProperties', [properties])\n\t}\n\n\tgetRecordingState() {\n\t\treturn this._isLoaded\n\t\t\t? this._callSdk('getRecordingState', [])\n\t\t\t: ('NotRecording' as const)\n\t}\n\n\tsnapshot(element: HTMLCanvasElement) {\n\t\treturn this._isLoaded\n\t\t\t? this._callSdk('snapshot', [element])\n\t\t\t: Promise.resolve(undefined)\n\t}\n\n\tregister(\n\t\tclient: LDClient,\n\t\tenvironmentMetadata: LDPluginEnvironmentMetadata,\n\t) {\n\t\treturn this._bufferCall('register', [client, environmentMetadata])\n\t}\n}\n\ninterface GlobalThis {\n\tLDRecord?: _LDRecord\n}\ndeclare var globalThis: GlobalThis\n\nexport let LDRecord!: _LDRecord\nif (typeof globalThis !== 'undefined') {\n\tif (globalThis.LDRecord) {\n\t\tLDRecord = globalThis.LDRecord\n\t} else {\n\t\tLDRecord = new _LDRecord()\n\t\tglobalThis.LDRecord = LDRecord\n\t}\n} else {\n\tLDRecord = new _LDRecord()\n}\n"],"names":["_LDRecord","BufferedClass","__publicField","__async","options","properties","element","client","environmentMetadata","LDRecord"],"mappings":";;;;;;;;;;;;;;;;;;;;AAOA,MAAMA,UAAkBC,EAAwC;AAAA,EAAhE;AAAA;AACS,IAAAC,EAAA;AAAA;AAAA,EAER,aAAoC;AACnC,WAAO,KAAK,YAAY,KAAK,SAAS,cAAc,CAAA,CAAE,IAAI;AAAA,EAC3D;AAAA,EAEgB,YAAY;AAAA,WAAAC,EAAA;AAG3B,YAAMC,IAAU,KAAK;AACrB,WAAK,wBAAwB,QAC7B,MAAM,KAAK,KAAK,MAAMA,CAAO;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,MAAMA,GAAwB;AAAA,WAAAD,EAAA;AACnC,kBAAK,wBAAwBC,GACtB,KAAK,OAAA;AAAA,IACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACN,IAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM;AAAA,EACvC;AAAA,EAEA,qBAAqBC,GAAoC;AACxD,WAAO,KAAK,YAAY,wBAAwB,CAACA,CAAU,CAAC;AAAA,EAC7D;AAAA,EAEA,oBAAoB;AACnB,WAAO,KAAK,YACT,KAAK,SAAS,qBAAqB,CAAA,CAAE,IACpC;AAAA,EACL;AAAA,EAEA,SAASC,GAA4B;AACpC,WAAO,KAAK,YACT,KAAK,SAAS,YAAY,CAACA,CAAO,CAAC,IACnC,QAAQ,QAAQ,MAAS;AAAA,EAC7B;AAAA,EAEA,SACCC,GACAC,GACC;AACD,WAAO,KAAK,YAAY,YAAY,CAACD,GAAQC,CAAmB,CAAC;AAAA,EAClE;AACD;AAOO,IAAIC;AACP,OAAO,cAAe,cACrB,WAAW,WACdA,IAAW,WAAW,YAEtBA,IAAW,IAAIT,EAAA,GACf,WAAW,WAAWS,KAGvBA,IAAW,IAAIT,EAAA;"}