@moviie/player-sdk 0.2.0 → 0.3.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/dist/index.d.cts CHANGED
@@ -1,6 +1,55 @@
1
1
  import { z } from 'zod';
2
2
  export { PLAYER_API_EVENTS, PlayerAPIEvent, PlayerState } from '@moviie/player-types';
3
3
 
4
+ /** A single moment in the video where the term occurs. */
5
+ interface TranscriptSearchMatch {
6
+ segmentIndex: number;
7
+ startSeconds: number;
8
+ endSeconds: number;
9
+ /** The sentence/segment containing the term (length-bounded by the server). */
10
+ text: string;
11
+ }
12
+ /** Result set for one transcript search query. */
13
+ interface TranscriptSearchResult {
14
+ query: string;
15
+ language: string | null;
16
+ total: number;
17
+ matches: TranscriptSearchMatch[];
18
+ nextCursor: number | null;
19
+ }
20
+ /** Default debounce and minimum query length for the in-player search UI. */
21
+ declare const TRANSCRIPT_SEARCH_DEBOUNCE_MS = 250;
22
+ declare const TRANSCRIPT_SEARCH_MIN_LENGTH = 2;
23
+ /** Low-level fetch of the transcript search endpoint, with error mapping. */
24
+ declare function fetchTranscriptSearch(params: {
25
+ url: string;
26
+ headers?: Record<string, string>;
27
+ signal?: AbortSignal;
28
+ }): Promise<TranscriptSearchResult>;
29
+ interface TranscriptSearchController {
30
+ /** Schedule a debounced search for the (trimmed) query. */
31
+ search(query: string): void;
32
+ /** Cancel any pending debounce and in-flight request. */
33
+ cancel(): void;
34
+ /** Tear down the controller. */
35
+ destroy(): void;
36
+ }
37
+ /**
38
+ * UI controller that applies debounce + a minimum query length before calling
39
+ * the search endpoint, and aborts any in-flight request when a newer query
40
+ * arrives. Queries below the minimum length clear the results without hitting
41
+ * the network — this is what keeps incomplete words from flooding the backend
42
+ * (FR-003 / SC-002).
43
+ */
44
+ declare function createTranscriptSearchController(opts: {
45
+ fetcher: (query: string, signal: AbortSignal) => Promise<TranscriptSearchResult>;
46
+ onResult: (result: TranscriptSearchResult) => void;
47
+ onError?: (error: unknown) => void;
48
+ onLoadingChange?: (loading: boolean) => void;
49
+ debounceMs?: number;
50
+ minLength?: number;
51
+ }): TranscriptSearchController;
52
+
4
53
  interface MoviieClientInfo {
5
54
  bundleId?: string;
6
55
  platform: "ios" | "android" | "web";
@@ -103,6 +152,30 @@ declare class MoviieClient {
103
152
  });
104
153
  private headers;
105
154
  getPlayback(embedId: string, signal?: AbortSignal): Promise<MoviiePlaybackData>;
155
+ /**
156
+ * Search the spoken content of the video a playback session is playing, and
157
+ * return the moments where the term appears (each with a timestamp). The
158
+ * session scopes the search to the video it actually loaded (swap-safe) and
159
+ * authorizes the request — it was gated when bootstrapped. Obtain the session
160
+ * id from the telemetry bootstrap. Matching is case- and accent-insensitive.
161
+ */
162
+ search(sessionId: string, query: string, opts?: {
163
+ limit?: number;
164
+ cursor?: number | null;
165
+ signal?: AbortSignal;
166
+ }): Promise<TranscriptSearchResult>;
167
+ /**
168
+ * Private transcript search for an embed's video (feature 183) — the
169
+ * authenticated twin of {@link search}. Requires a PRIVATE API key (publishable
170
+ * keys are rejected) and is scoped to the key's organization; the embed must
171
+ * belong to it. Unlike {@link search} it needs no playback session. Matching is
172
+ * case- and accent-insensitive.
173
+ */
174
+ searchEmbedTranscript(embedId: string, query: string, opts?: {
175
+ limit?: number;
176
+ cursor?: number | null;
177
+ signal?: AbortSignal;
178
+ }): Promise<TranscriptSearchResult>;
106
179
  getVideo(videoId: string, signal?: AbortSignal): Promise<MoviieVideo>;
