@appfunnel-dev/sdk 0.12.0 → 0.14.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.
@@ -1,4 +1,4 @@
1
- import { useFunnelContext } from './chunk-DAHMOQ63.js';
1
+ import { useFunnelContext } from './chunk-H5C2QJIY.js';
2
2
  import { useCallback, useSyncExternalStore, useMemo } from 'react';
3
3
 
4
4
  function useResponse(key) {
@@ -100,5 +100,5 @@ function useNavigation() {
100
100
  }
101
101
 
102
102
  export { useNavigation, useResponse, useResponses };
103
- //# sourceMappingURL=chunk-GZKA33W2.js.map
104
- //# sourceMappingURL=chunk-GZKA33W2.js.map
103
+ //# sourceMappingURL=chunk-7JLCKTX6.js.map
104
+ //# sourceMappingURL=chunk-7JLCKTX6.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/hooks/useResponse.ts","../src/hooks/useNavigation.ts"],"names":["useSyncExternalStore","useCallback"],"mappings":"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","file":"chunk-GZKA33W2.js","sourcesContent":["import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single response variable (answers.*).\n *\n * ```tsx\n * const [goal, setGoal] = useResponse<string>('goal')\n * const [interests, setInterests] = useResponse<string[]>('interests')\n * ```\n */\nexport function useResponse<T extends VariableValue>(\n key: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n const prefixedKey = `answers.${key}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb, { keys: [prefixedKey] }),\n [variableStore, prefixedKey],\n )\n const getSnapshot = useCallback(\n () => variableStore.get(prefixedKey) as T,\n [variableStore, prefixedKey],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(prefixedKey, v),\n [variableStore, prefixedKey],\n )\n\n return [value, setValue]\n}\n\n/**\n * Read all response variables as a flat object (without the `answers.` prefix).\n *\n * Only re-renders when an `answers.*` variable changes.\n *\n * ```tsx\n * const responses = useResponses()\n * // { goal: 'weight_loss', interests: ['yoga', 'running'] }\n * ```\n */\nexport function useResponses(): Record<string, VariableValue> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb, { prefix: 'answers.' }),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const result: Record<string, VariableValue> = {}\n for (const [key, value] of Object.entries(variables)) {\n if (key.startsWith('answers.')) {\n result[key.slice(8)] = value\n }\n }\n return result\n }, [variables])\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { NavigationState } from '../types'\n\n/**\n * Navigation hook — evaluates routes, navigates between pages, tracks progress.\n *\n * Only re-renders when the router's current page changes (not on variable changes).\n * Variables are read lazily at navigation time — callbacks are referentially stable.\n */\nexport function useNavigation(): NavigationState {\n const { router, variableStore, tracker } = useFunnelContext()\n\n // Re-render only when the router's current page changes\n useSyncExternalStore(\n useCallback((cb: () => void) => router.subscribe(cb), [router]),\n useCallback(() => router.getSnapshot(), [router]),\n useCallback(() => router.getSnapshot(), [router]),\n )\n\n /** Called after the router has already navigated to `key`. */\n const afterNavigate = useCallback((key: string) => {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': key,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n })\n }, [router, tracker, variableStore])\n\n const goToNextPage = useCallback(() => {\n const previousPage = router.getCurrentPage()\n if (previousPage) {\n tracker.stopPageTracking()\n }\n\n // Read variables at call time — not captured in closure\n const variables = variableStore.getState()\n const nextKey = router.goToNextPage(variables)\n if (nextKey) {\n afterNavigate(nextKey)\n }\n }, [router, tracker, variableStore, afterNavigate])\n\n const goBack = useCallback(() => {\n tracker.stopPageTracking()\n const prevKey = router.goBack()\n if (prevKey) {\n afterNavigate(prevKey)\n }\n }, [router, tracker, afterNavigate])\n\n const goToPage = useCallback((pageKey: string) => {\n tracker.stopPageTracking()\n const key = router.goToPage(pageKey)\n if (key) {\n afterNavigate(key)\n }\n }, [router, tracker, afterNavigate])\n\n return {\n goToNextPage,\n goBack,\n goToPage,\n currentPage: router.getCurrentPage(),\n pageHistory: router.getPageHistory(),\n progress: router.getProgress(),\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/hooks/useResponse.ts","../src/hooks/useNavigation.ts"],"names":["useSyncExternalStore","useCallback"],"mappings":"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","file":"chunk-7JLCKTX6.js","sourcesContent":["import { useSyncExternalStore, useCallback, useMemo } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { VariableValue } from '../types'\n\n/**\n * Read/write a single response variable (answers.*).\n *\n * ```tsx\n * const [goal, setGoal] = useResponse<string>('goal')\n * const [interests, setInterests] = useResponse<string[]>('interests')\n * ```\n */\nexport function useResponse<T extends VariableValue>(\n key: string,\n): [T, (value: T) => void] {\n const { variableStore } = useFunnelContext()\n const prefixedKey = `answers.${key}`\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb, { keys: [prefixedKey] }),\n [variableStore, prefixedKey],\n )\n const getSnapshot = useCallback(\n () => variableStore.get(prefixedKey) as T,\n [variableStore, prefixedKey],\n )\n\n const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n const setValue = useCallback(\n (v: T) => variableStore.set(prefixedKey, v),\n [variableStore, prefixedKey],\n )\n\n return [value, setValue]\n}\n\n/**\n * Read all response variables as a flat object (without the `answers.` prefix).\n *\n * Only re-renders when an `answers.*` variable changes.\n *\n * ```tsx\n * const responses = useResponses()\n * // { goal: 'weight_loss', interests: ['yoga', 'running'] }\n * ```\n */\nexport function useResponses(): Record<string, VariableValue> {\n const { variableStore } = useFunnelContext()\n\n const subscribe = useCallback(\n (cb: () => void) => variableStore.subscribe(cb, { prefix: 'answers.' }),\n [variableStore],\n )\n const getSnapshot = useCallback(\n () => variableStore.getState(),\n [variableStore],\n )\n const variables = useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n\n return useMemo(() => {\n const result: Record<string, VariableValue> = {}\n for (const [key, value] of Object.entries(variables)) {\n if (key.startsWith('answers.')) {\n result[key.slice(8)] = value\n }\n }\n return result\n }, [variables])\n}\n","import { useCallback, useSyncExternalStore } from 'react'\nimport { useFunnelContext } from '../components/FunnelProvider'\nimport type { NavigationState } from '../types'\n\n/**\n * Navigation hook — evaluates routes, navigates between pages, tracks progress.\n *\n * Only re-renders when the router's current page changes (not on variable changes).\n * Variables are read lazily at navigation time — callbacks are referentially stable.\n */\nexport function useNavigation(): NavigationState {\n const { router, variableStore, tracker } = useFunnelContext()\n\n // Re-render only when the router's current page changes\n useSyncExternalStore(\n useCallback((cb: () => void) => router.subscribe(cb), [router]),\n useCallback(() => router.getSnapshot(), [router]),\n useCallback(() => router.getSnapshot(), [router]),\n )\n\n /** Called after the router has already navigated to `key`. */\n const afterNavigate = useCallback((key: string) => {\n const page = router.getCurrentPage()\n if (page) {\n tracker.track('page.view', {\n pageId: page.key,\n pageKey: page.key,\n pageName: page.name,\n })\n tracker.startPageTracking(page.key)\n }\n variableStore.setMany({\n 'page.currentId': key,\n 'page.currentIndex': router.getPageHistory().length,\n 'page.current': router.getPageHistory().length + 1,\n 'page.startedAt': Date.now(),\n })\n }, [router, tracker, variableStore])\n\n const goToNextPage = useCallback(() => {\n const previousPage = router.getCurrentPage()\n if (previousPage) {\n tracker.stopPageTracking()\n }\n\n // Read variables at call time — not captured in closure\n const variables = variableStore.getState()\n const nextKey = router.goToNextPage(variables)\n if (nextKey) {\n afterNavigate(nextKey)\n }\n }, [router, tracker, variableStore, afterNavigate])\n\n const goBack = useCallback(() => {\n tracker.stopPageTracking()\n const prevKey = router.goBack()\n if (prevKey) {\n afterNavigate(prevKey)\n }\n }, [router, tracker, afterNavigate])\n\n const goToPage = useCallback((pageKey: string) => {\n tracker.stopPageTracking()\n const key = router.goToPage(pageKey)\n if (key) {\n afterNavigate(key)\n }\n }, [router, tracker, afterNavigate])\n\n return {\n goToNextPage,\n goBack,\n goToPage,\n currentPage: router.getCurrentPage(),\n pageHistory: router.getPageHistory(),\n progress: router.getProgress(),\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useRef, useMemo, useCallback, useEffect } from 'react';
1
+ import { createContext, useContext, useRef, useState, useEffect, useMemo, useCallback } from 'react';
2
2
  import { Toaster } from 'sonner';
3
3
  import { jsxs, jsx } from 'react/jsx-runtime';
4
4
 
@@ -376,7 +376,8 @@ var Router = class {
376
376
  this.initialKey = config.pages?.[initialPage] ? initialPage : defaultInitial;
377
377
  } else {
378
378
  const hasSession = this.hasSessionCookie(campaignSlug);
379
- this.initialKey = hasSession && config.pages?.[initialPage] ? initialPage : defaultInitial;
379
+ const hasPendingSession = typeof window !== "undefined" && (window.location.search.includes("customer=") || window.location.search.includes("sid="));
380
+ this.initialKey = (hasSession || hasPendingSession) && config.pages?.[initialPage] ? initialPage : defaultInitial;
380
381
  }
381
382
  } else {
382
383
  this.initialKey = initialPage || defaultInitial;
@@ -1176,6 +1177,121 @@ var I18n = class {
1176
1177
  this.listeners.forEach((l) => l());
1177
1178
  }
1178
1179
  };
1180
+
1181
+ // src/runtime/session.ts
1182
+ var API_BASE_URL2 = "https://api.appfunnel.net";
1183
+ var API_HEADERS = { "ngrok-skip-browser-warning": "1" };
1184
+ async function apiFetch(path) {
1185
+ try {
1186
+ const res = await fetch(`${API_BASE_URL2}${path}`, { headers: API_HEADERS });
1187
+ return res.ok ? res.json() : null;
1188
+ } catch {
1189
+ return null;
1190
+ }
1191
+ }
1192
+ function mergeVariables(store, data) {
1193
+ if (Object.keys(data).length === 0) return;
1194
+ store.setState((prev) => {
1195
+ const merged = { ...prev };
1196
+ for (const [key, value] of Object.entries(data)) {
1197
+ if (value !== void 0) merged[key] = value;
1198
+ }
1199
+ return merged;
1200
+ });
1201
+ }
1202
+ function cleanUrlParams(...keys) {
1203
+ const url = new URL(window.location.href);
1204
+ for (const key of keys) url.searchParams.delete(key);
1205
+ window.history.replaceState({}, "", url.toString());
1206
+ }
1207
+ async function fetchAndRestoreSession(store, sessionId, funnelId) {
1208
+ const result = await apiFetch(`/session/${sessionId}/data`);
1209
+ if (!result?.success) return;
1210
+ if (result.data?.funnelId && result.data.funnelId !== funnelId) return;
1211
+ const savedData = result.data?.data || {};
1212
+ mergeVariables(store, savedData);
1213
+ }
1214
+ async function resolveCheckoutSuccess(ctx, params) {
1215
+ const stripeSessionId = params.get("session_id");
1216
+ cleanUrlParams("checkout", "session_id");
1217
+ const sessionId = ctx.tracker.getSessionId();
1218
+ if (!sessionId) return { ok: false };
1219
+ ctx.store.setMany({
1220
+ "purchase.status": "success",
1221
+ "purchase.success": true,
1222
+ "purchase.cancelled": false
1223
+ });
1224
+ await Promise.all([
1225
+ apiFetch(
1226
+ `/campaign/${ctx.campaignId}/stripe/checkout-status?sessionId=${encodeURIComponent(sessionId)}&checkoutSessionId=${encodeURIComponent(stripeSessionId)}`
1227
+ ).then((result) => {
1228
+ if (!result?.success) return;
1229
+ const updates = {
1230
+ "payment.status": result.paymentStatus || "paid"
1231
+ };
1232
+ if (result.stripeCustomerId) {
1233
+ updates["user.stripeCustomerId"] = result.stripeCustomerId;
1234
+ }
1235
+ if (result.subscriptionId) {
1236
+ updates["stripe.subscriptionId"] = result.subscriptionId;
1237
+ updates["subscription.status"] = result.subscriptionStatus || "active";
1238
+ }
1239
+ if (result.paymentIntentId) {
1240
+ updates["stripe.paymentIntentId"] = result.paymentIntentId;
1241
+ }
1242
+ ctx.store.setMany(updates);
1243
+ ctx.tracker.track("purchase.complete", {
1244
+ eventId: stripeSessionId,
1245
+ amount: result.amountTotal ? result.amountTotal / 100 : 0,
1246
+ currency: result.currency || "usd",
1247
+ email: result.customerEmail
1248
+ });
1249
+ }),
1250
+ fetchAndRestoreSession(ctx.store, sessionId, ctx.funnelId)
1251
+ ]);
1252
+ return { ok: true };
1253
+ }
1254
+ function resolveCheckoutCanceled(ctx) {
1255
+ cleanUrlParams("checkout", "session_id");
1256
+ ctx.store.setMany({
1257
+ "purchase.status": "cancelled",
1258
+ "purchase.success": false,
1259
+ "purchase.cancelled": true
1260
+ });
1261
+ return { ok: true };
1262
+ }
1263
+ async function resolveCustomer(ctx, customerId) {
1264
+ cleanUrlParams("customer");
1265
+ const result = await apiFetch(
1266
+ `/session/by-customer?customerId=${encodeURIComponent(customerId)}&campaignId=${encodeURIComponent(ctx.campaignId)}&funnelId=${encodeURIComponent(ctx.funnelId)}`
1267
+ );
1268
+ if (!result?.success || !result.sessionId) return { ok: false };
1269
+ ctx.tracker.setSessionId(result.sessionId);
1270
+ if (result.data) {
1271
+ mergeVariables(ctx.store, result.data);
1272
+ }
1273
+ return { ok: true };
1274
+ }
1275
+ async function resolveExistingSession(ctx) {
1276
+ const sessionId = ctx.tracker.getSessionId();
1277
+ if (!sessionId) return { ok: true };
1278
+ await fetchAndRestoreSession(ctx.store, sessionId, ctx.funnelId);
1279
+ return { ok: true };
1280
+ }
1281
+ async function resolveSession(ctx, params) {
1282
+ const checkoutStatus = params.get("checkout");
1283
+ const customerId = params.get("customer");
1284
+ if (checkoutStatus === "success" && params.get("session_id")) {
1285
+ return resolveCheckoutSuccess(ctx, params);
1286
+ }
1287
+ if (checkoutStatus === "canceled") {
1288
+ return resolveCheckoutCanceled(ctx);
1289
+ }
1290
+ if (customerId) {
1291
+ return resolveCustomer(ctx, customerId);
1292
+ }
1293
+ return resolveExistingSession(ctx);
1294
+ }
1179
1295
  var FunnelContext = createContext(null);