107
180
  resolveEmbedIdFromVideoId(videoId: string, signal?: AbortSignal): Promise<string>;
108
181
  getEventsBaseUrl(): string;
@@ -267,4 +340,4 @@ declare const MOVIIE_WATCH_BASE = "https://watch.moviie.ai";
267
340
 
268
341
  declare function deriveTelemetryEventsBaseUrlFromBootstrapUrl(bootstrapUrl: string): string | null;
269
342
 
270
- export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, type MoviieCTA, type MoviieCaption, type MoviieChapter, MoviieClient, type MoviieClientInfo, type MoviieEndpointsConfiguration, type MoviieErrorCode, MoviieNetworkError, MoviieNotFoundError, type MoviiePlaybackControls, type MoviiePlaybackData, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, type MoviieVideo, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TelemetryClient, type ViewerTokenStore, buildClientHeaders, configureMoviieEndpoints, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
343
+ export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, type MoviieCTA, type MoviieCaption, type MoviieChapter, MoviieClient, type MoviieClientInfo, type MoviieEndpointsConfiguration, type MoviieErrorCode, MoviieNetworkError, MoviieNotFoundError, type MoviiePlaybackControls, type MoviiePlaybackData, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, type MoviieVideo, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TRANSCRIPT_SEARCH_DEBOUNCE_MS, TRANSCRIPT_SEARCH_MIN_LENGTH, TelemetryClient, type TranscriptSearchController, type TranscriptSearchMatch, type TranscriptSearchResult, type ViewerTokenStore, buildClientHeaders, configureMoviieEndpoints, createTranscriptSearchController, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, fetchTranscriptSearch, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,55 @@
1
1
  import { z } from 'zod';
2
2
  export { PLAYER_API_EVENTS, PlayerAPIEvent, PlayerState } from '@moviie/player-types';
3
3
 
4
+ /** A single moment in the video where the term occurs. */
5
+ interface TranscriptSearchMatch {
6
+ segmentIndex: number;
7
+ startSeconds: number;
8
+ endSeconds: number;
9
+ /** The sentence/segment containing the term (length-bounded by the server). */
10
+ text: string;
11
+ }
12
+ /** Result set for one transcript search query. */
13
+ interface TranscriptSearchResult {
14
+ query: string;
15
+ language: string | null;
16
+ total: number;
17
+ matches: TranscriptSearchMatch[];
18
+ nextCursor: number | null;
19
+ }
20
+ /** Default debounce and minimum query length for the in-player search UI. */
21
+ declare const TRANSCRIPT_SEARCH_DEBOUNCE_MS = 250;
22
+ declare const TRANSCRIPT_SEARCH_MIN_LENGTH = 2;
23
+ /** Low-level fetch of the transcript search endpoint, with error mapping. */
24
+ declare function fetchTranscriptSearch(params: {
25
+ url: string;
26
+ headers?: Record<string, string>;
27
+ signal?: AbortSignal;
28
+ }): Promise<TranscriptSearchResult>;
29
+ interface TranscriptSearchController {
30
+ /** Schedule a debounced search for the (trimmed) query. */
31
+ search(query: string): void;
32
+ /** Cancel any pending debounce and in-flight request. */
33
+ cancel(): void;
34
+ /** Tear down the controller. */
35
+ destroy(): void;
36
+ }
37
+ /**
38
+ * UI controller that applies debounce + a minimum query length before calling
39
+ * the search endpoint, and aborts any in-flight request when a newer query
40
+ * arrives. Queries below the minimum length clear the results without hitting
41
+ * the network — this is what keeps incomplete words from flooding the backend
42
+ * (FR-003 / SC-002).
43
+ */
44
+ declare function createTranscriptSearchController(opts: {
45
+ fetcher: (query: string, signal: AbortSignal) => Promise<TranscriptSearchResult>;
46
+ onResult: (result: TranscriptSearchResult) => void;
47
+ onError?: (error: unknown) => void;
48
+ onLoadingChange?: (loading: boolean) => void;
49
+ debounceMs?: number;
50
+ minLength?: number;
51
+ }): TranscriptSearchController;
52
+
4
53
  interface MoviieClientInfo {
5
54
  bundleId?: string;
6
55
  platform: "ios" | "android" | "web";
@@ -103,6 +152,30 @@ declare class MoviieClient {
103
152
  });
104
153
  private headers;
105
154
  getPlayback(embedId: string, signal?: AbortSignal): Promise<MoviiePlaybackData>;
155
+ /**
156
+ * Search the spoken content of the video a playback session is playing, and
157
+ * return the moments where the term appears (each with a timestamp). The
158
+ * session scopes the search to the video it actually loaded (swap-safe) and
159
+ * authorizes the request — it was gated when bootstrapped. Obtain the session
160
+ * id from the telemetry bootstrap. Matching is case- and accent-insensitive.
161
+ */
162
+ search(sessionId: string, query: string, opts?: {
163
+ limit?: number;
164
+ cursor?: number | null;
165
+ signal?: AbortSignal;
166
+ }): Promise<TranscriptSearchResult>;
167
+ /**
168
+ * Private transcript search for an embed's video (feature 183) — the
169
+ * authenticated twin of {@link search}. Requires a PRIVATE API key (publishable
170
+ * keys are rejected) and is scoped to the key's organization; the embed must
171
+ * belong to it. Unlike {@link search} it needs no playback session. Matching is
172
+ * case- and accent-insensitive.
173
+ */
174
+ searchEmbedTranscript(embedId: string, query: string, opts?: {
175
+ limit?: number;
176
+ cursor?: number | null;
177
+ signal?: AbortSignal;
178
+ }): Promise<TranscriptSearchResult>;
106
179
  getVideo(videoId: string, signal?: AbortSignal): Promise<MoviieVideo>;
107
180
  resolveEmbedIdFromVideoId(videoId: string, signal?: AbortSignal): Promise<string>;
108
181
  getEventsBaseUrl(): string;
@@ -267,4 +340,4 @@ declare const MOVIIE_WATCH_BASE = "https://watch.moviie.ai";
267
340
 
268
341
  declare function deriveTelemetryEventsBaseUrlFromBootstrapUrl(bootstrapUrl: string): string | null;
269
342
 
270
- export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, type MoviieCTA, type MoviieCaption, type MoviieChapter, MoviieClient, type MoviieClientInfo, type MoviieEndpointsConfiguration, type MoviieErrorCode, MoviieNetworkError, MoviieNotFoundError, type MoviiePlaybackControls, type MoviiePlaybackData, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, type MoviieVideo, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TelemetryClient, type ViewerTokenStore, buildClientHeaders, configureMoviieEndpoints, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
343
+ export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, type MoviieCTA, type MoviieCaption, type MoviieChapter, MoviieClient, type MoviieClientInfo, type MoviieEndpointsConfiguration, type MoviieErrorCode, MoviieNetworkError, MoviieNotFoundError, type MoviiePlaybackControls, type MoviiePlaybackData, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, type MoviieVideo, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TRANSCRIPT_SEARCH_DEBOUNCE_MS, TRANSCRIPT_SEARCH_MIN_LENGTH, TelemetryClient, type TranscriptSearchController, type TranscriptSearchMatch, type TranscriptSearchResult, type ViewerTokenStore, buildClientHeaders, configureMoviieEndpoints, createTranscriptSearchController, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, fetchTranscriptSearch, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
package/dist/index.js CHANGED
@@ -268,6 +268,102 @@ async function fetchPlaybackData(params) {
268
268
  }
269
269
  return parsed.data;
270
270
  }