1180
1296
  function useFunnelContext() {
1181
1297
  const ctx = useContext(FunnelContext);
@@ -1196,6 +1312,23 @@ function FunnelProvider({
1196
1312
  }) {
1197
1313
  const campaignId = sessionData?.campaignId || config.projectId || "";
1198
1314
  const funnelId = sessionData?.funnelId || config.projectId || "";
1315
+ const disableLoadingScreen = config.settings?.disableLoadingScreen === true;
1316
+ const initialUrlParams = useRef(null);
1317
+ if (!initialUrlParams.current && typeof window !== "undefined") {
1318
+ initialUrlParams.current = new URLSearchParams(window.location.search);
1319
+ }
1320
+ const [isReady, setIsReady] = useState(() => {
1321
+ if (disableLoadingScreen) return true;
1322
+ if (sessionData?.variables) return true;
1323
+ if (globalThis.__APPFUNNEL_DEV__) return true;
1324
+ if (typeof window === "undefined") return false;
1325
+ const params = initialUrlParams.current;
1326
+ if (!params.has("checkout") && !params.has("customer") && !params.has("sid")) {
1327
+ const hasCookie = document.cookie.includes("fs_");
1328
+ if (!hasCookie) return true;
1329
+ }
1330
+ return false;
1331
+ });
1199
1332
  const storeRef = useRef(null);
1200
1333
  const routerRef = useRef(null);
1201
1334
  const trackerRef = useRef(null);
@@ -1208,12 +1341,7 @@ function FunnelProvider({
1208
1341
  );
1209
1342
  }
1210
1343
  if (!routerRef.current) {
1211
- routerRef.current = new Router({
1212
- config,
1213
- initialPage,
1214
- basePath,
1215
- campaignSlug
1216
- });
1344
+ routerRef.current = new Router({ config, initialPage, basePath, campaignSlug });
1217
1345
  }
1218
1346
  if (!trackerRef.current) {
1219
1347
  trackerRef.current = new FunnelTracker();
@@ -1233,29 +1361,21 @@ function FunnelProvider({
1233
1361
  const router = routerRef.current;
1234
1362
  const tracker = trackerRef.current;
1235
1363
  const i18n = i18nRef.current;
1236
- const products = useMemo(() => {
1237
- if (!config.products?.items || !priceData) return [];
1238
- return buildRuntimeProducts(config.products.items, priceData);
1239
- }, [config.products, priceData]);
1240
- const defaultProductId = config.products?.defaultId || products[0]?.id || null;
1241
- const selectedProductIdRef = useRef(defaultProductId);
1242
- const selectProduct = useCallback((productId) => {
1243
- selectedProductIdRef.current = productId;
1244
- store.set("products.selectedProductId", productId);
1245
- }, [store]);
1246
1364
  useEffect(() => {
1247
- const eventBus = new AppFunnelEventBus(store, router, selectProduct);
1248
- eventBus.attach();
1249
- eventBusRef.current = eventBus;
1250
- if (config.integrations && Object.keys(config.integrations).length > 0) {
1251
- initializeIntegrations(config.integrations);
1252
- }
1253
- return () => {
1254
- eventBus.destroy();
1255
- eventBusRef.current = null;
1256
- };
1365
+ if (sessionData?.variables) return;
1366
+ if (globalThis.__APPFUNNEL_DEV__) return;
1367
+ if (typeof window === "undefined") return;
1368
+ tracker.init(campaignId, funnelId, campaignSlug, sessionData?.experimentId);
1369
+ const params = initialUrlParams.current || new URLSearchParams(window.location.search);
1370
+ resolveSession({ store, tracker, campaignId, funnelId }, params).then((result) => {
1371
+ if (!result.ok) {
1372
+ const initialKey = config.initialPageKey || Object.keys(config.pages ?? {})[0];
1373
+ if (initialKey) router.goToPage(initialKey);
1374
+ }
1375
+ }).finally(() => setIsReady(true));
1257
1376
  }, []);
1258
1377
  useEffect(() => {
1378
+ if (!isReady) return;
1259
1379
  tracker.init(campaignId, funnelId, campaignSlug, sessionData?.experimentId);
1260
1380
  if (sessionData?.sessionId) {
1261
1381
  tracker.setSessionId(sessionData.sessionId);
@@ -1278,11 +1398,33 @@ function FunnelProvider({
1278
1398
  tracker.stopPageTracking();
1279
1399
  tracker.flushVariables();
1280
1400
  };
1401
+ }, [isReady]);
1402
+ const products = useMemo(() => {
1403
+ if (!config.products?.items || !priceData) return [];
1404
+ return buildRuntimeProducts(config.products.items, priceData);
1405
+ }, [config.products, priceData]);
1406
+ const defaultProductId = config.products?.defaultId || products[0]?.id || null;
1407
+ const selectedProductIdRef = useRef(defaultProductId);
1408
+ const selectProduct = useCallback((productId) => {
1409
+ selectedProductIdRef.current = productId;
1410
+ store.set("products.selectedProductId", productId);
1411
+ }, [store]);
1412
+ useEffect(() => {
1413
+ const eventBus = new AppFunnelEventBus(store, router, selectProduct);
1414
+ eventBus.attach();
1415
+ eventBusRef.current = eventBus;
1416
+ if (config.integrations && Object.keys(config.integrations).length > 0) {
1417
+ initializeIntegrations(config.integrations);
1418
+ }
1419
+ return () => {
1420
+ eventBus.destroy();
1421
+ eventBusRef.current = null;
1422
+ };
1281
1423
  }, []);
1282
1424
  const sessionStartTime = useRef(Date.now());
1283
1425
  const pageStartTime = useRef(Date.now());
1284
1426
  useEffect(() => {
1285
- const sysVars = computeSystemVariables({
1427
+ store.setMany(computeSystemVariables({
1286
1428
  currentPageKey: router.getCurrentPage()?.key || "",
1287
1429
  pageHistory: router.getPageHistory(),
1288
1430
  pageStartTime: pageStartTime.current,
@@ -1290,8 +1432,7 @@ function FunnelProvider({
1290
1432
  totalPages: Object.keys(config.pages ?? {}).length,
1291
1433
  funnelId,
1292
1434
  campaignId
1293
- });
1294
- store.setMany(sysVars);
1435
+ }));
1295
1436
  if (defaultProductId) {
1296
1437
  store.set("products.selectedProductId", defaultProductId);
1297
1438
  }
@@ -1315,11 +1456,20 @@ function FunnelProvider({
1315
1456
  sessionId: tracker.getSessionId()
1316
1457
  }), [config, store, router, tracker, i18n, products, selectProduct, funnelId, campaignId]);
1317
1458
  return /* @__PURE__ */ jsxs(FunnelContext.Provider, { value: contextValue, children: [
1318
- children,
1459
+ /* @__PURE__ */ jsx(
1460
+ "div",
1461
+ {
1462
+ style: {
1463
+ opacity: isReady ? 1 : 0,
1464
+ transition: "opacity 0.15s ease-in"
1465
+ },
1466
+ children
1467
+ }
1468
+ ),
1319
1469
  /* @__PURE__ */ jsx(Toaster, { position: "top-center" })
1320
1470
  ] });
1321
1471
  }
1322
1472
 
1323
1473
  export { FunnelProvider, __require, registerIntegration, useFunnelContext };
1324
- //# sourceMappingURL=chunk-DAHMOQ63.js.map
1325
- //# sourceMappingURL=chunk-DAHMOQ63.js.map
1474
+ //# sourceMappingURL=chunk-H5C2QJIY.js.map
1475
+ //# sourceMappingURL=chunk-H5C2QJIY.js.map