271
+ var matchSchema = z.object({
272
+ segmentIndex: z.number().int(),
273
+ startSeconds: z.number(),
274
+ endSeconds: z.number(),
275
+ text: z.string()
276
+ });
277
+ var resultSchema = z.object({
278
+ query: z.string(),
279
+ language: z.string().nullable(),
280
+ total: z.number().int(),
281
+ matches: z.array(matchSchema),
282
+ nextCursor: z.number().int().nullable()
283
+ });
284
+ var TRANSCRIPT_SEARCH_DEBOUNCE_MS = 250;
285
+ var TRANSCRIPT_SEARCH_MIN_LENGTH = 2;
286
+ var EMPTY_RESULT = (query) => ({
287
+ query,
288
+ language: null,
289
+ total: 0,
290
+ matches: [],
291
+ nextCursor: null
292
+ });
293
+ async function fetchTranscriptSearch(params) {
294
+ const response = await fetchWithRetry(params.url, {
295
+ method: "GET",
296
+ headers: params.headers,
297
+ signal: params.signal
298
+ });
299
+ if (response.status === 401) throw new MoviieAuthError();
300
+ if (response.status === 404) throw new MoviieNotFoundError();
301
+ if (response.status >= 500) throw new MoviieNetworkError();
302
+ if (!response.ok) throw new MoviieNetworkError();
303
+ const json = await response.json();
304
+ const parsed = resultSchema.safeParse(json);
305
+ if (!parsed.success) {
306
+ throw new MoviieNetworkError("Resposta de busca inv\xE1lida");
307
+ }
308
+ return parsed.data;
309
+ }
310
+ function createTranscriptSearchController(opts) {
311
+ const debounceMs = opts.debounceMs ?? TRANSCRIPT_SEARCH_DEBOUNCE_MS;
312
+ const minLength = opts.minLength ?? TRANSCRIPT_SEARCH_MIN_LENGTH;
313
+ let timer = null;
314
+ let inFlight = null;
315
+ function clearTimer() {
316
+ if (timer !== null) {
317
+ clearTimeout(timer);
318
+ timer = null;
319
+ }
320
+ }
321
+ function cancelInFlight() {
322
+ if (inFlight) {
323
+ inFlight.abort();
324
+ inFlight = null;
325
+ }
326
+ }
327
+ function search(rawQuery) {
328
+ const query = rawQuery.trim();
329
+ clearTimer();
330
+ if (query.length < minLength) {
331
+ cancelInFlight();
332
+ opts.onResult(EMPTY_RESULT(query));
333
+ return;
334
+ }
335
+ timer = setTimeout(() => {
336
+ timer = null;
337
+ cancelInFlight();
338
+ const controller = new AbortController();
339
+ inFlight = controller;
340
+ opts.onLoadingChange?.(true);
341
+ opts.fetcher(query, controller.signal).then((result) => {
342
+ if (!controller.signal.aborted) opts.onResult(result);
343
+ }).catch((error) => {
344
+ if (controller.signal.aborted) return;
345
+ if (error instanceof Error && error.name === "AbortError") return;
346
+ opts.onError?.(error);
347
+ }).finally(() => {
348
+ if (inFlight === controller) {
349
+ inFlight = null;
350
+ opts.onLoadingChange?.(false);
351
+ }
352
+ });
353
+ }, debounceMs);
354
+ }
355
+ return {
356
+ search,
357
+ cancel() {
358
+ clearTimer();
359
+ cancelInFlight();
360
+ },
361
+ destroy() {
362
+ clearTimer();
363
+ cancelInFlight();
364
+ }
365
+ };
366
+ }
271
367
 
272
368
  // src/client/moviie-client.ts
273
369
  var videoEmbedResponseSchema = z.object({
@@ -305,6 +401,50 @@ var MoviieClient = class {
305
401
  signal
306
402
  });
307
403
  }
404
+ /**
405
+ * Search the spoken content of the video a playback session is playing, and
406
+ * return the moments where the term appears (each with a timestamp). The
407
+ * session scopes the search to the video it actually loaded (swap-safe) and
408
+ * authorizes the request — it was gated when bootstrapped. Obtain the session
409
+ * id from the telemetry bootstrap. Matching is case- and accent-insensitive.
410
+ */
411
+ async search(sessionId, query, opts) {
412
+ const key = this.options.publishableKey?.trim();
413
+ if (!key) {
414
+ throw new MoviieAuthError(SDK_PLAYBACK_AUTH_ERROR_MESSAGE.KEY_REQUIRED);
415
+ }
416
+ if (!key.startsWith(SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE)) {
417
+ throw new MoviieAuthError(SDK_PLAYBACK_AUTH_ERROR_MESSAGE.PRIVATE_KEY_FORBIDDEN);
418
+ }
419
+ const base = getMoviieApiBaseUrl().replace(/\/+$/, "");
420
+ const params = new URLSearchParams({ q: query });
421
+ if (opts?.limit != null) params.set("limit", String(opts.limit));
422
+ if (opts?.cursor != null) params.set("cursor", String(opts.cursor));
423
+ const url = `${base}/sessions/${encodeURIComponent(sessionId)}/search?${params.toString()}`;
424
+ return fetchTranscriptSearch({ url, headers: this.headers(), signal: opts?.signal });
425
+ }
426
+ /**
427
+ * Private transcript search for an embed's video (feature 183) — the
428
+ * authenticated twin of {@link search}. Requires a PRIVATE API key (publishable
429
+ * keys are rejected) and is scoped to the key's organization; the embed must
430
+ * belong to it. Unlike {@link search} it needs no playback session. Matching is
431
+ * case- and accent-insensitive.
432
+ */
433
+ async searchEmbedTranscript(embedId, query, opts) {
434
+ const key = this.options.publishableKey?.trim();
435
+ if (!key) {
436
+ throw new MoviieAuthError(SDK_PLAYBACK_AUTH_ERROR_MESSAGE.KEY_REQUIRED);
437
+ }
438
+ if (key.startsWith(SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE)) {
439
+ throw new MoviieAuthError("A busca privada exige uma chave de API privada (n\xE3o publishable).");
440
+ }
441
+ const base = getMoviieApiBaseUrl().replace(/\/+$/, "");
442
+ const params = new URLSearchParams({ q: query });
443
+ if (opts?.limit != null) params.set("limit", String(opts.limit));
444
+ if (opts?.cursor != null) params.set("cursor", String(opts.cursor));
445
+ const url = `${base}/embeds/${encodeURIComponent(embedId)}/transcript/search?${params.toString()}`;
446
+ return fetchTranscriptSearch({ url, headers: this.headers(), signal: opts?.signal });
447
+ }
308
448
  async getVideo(videoId, signal) {
309
449
  const key = this.options.publishableKey?.trim();
310
450
  if (!key) {
@@ -730,6 +870,6 @@ function deriveTelemetryEventsBaseUrlFromBootstrapUrl(bootstrapUrl) {
730
870
  }
731
871
  }
732
872
 
733
- export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, MoviieClient, MoviieNetworkError, MoviieNotFoundError, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TelemetryClient, buildClientHeaders, configureMoviieEndpoints, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
873
+ export { HEARTBEAT_CONFIG, MOVIIE_CDN_BASE, MOVIIE_DEFAULT_API_BASE_URL, MOVIIE_TELEMETRY_API_PATH_PREFIX, MOVIIE_WATCH_BASE, MemoryViewerTokenStore, MoviieAuthError, MoviieBundleBlockedError, MoviieClient, MoviieNetworkError, MoviieNotFoundError, MoviieRateLimitError, MoviieReferrerBlockedError, MoviieSubscriptionInactiveError, PLAYBACK_EVENT_TYPE, SDK_PLAYBACK_AUTH_ERROR_MESSAGE, SDK_PUBLIC_API_KEY_PREFIX_PUBLISHABLE, TELEMETRY_TOKEN_CONFIG, TRANSCRIPT_SEARCH_DEBOUNCE_MS, TRANSCRIPT_SEARCH_MIN_LENGTH, TelemetryClient, buildClientHeaders, configureMoviieEndpoints, createTranscriptSearchController, deriveMoviieTelemetryBaseUrlFromApiBaseUrl, deriveTelemetryEventsBaseUrlFromBootstrapUrl, fetchPlaybackData, fetchTranscriptSearch, getMoviieApiBaseUrl, getMoviieEventsBaseUrl, planRefresh, resetMoviieEndpointsConfiguration };
734
874
  //# sourceMappingURL=index.js.map
735
875
  //# sourceMappingURL=index.js.map