@pugpigbolt/bridge 0.1.2 → 0.1.3
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/chunks/bootstrap-B7Gwb_jl.mjs +1 -0
- package/dist/chunks/development-CzUmtUQR.mjs +1 -0
- package/dist/{index-BjDhZ_q5.d.mts → chunks/index-B2cNakTH.d.mts} +2 -107
- package/dist/chunks/mockBridgeService-M_48ewQL.mjs +27 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -19
- package/dist/vue.d.mts +8 -45
- package/dist/vue.mjs +1 -213
- package/package.json +1 -1
- package/dist/bootstrap-DQyoNFue.mjs +0 -530
- package/dist/development-Bl8-5E3g.mjs +0 -56
- package/dist/mockBridgeService-vnaAIjCu.mjs +0 -272
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e,t){let{paywall_locked:n,entitlements:r=[]}=e.entry;n&&r.length<=0&&(r=e.feedid?[e.feedid]:[]);let i=e.feedid?t[e.feedid]:!1,a=r.length>0?r.find(e=>t[e]):!0;return!i&&!a}const t={feed:{},rawStories:[],timelines:[],timelinesStates:{},themeURL:[],theme:{},darkTheme:{},timelineMode:`Single`,timelineType:`Timeline`,sourceURL:null,baseUrl:``,metadataLoaded:!1,initialBatchSize:0,filter:{},positionOverrides:[],debugLogs:!1,actionProviderNames:[],authorisationStatus:{},issueAuthorisationStatus:{},read:new Set,saved:new Set,get stories(){return n(this.rawStories,this.saved,this.read,this.authorisationStatus,this.issueAuthorisationStatus)},get themeFileNames(){return this.themeURL?.map(e=>e.split(`/`).pop()??``)??[]},get isSavedTimeline(){return this.timelineType===`SavedTimeline`},get isCollection(){return this.feed?.classes?.includes(`collection_type-edition`)??!1},isTimelineStyleVersion(e){return window.timelineStyleVersion===e}};function n(t,n,a,o,s){let c=!!window.parent?.pugpigBridgeService?.issueAuthorisationStatus;return t.map((t,l)=>(t.locked=c?e(t,s):r(t,o),t.hidden=i(t,o),t.saved=n.has(t.entry.id),t.read=a.has(`${t.feedid}::::${t.entry.id}`),t.originalIndex=l,t))}function r(e,t){let{state:n}=t,{paywall_locked:r=!1}=e.entry;return n!==`active`&&r}function i(e,t){let{state:n}=t,{visibility:r,categories:i,hidden:a}=e.entry,o=i?.find(({scheme:e})=>e===`http://schema.pugpig.com/attributes`);return r?r===`marketing`&&n!==`inactive`||r===`private`&&!!e.locked:o?o.term===`marketing`&&n!==`inactive`||o.term===`private`&&n!==`inactive`:!!a}async function a(e){try{let t=await e;return{data:t?JSON.parse(t):void 0}}catch(e){return{error:e}}}async function o(e,t){let n=window.parent?.pugpigBridgeService,r=n&&n[e],i=t?JSON.stringify(t):void 0;if(r){let{data:t,error:r}=await a(Promise.resolve(i?n[e](i):n[e]()));if(r)throw Error(r instanceof Error?r.message:JSON.stringify(r));return t}window.parent?.postMessage({bolt:`up`,action:e,payload:JSON.parse(i??`{}`)},`*`)}function s(){return(window.location.pathname.split(`/`).pop()?.replace(`.html`,``)??``).split(/[-_]/).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `)}function c(e,t){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>e.apply(this,r),t)}}const l={openArticle(e,t){return o(`viewArticle`,{...e,story:e,index:t})},openEdition(e,t,n=!1,r=!0){let i={editionId:e,skipTimeline:n,autoDownload:r};return t&&(i.partition=t),o(`openEdition`,i)},shouldViewWidget(e,t){return o(`shouldViewWidget`,{...e,story:e,index:t})},setSaved(e,t,n){return o(`setSaved`,{story:e,index:t,saved:n})},setRead(e,t){return o(`setRead`,{story:e,index:t})},shareStory(e,t){return o(`shareStory`,{story:e,index:t})},addToCalendar(e,t){return o(`addToCalendar`,{story:e,index:t})}},u={logInfo(e,t){if(e===`debug`&&!this.debugLogs)return;let n=this.feed?.id?` [${this.feed.id}]`:``;o(`logInfo`,`[${document.title||`Bolt Timeline`}]${n} ${t}`)},sendAnalytics(e,t,n=0,r={}){let i=s(),a=t?.originalBaseURL||t?.baseURL,o=typeof e==`object`&&e?e:{},c={type:e,story:t,index:n,param:t?.feedid,dimensions:r,...o},l=c.paramName||`pugpigEditionID`,d=this.timelineType===`SavedTimeline`?`/SavedTimeline`:`/Timeline`;return c.dimensions.pugpigEventOrigin=i,!c.paramName&&c?.param===c?.story?.entry.title&&(l=`pugpigPageName`),c?.story?.entry.url&&a&&(c.story.entry.url=new URL(c.story.entry.url,a).href),c?.story?.entry.shareurl&&a&&(c.story.entry.shareurl=new URL(c.story.entry.shareurl,a).href),u.sendAnalyticsEvent(c.type,d,c.param,l,c.dimensions,c.story?.entry,c.story?.feedid,c.index)},sendAnalyticsEvent(e,t,n=``,r=``,i={},a,c,l){let u={name:e,category:t,paramName:r,feedid:c,storyEntry:a,index:l,dimensions:i};return n&&n!==``&&(u.param=typeof n==`string`?n:JSON.stringify(n)),u.dimensions={...i,pugpigEventOrigin:s()},o(`trackAnalyticsEvent`,u)}},d={openAudio(e,t,n){return o(`playAudio`,{story:e,index:n,...t})},openImageGallery(e,t=0){return o(`openImageGallery`,{images:e,initialImage:t})}},f={fireToast(e,t){return o(`fireToast`,{type:e,action:t})},clearForwardTouchesWithin(){return o(`clearForwardTouchesWithin`)},forwardTouchesWithin:c(async function(e){return await this.clearForwardTouchesWithin(),o(`forwardTouchesWithin`,e&&Object.values(e))},300)},p={call(e,t){return o(e,t)},timelineIsReady(){let e=import.meta.env.VITE_GIT_VERSION;o(`timelineIsReady`,{version:e}),this.logInfo(`global`,`timelineIsReady took ${performance.now()}ms`)}},m={...l,...u,...d,...f,...p},h={events:{},debounceTimers:{},$on(e,t){return Array.isArray(this.events[e])||(this.events[e]=[]),this.events[e].push(t),()=>this.removeListener(e,t)},removeListener(e,t){if(Array.isArray(this.events[e])){let n=this.events[e].indexOf(t);n>-1&&this.events[e].splice(n,1)}},$off(e,t){this.removeListener(e,t)},$emit(e,...t){let n=t?.[0]?.debounce,r=Object.keys(this.events).filter(t=>RegExp(`^`+t.replace(/\*/g,`.*`)+`$`).test(e));!r||r.length<=0||r.forEach(e=>{n?(this.debounceTimers[e]&&clearTimeout(this.debounceTimers[e]),this.debounceTimers[e]=setTimeout(()=>{this.events[e].forEach(e=>e.apply(this,t))},n)):this.events[e].forEach(e=>e.apply(this,t))})},$once(e,t){let n=this.$on(e,(...e)=>{n(),t.apply(this,e)})},subscribe(e){return e(this),this.$on(`change`,()=>e(this))}},g=Object.assign(t,{...m,resolveIssueAccess:n=>e(n,t.issueAuthorisationStatus)},h);function _(e){return new Proxy(e,{set(t,n,r,i){let a=Reflect.set(t,n,r,i);return typeof n==`string`?(e.$emit(`change:${n}`,r),e.$emit(`change`,n,r),a):a}})}function v(e,t){if(e.length!==t.length)return!0;for(let n=0;n<e.length;n++){let{entry:{id:r,updated:i}}=e[n],{entry:{id:a,updated:o}}=t[n];if(r!==a||i!==o)return!0}return!1}async function y(e,t){let n=window.parent?.pugpigBridgeService,r=t?await Promise.resolve(n?.[e](t)):await Promise.resolve(n?.[e]()),i=JSON.parse(r),a=window.parent?.pugpig?.timelineHooks?.transforms?.bridge;return a&&(i=await a({method:e,payload:i})),i}const b={stories:async function({updateAction:e}={}){let{stories:t}=await y(`stories`),n=this.rawStories,r=v(n,t);this.rawStories=t,r&&(window.pugpigUpdate(`issueAuthorisationStatus`),window.pugpigUpdate(`timelineInfo`)),n.length>0&&this.$emit(`stories-updated`,{feedUpdated:r,updateAction:e})},timelines:async function(){this.timelines=await y(`timelines`,JSON.stringify(this.filter))},timelineInfo:async function(){let{themeURL:e,timelineType:t,debugLogs:n,sourceURL:r,timelineMode:i,metadata:a,feedReference:o}=await y(`timelineInfo`);this.themeURL=e,this.sourceURL=r,this.theme=a?.configuration?.theme??{},this.darkTheme=a?.configuration?.darkTheme??this.theme,this.feed=o,this.timelineType=t,this.timelineMode=i,a&&(this.metadataLoaded=!0),this.initialBatchSize=a?.configuration?.timeline_initial_batch_size??a?.timeline_initial_batch_size??Math.floor(screen.height/150),window.useTimelineGrid&&(this.positionOverrides=window.timelinePositionOverrides??a?.configuration?.position_overrides??a?.position_overrides??[]),this.debugLogs=n},timeline:async function({editionId:e,progress:t,state:n,downloadError:r}){let i=this.timelines.findIndex(t=>t.id===e);!this.timelines||this.timelines.length<=0||!this.timelines[i]||(this.timelinesStates[e]||(this.timelinesStates[e]={}),this.timelinesStates[e].progress=t,this.timelinesStates[e].state=n,this.timelinesStates[e].downloadError=r)},timelinesInfo:async function(){let{baseurl:e,debugLogs:t,filter:n,css:r=[],theme:i={},darkTheme:a}=await y(`timelinesInfo`);this.theme=i,this.darkTheme=a??i,this.themeURL=r,this.baseUrl=e,this.filter=n,this.debugLogs=t},localeInfo:async function(){let{locale:e=`en-GB`,direction:t=`ltr`}=await y(`localeInfo`);document.documentElement.lang!==e&&(document.documentElement.lang=e?.replace(/_/g,`-`)),document.documentElement.dir!==t&&(document.documentElement.dir=t)},issueAuthorisationStatus:async function(){let e=[...new Set(this.rawStories.flatMap(({feedid:e,entry:t})=>[e,...t.entitlements??[]]))];this.issueAuthorisationStatus=await y(`issueAuthorisationStatus`,JSON.stringify(e))},authorisationStatus:async function(){this.authorisationStatus=await y(`authorisationStatus`)},actionProviderNames:async function(){this.actionProviderNames=await y(`actionProviderNames`)},readStories:async function(){let{readStories:e}=await y(`readStories`);this.read=new Set(e.map(e=>e.join(`::::`)))},savedStories:async function(){let{savedStories:e}=await y(`savedStories`);this.saved=new Set(e.map(e=>e?.[1]))},updateTime:async function(){let{dateTime:e,lastCheckedDateTime:t}=await y(`updateTime`);this.$emit(`time-updated`,{dateTime:e,lastCheckedDateTime:t})},storeGet:async function({key:e}){this.$emit(`store-updated`,{key:e})},webviewInfo:async function(){let{themeURL:e}=await y(`webviewInfo`);this.themeURL=e}};function x(e){return typeof e==`function`&&`__boltHandlers`in e}function S(){if(x(window.pugpigUpdate))return window.pugpigUpdate.__boltHandlers;let e=window.pugpigUpdate?[window.pugpigUpdate]:[],t=Object.assign((t,n={})=>e.forEach(e=>e(t,n)),{__boltHandlers:e});return window.pugpigUpdate=t,e}const C=new WeakMap;function w(e){let t=S();C.has(e)||C.set(e,(t,n={})=>{if(window.parent?.pugpigBridgeService?.[t])return document.querySelectorAll(`iframe`).forEach(e=>{try{e.contentWindow?.pugpigUpdate?.(t,n)}catch{}}),b[t]?.call(e,n);console.info(`Bolt Timeline Bridge: '${t}' not available on this platform.`)});let n=C.get(e);t.includes(n)||t.push(n)}const T=[`localeInfo`,`timelineInfo`,`authorisationStatus`,`savedStories`,`readStories`,`updateTime`,`actionProviderNames`,`stories`];function E(e=T){for(let t of e)window.pugpigUpdate(t)}function D(e,t={}){let{rootSelector:n=`#app`,readyTimeout:r=4e3}=t;`scrollRestoration`in history&&(history.scrollRestoration=`manual`),E();let i=document.querySelector(n),a=[],o=setTimeout(()=>{e.logInfo(`debug`,`${r}ms have passed, forcing timelineIsReady`),e.timelineIsReady()},r);function s(t){a.push(t),[`renderedRequiredStyles`,...e.themeFileNames??[]].every(e=>a.includes(e))&&(clearTimeout(o),document.fonts.ready.then(()=>e.timelineIsReady()))}for(let t of e.themeURL??[]){let e=document.createElement(`link`);e.rel=`stylesheet`,e.href=t,e.onload=()=>s(t),e.onerror=()=>s(t),document.head.appendChild(e)}s(`renderedRequiredStyles`);function c(){let t=[...e.feed?.classes??[]];e.isSavedTimeline&&t.push(`saved-timeline`),i&&t.length&&i.classList.add(...t)}c();let l=e.$on(`change:feed`,c);return()=>{clearTimeout(o),l()}}export{_ as a,w as i,D as n,g as o,E as r,m as s,T as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,r as t}from"./mockBridgeService-M_48ewQL.mjs";function n(e){return e===`origin`&&(e=window.location.origin),/^https?:\/\//i.test(e)||(e=`https://`+e),e}async function r(e){let n=`${e.live_domain}/timelines.json`,r=await t(n),i=r.timelines?.find(t=>t.id===e.edition)??r.timelines[0],a=new URL(i?.feed??``,n).href,o=await t(e?.stories||a);return Object.assign(e,{live_domain:e.live_domain,timelines:r.timelines,timeline:i,stories:o.stories,metadata:o.metadata})}async function i(e){let n=e.platform??`web`,r=(await t(`${e.live_domain}/bolt_properties.json`))?.[`${e.config}_version`]??`latest_version`,i=`${e.live_domain}/bolt/config/${r}/web/config.json`,a=(e.config?await t(i):void 0)?.timeline_css.map(t=>`${e.live_domain}/bolt/config/${r}/${n}/${t}`);return Object.assign(e,{themeUrl:a})}async function a(e,t){let a=new URLSearchParams(window.location.search),o=Object.fromEntries(a.entries());if(o.useStorage){let e=localStorage.getItem(`config`);if(e)return JSON.parse(e)}let s={...window.__TIMELINE_LOCAL_CONFIG__,...o,debugLogs:o.debugLogs===`true`};return s.live_domain&&(s.live_domain=n(s.live_domain),s=await r(s),s=await i(s)),localStorage.setItem(`config`,JSON.stringify(s)),s}async function o(t,n){window.config=await a(t,n),window.pugpigBridgeService=e(window.config)}export{o as injectBridge};
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { App } from "vue";
|
|
2
2
|
|
|
3
3
|
//#region src/types.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* @section Story types
|
|
6
|
-
*
|
|
7
|
-
* Core data structures for stories and their entries, shared across the bridge
|
|
8
|
-
* and widget layer.
|
|
9
|
-
*/
|
|
10
4
|
interface StoryImage {
|
|
11
5
|
src?: string;
|
|
12
6
|
srcset?: string;
|
|
@@ -15,7 +9,6 @@ interface StoryImage {
|
|
|
15
9
|
credit?: string;
|
|
16
10
|
externalurl?: string;
|
|
17
11
|
}
|
|
18
|
-
/** A single DFP ad size — either a [width, height] tuple or the string 'fluid'. */
|
|
19
12
|
type AdSize = number[] | string;
|
|
20
13
|
interface StoryEntry {
|
|
21
14
|
id: string;
|
|
@@ -155,62 +148,29 @@ interface Story {
|
|
|
155
148
|
isArticleLink?: boolean;
|
|
156
149
|
original_hidden?: boolean;
|
|
157
150
|
}
|
|
158
|
-
/**
|
|
159
|
-
* @section Bridge service interface
|
|
160
|
-
*
|
|
161
|
-
* The `BridgeService` interface consumed by `@pugpigbolt/components` and widgets to
|
|
162
|
-
* open articles, send analytics, manage saved state, and communicate with the
|
|
163
|
-
* native shell via events.
|
|
164
|
-
*/
|
|
165
151
|
interface BridgeService {
|
|
166
|
-
/** Current timeline type string, e.g. 'Timeline' | 'SavedTimeline'. */
|
|
167
152
|
timelineType: string;
|
|
168
|
-
/** Processed story array — locked, hidden, saved, and read flags applied. */
|
|
169
153
|
stories: Story[];
|
|
170
|
-
/** Unprocessed stories as received from the native shell before flag processing. */
|
|
171
154
|
rawStories: Story[];
|
|
172
|
-
/** Number of stories rendered in the first batch. */
|
|
173
155
|
initialBatchSize: number;
|
|
174
|
-
/** Position override rules applied to story ordering. */
|
|
175
156
|
positionOverrides: unknown[];
|
|
176
|
-
/** Names of registered native action providers, if any. */
|
|
177
157
|
actionProviderNames?: string[];
|
|
178
|
-
/** Current user authorisation status — state ('active'|'inactive'), token, userInfo. */
|
|
179
158
|
authorisationStatus?: AuthorisationStatus;
|
|
180
|
-
/** The source url that loaded the timeline. */
|
|
181
159
|
sourceURL?: string;
|
|
182
|
-
/** Returns true if the native app is running at least the given timeline style version. */
|
|
183
160
|
isTimelineStyleVersion(version: string): boolean;
|
|
184
|
-
/** Sends an analytics event. event is a string action name or a Record with type/param. story and index identify the context. */
|
|
185
161
|
sendAnalytics(event: string | Record<string, unknown>, story?: Story, index?: number, extra?: Record<string, unknown>): void;
|
|
186
|
-
/** Asks the native shell to open a story in the native article reader. */
|
|
187
162
|
openArticle(story: Story, index: number): void;
|
|
188
|
-
/** Marks a story as read in the native shell's read-state store. */
|
|
189
163
|
setRead(story: Story, index: number): void;
|
|
190
|
-
/** Opens the native audio player for a story. metadata carries player-specific config. */
|
|
191
164
|
openAudio(story: Story, metadata: Record<string, unknown>, index: number): void;
|
|
192
|
-
/** Opens the native share sheet for a story. */
|
|
193
165
|
shareStory(story: Story, index: number): void;
|
|
194
|
-
/** Saves or unsaves a story in the native shell's saved-stories store. */
|
|
195
166
|
setSaved(story: Story, index: number, saved: boolean): void;
|
|
196
|
-
/** Displays a native toast notification. key is the toast identifier, action is an optional CTA. */
|
|
197
167
|
fireToast(key: string, action?: string): void;
|
|
198
|
-
/** Returns whether the story is locked based on issue authorisation status. */
|
|
199
168
|
resolveIssueAccess(story: Pick<Story, 'feedid' | 'entry'>): boolean;
|
|
200
|
-
/** Adds an event-type story to the device calendar. */
|
|
201
169
|
addToCalendar(story: Story, index: number): void;
|
|
202
|
-
/** Dispatches an arbitrary named action to the native bridge. Use as an escape hatch when no typed method exists. */
|
|
203
170
|
call(method: string, ...args: unknown[]): Promise<unknown>;
|
|
204
|
-
/** Subscribes to a bridge event by name. Returns an unsubscribe function — call it in onUnmounted. */
|
|
205
171
|
$on(event: string, callback: (...args: unknown[]) => void): () => void;
|
|
206
|
-
/** Emits a named bridge event with an optional data payload. */
|
|
207
172
|
$emit(event: string, data?: unknown): void;
|
|
208
173
|
}
|
|
209
|
-
/**
|
|
210
|
-
* @section Timeline types
|
|
211
|
-
*
|
|
212
|
-
* Types describing timelines and their download or progress state.
|
|
213
|
-
*/
|
|
214
174
|
interface Timeline {
|
|
215
175
|
id: string;
|
|
216
176
|
feed?: string;
|
|
@@ -221,12 +181,6 @@ interface TimelineState {
|
|
|
221
181
|
state?: 'idle' | 'downloading' | 'deleting' | (string & {});
|
|
222
182
|
downloadError?: string;
|
|
223
183
|
}
|
|
224
|
-
/**
|
|
225
|
-
* @section Feed, auth, and theme
|
|
226
|
-
*
|
|
227
|
-
* Feed descriptor, authorisation status, issue-level access map, and theme
|
|
228
|
-
* types used across the bridge.
|
|
229
|
-
*/
|
|
230
184
|
interface Feed {
|
|
231
185
|
id?: string;
|
|
232
186
|
classes?: string[];
|
|
@@ -242,12 +196,6 @@ interface AuthorisationStatus {
|
|
|
242
196
|
}
|
|
243
197
|
type IssueAuthorisationStatus = Record<string, boolean>;
|
|
244
198
|
type Theme = Record<string, unknown>;
|
|
245
|
-
/**
|
|
246
|
-
* @section Remote config
|
|
247
|
-
*
|
|
248
|
-
* Timeline metadata and the full remote configuration shape delivered by the
|
|
249
|
-
* native shell at startup.
|
|
250
|
-
*/
|
|
251
199
|
interface TimelineMetadata {
|
|
252
200
|
configuration?: {
|
|
253
201
|
theme?: Theme;
|
|
@@ -277,13 +225,6 @@ interface RemoteConfig {
|
|
|
277
225
|
baseurl?: string;
|
|
278
226
|
[key: string]: unknown;
|
|
279
227
|
}
|
|
280
|
-
/**
|
|
281
|
-
* @section Native bridge service interface
|
|
282
|
-
*
|
|
283
|
-
* The raw `parent.pugpigBridgeService` interface exposed by the native iOS and
|
|
284
|
-
* Android shell. Widget code should not call this directly — use `BridgeService`
|
|
285
|
-
* instead.
|
|
286
|
-
*/
|
|
287
228
|
interface PugpigBridgeService {
|
|
288
229
|
stories(payload?: string): unknown;
|
|
289
230
|
timeline(payload?: string): unknown;
|
|
@@ -317,12 +258,6 @@ interface PugpigBridgeService {
|
|
|
317
258
|
actionProviderNames?(payload?: string): unknown;
|
|
318
259
|
[key: string]: ((payload?: string) => unknown) | undefined;
|
|
319
260
|
}
|
|
320
|
-
/**
|
|
321
|
-
* @section Incoming handler payload types
|
|
322
|
-
*
|
|
323
|
-
* Payload shapes for each `pugpigUpdate` method call received from the native
|
|
324
|
-
* shell.
|
|
325
|
-
*/
|
|
326
261
|
interface StoriesPayload {
|
|
327
262
|
stories: Story[];
|
|
328
263
|
}
|
|
@@ -366,37 +301,11 @@ interface TimelineInfoPayload {
|
|
|
366
301
|
feedReference: Feed;
|
|
367
302
|
metadata: TimelineMetadata;
|
|
368
303
|
}
|
|
369
|
-
/**
|
|
370
|
-
* @section Bootstrap
|
|
371
|
-
*
|
|
372
|
-
* Options passed to the bridge bootstrap process that initialises the Vue app
|
|
373
|
-
* and connects it to the native shell.
|
|
374
|
-
*/
|
|
375
304
|
interface BootstrapOptions {
|
|
376
|
-
/**
|
|
377
|
-
* CSS selector for the app root element used to apply feed classes.
|
|
378
|
-
* Defaults to `'#app'`.
|
|
379
|
-
*/
|
|
380
305
|
rootSelector?: string;
|
|
381
|
-
/**
|
|
382
|
-
* Milliseconds to wait for theme CSS and fonts before forcing `timelineIsReady`.
|
|
383
|
-
* Defaults to `4000`.
|
|
384
|
-
*/
|
|
385
306
|
readyTimeout?: number;
|
|
386
307
|
}
|
|
387
|
-
/**
|
|
388
|
-
* @section Plugin type
|
|
389
|
-
*
|
|
390
|
-
* Type alias for the Vue plugin produced by the bridge factory. Pass an
|
|
391
|
-
* instance to `app.use()` to install the bridge into a Vue application.
|
|
392
|
-
*/
|
|
393
308
|
type BoltBridgePlugin = (app: App, callback?: () => void) => void;
|
|
394
|
-
/**
|
|
395
|
-
* @section Analytics
|
|
396
|
-
*
|
|
397
|
-
* Context and dimension types passed when firing analytics events through the
|
|
398
|
-
* bridge.
|
|
399
|
-
*/
|
|
400
309
|
interface AnalyticsContext {
|
|
401
310
|
debugLogs: boolean;
|
|
402
311
|
feed?: {
|
|
@@ -408,12 +317,6 @@ interface AnalyticsDimensions {
|
|
|
408
317
|
pugpigEventOrigin?: string;
|
|
409
318
|
[key: string]: unknown;
|
|
410
319
|
}
|
|
411
|
-
/**
|
|
412
|
-
* @section Global window augmentation
|
|
413
|
-
*
|
|
414
|
-
* Extensions added to the browser `window` object by the native shell,
|
|
415
|
-
* including the `pugpigUpdate` entry point and timeline configuration globals.
|
|
416
|
-
*/
|
|
417
320
|
declare global {
|
|
418
321
|
interface Window {
|
|
419
322
|
boltBridge?: unknown;
|
|
@@ -549,8 +452,8 @@ declare function createPugpigBridgeService(config: BridgeServiceConfig): {
|
|
|
549
452
|
ok: boolean;
|
|
550
453
|
};
|
|
551
454
|
css: string[] | undefined;
|
|
552
|
-
theme:
|
|
553
|
-
darkTheme:
|
|
455
|
+
theme: Record<string, unknown> | undefined;
|
|
456
|
+
darkTheme: Record<string, unknown> | undefined;
|
|
554
457
|
debugLogs: boolean | undefined;
|
|
555
458
|
};
|
|
556
459
|
storeGet(payload?: string): string | null;
|
|
@@ -587,15 +490,7 @@ declare const BOOTSTRAP_METHODS: readonly ["localeInfo", "timelineInfo", "author
|
|
|
587
490
|
declare function triggerPugpigUpdateSequence(methods?: readonly string[]): void;
|
|
588
491
|
//#endregion
|
|
589
492
|
//#region src/index.d.ts
|
|
590
|
-
/**
|
|
591
|
-
* @signature globalBridge: GlobalBridge
|
|
592
|
-
* @description Singleton proxy bridge instance exposed as window.boltBridge. Emits change:prop events on every property write. Use this for non-Vue integrations; Vue apps should use useBridge() instead.
|
|
593
|
-
*/
|
|
594
493
|
declare const globalBridge: GlobalBridge;
|
|
595
|
-
/**
|
|
596
|
-
* @signature bootstrap(options?: BootstrapOptions): () => void
|
|
597
|
-
* @description Initialises the bridge for a non-Vue framework entry point. Call once before rendering. Returns a teardown function that removes all listeners and cleans up state.
|
|
598
|
-
*/
|
|
599
494
|
declare function bootstrap(options?: BootstrapOptions): () => void;
|
|
600
495
|
//#endregion
|
|
601
496
|
export { TimelineState as A, StoryEntry as C, TimelineArgs as D, Timeline as E, UpdateTimePayload as M, WebviewInfoPayload as N, TimelineInfoPayload as O, Story as S, Theme as T, PugpigBridgeService as _, createPugpigBridgeService as a, SavedStoriesPayload as b, AnalyticsContext as c, BoltBridgePlugin as d, BootstrapOptions as f, LocaleInfoPayload as g, IssueAuthorisationStatus as h, triggerPugpigUpdateSequence as i, TimelinesInfoPayload as j, TimelineMetadata as k, AnalyticsDimensions as l, Feed as m, globalBridge as n, GlobalBridge as o, BridgeService as p, BOOTSTRAP_METHODS as r, AdSize as s, bootstrap as t, AuthorisationStatus as u, ReadStoriesPayload as v, StoryImage as w, StoriesPayload as x, RemoteConfig as y };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
async function e(e,t){let n=await(await fetch(e)).json();return t?n?.[t]:n}function t(e){let t=0,n=`idle`;window[e]&&clearInterval(window[e]),window[e]=setInterval(()=>{let r=t<=0,i=t>=1;n=r||i?`idle`:`downloading`,i&&clearInterval(window[e]),window.pugpigUpdate(`timeline`,{editionId:e,state:n,progress:t}),t+=.05},500)}let n=null;function r(){return n||(n=document.createElement(`div`),n.id=`bridge-toast-container`,n.style.cssText=`
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 10px;
|
|
4
|
+
right: 10px;
|
|
5
|
+
z-index: 99999;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
gap: 8px;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
`,document.body.appendChild(n),n)}function i(e,t=3e3){let n=r(),i=document.createElement(`div`);i.style.cssText=`
|
|
11
|
+
background: #333;
|
|
12
|
+
color: #fff;
|
|
13
|
+
padding: 8px 12px;
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
font-size: 12px;
|
|
16
|
+
font-family: monospace;
|
|
17
|
+
max-width: 300px;
|
|
18
|
+
word-break: break-word;
|
|
19
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
20
|
+
animation: slideIn 0.3s ease;
|
|
21
|
+
pointer-events: auto;
|
|
22
|
+
`,i.textContent=e;let a=document.createElement(`style`);a.textContent=`
|
|
23
|
+
@keyframes slideIn {
|
|
24
|
+
from { transform: translateX(100%); opacity: 0; }
|
|
25
|
+
to { transform: translateX(0); opacity: 1; }
|
|
26
|
+
}
|
|
27
|
+
`,document.querySelector(`#bridge-toast-styles`)||(a.id=`bridge-toast-styles`,document.head.appendChild(a)),n.appendChild(i),setTimeout(()=>{i.style.opacity=`0`,i.style.transition=`opacity 0.3s ease`,setTimeout(()=>i.remove(),300)},t)}function a(e){return{stories(){return window.stories=window.stories||o(e,e.stories),{stories:window.stories}},timeline(){return{progress:0,state:`idle`}},timelines(){return window.timelines=window.timelines||e.timelines,window.timelines},logInfo(e){return console.info(JSON.parse(e??`null`))},timelineInfo(){let{themeUrl:t,timelineType:n,metadata:r,debugLogs:i}=window.config??e,a=(window.config??e).timeline;return{themeURL:t,timelineType:n,debugLogs:i,metadata:r,sourceURL:window.sourceURL||window.location.href,feedReference:a}},forwardTouchesWithin(e){JSON.parse(e??`[]`).forEach(e=>{let t=document.createElement(`div`);t.className=`forwardTouchesWithin`,t.style.position=`absolute`,t.style.width=e.w+`px`,t.style.height=e.h+`px`,t.style.top=e.y+`px`,t.style.left=e.x+`px`,t.style.outline=`3px solid red`,t.style.pointerEvents=`none`,document.body.appendChild(t)})},clearForwardTouchesWithin(){document.querySelectorAll(`.forwardTouchesWithin`).forEach(e=>e.remove())},issueAuthorisationStatus(e){return JSON.parse(e??`[]`).reduce((e,t)=>(e[t]=!0,e),{})},shouldViewWidget(e){return!0},viewArticle(){console.log(`eheheh`)},startEditionDownload(e){let{editionId:n}=JSON.parse(e??`{}`);t(n)},deleteEdition(e){let{editionId:t}=JSON.parse(e??`{}`);window.pugpigUpdate(`timeline`,{editionId:t,state:`deleting`}),setTimeout(()=>window.pugpigUpdate(`timeline`,{editionId:t,state:`idle`,progress:0}),1e3)},cancelEditionDownload(e){let{editionId:t}=JSON.parse(e??`{}`);window[t]&&clearInterval(window[t]),window.pugpigUpdate(`timeline`,{editionId:t,state:`idle`,progress:0})},timelinesInfo(){let{theme:t,darkTheme:n,css:r,debugLogs:i,live_domain:a}=window.config??e;return{baseurl:a,filter:{ok:!0},css:r,theme:t,darkTheme:n,debugLogs:i}},storeGet(e){let t=JSON.parse(e??`null`);return localStorage.getItem(t)},storeSet(e){let{key:t,value:n}=JSON.parse(e??`{}`),r=localStorage.setItem(t,n);return setTimeout(()=>window.pugpigUpdate(`storeGet`,{key:t}),200),r},localeInfo(){let{globalDir:t}=window.config??e;return{locale:`en_GB`,direction:t}},trackAnalyticsEvent(e){return JSON.parse(e??`null`)},updateTime(){return{dateTime:Date.now(),lastCheckedDateTime:Date.now()}},authorisationStatus(e){return{state:`active`,userInfo:{}}},savedStories(){return{savedStories:window.saved||[]}},readStories(){return{readStories:window.read||[]}},localizableString(e){let{stringId:t,params:n}=JSON.parse(e??`{}`);return n?.length?`${t}(${n.join(`, `)})`:t},localizableRelativeTimeString(e){let{datetime:t}=JSON.parse(e??`{}`);return t?new Date(t).toLocaleDateString():null},localizableDateTimeString(e){let{datetime:t}=JSON.parse(e??`{}`);return t?new Date(t).toLocaleString():null},localizableQuantityString(e){let{stringId:t,quantity:n}=JSON.parse(e??`{}`);return`${t}(${n})`},setSaved(e){let{story:t,saved:n}=JSON.parse(e??`{}`);window.saved=window.saved||[];let r=window.saved.findIndex(([e,n])=>e===t.feedid&&n===t.entry.id);!n&&r>-1&&window.saved.splice(r,1),n&&window.saved.push([t.feedid,t.entry.id]),window.pugpigUpdate(`savedStories`)},setRead(e){let{story:t}=JSON.parse(e??`{}`);return window.read=window.read||[],window.read.push([t.feedid,t.entry.id]),window.pugpigUpdate(`readStories`),JSON.parse(e??`null`)}}}function o(e,t){return t.map(t=>({feedid:e?.timeline?.id||`Bolt Timeline`,entry:t,saved:!1,locked:!0,baseURL:e.live_domain}))}function s(e){let t=a(e);return new Proxy(t,{get(t,n){let r=t[n];return typeof r==`function`?(...t)=>{let a=r(t[0])??null;return e.debugLogs&&a&&(i(`${n} ${JSON.stringify(t)}`),console.log(`%c[Pugpig Bridge Service]%c[${n}]`,`color: green;`,`color: orange;`,n,r(t[0]))),a?JSON.stringify(a):void 0}:t[n]}})}export{s as n,e as r,a as t};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as TimelineState, C as StoryEntry, D as TimelineArgs, E as Timeline, M as UpdateTimePayload, N as WebviewInfoPayload, O as TimelineInfoPayload, S as Story, T as Theme, _ as PugpigBridgeService, a as createPugpigBridgeService, b as SavedStoriesPayload, c as AnalyticsContext, d as BoltBridgePlugin, f as BootstrapOptions, g as LocaleInfoPayload, h as IssueAuthorisationStatus, i as triggerPugpigUpdateSequence, j as TimelinesInfoPayload, k as TimelineMetadata, l as AnalyticsDimensions, m as Feed, n as globalBridge, o as GlobalBridge, p as BridgeService, r as BOOTSTRAP_METHODS, s as AdSize, t as bootstrap, u as AuthorisationStatus, v as ReadStoriesPayload, w as StoryImage, x as StoriesPayload, y as RemoteConfig } from "./index-
|
|
1
|
+
import { A as TimelineState, C as StoryEntry, D as TimelineArgs, E as Timeline, M as UpdateTimePayload, N as WebviewInfoPayload, O as TimelineInfoPayload, S as Story, T as Theme, _ as PugpigBridgeService, a as createPugpigBridgeService, b as SavedStoriesPayload, c as AnalyticsContext, d as BoltBridgePlugin, f as BootstrapOptions, g as LocaleInfoPayload, h as IssueAuthorisationStatus, i as triggerPugpigUpdateSequence, j as TimelinesInfoPayload, k as TimelineMetadata, l as AnalyticsDimensions, m as Feed, n as globalBridge, o as GlobalBridge, p as BridgeService, r as BOOTSTRAP_METHODS, s as AdSize, t as bootstrap, u as AuthorisationStatus, v as ReadStoriesPayload, w as StoryImage, x as StoriesPayload, y as RemoteConfig } from "./chunks/index-B2cNakTH.mjs";
|
|
2
2
|
export { AdSize, AnalyticsContext, AnalyticsDimensions, AuthorisationStatus, BOOTSTRAP_METHODS, BoltBridgePlugin, BootstrapOptions, BridgeService, Feed, GlobalBridge, IssueAuthorisationStatus, LocaleInfoPayload, PugpigBridgeService, ReadStoriesPayload, RemoteConfig, SavedStoriesPayload, StoriesPayload, Story, StoryEntry, StoryImage, Theme, Timeline, TimelineArgs, TimelineInfoPayload, TimelineMetadata, TimelineState, TimelinesInfoPayload, UpdateTimePayload, WebviewInfoPayload, bootstrap, createPugpigBridgeService, globalBridge, triggerPugpigUpdateSequence };
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { t as createPugpigBridgeService } from "./mockBridgeService-vnaAIjCu.mjs";
|
|
3
|
-
//#region src/index.ts
|
|
4
|
-
/**
|
|
5
|
-
* @signature globalBridge: GlobalBridge
|
|
6
|
-
* @description Singleton proxy bridge instance exposed as window.boltBridge. Emits change:prop events on every property write. Use this for non-Vue integrations; Vue apps should use useBridge() instead.
|
|
7
|
-
*/
|
|
8
|
-
const globalBridge = window.boltBridge || makeProxyBridge(rawBridge);
|
|
9
|
-
window.boltBridge = globalBridge;
|
|
10
|
-
setupPugpigUpdate(globalBridge);
|
|
11
|
-
/**
|
|
12
|
-
* @signature bootstrap(options?: BootstrapOptions): () => void
|
|
13
|
-
* @description Initialises the bridge for a non-Vue framework entry point. Call once before rendering. Returns a teardown function that removes all listeners and cleans up state.
|
|
14
|
-
*/
|
|
15
|
-
function bootstrap(options) {
|
|
16
|
-
return bootstrap$1(globalBridge, options);
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
|
-
export { BOOTSTRAP_METHODS, bootstrap, createPugpigBridgeService, globalBridge, triggerPugpigUpdateSequence };
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,t as a}from"./chunks/bootstrap-B7Gwb_jl.mjs";import{t as o}from"./chunks/mockBridgeService-M_48ewQL.mjs";const s=window.boltBridge||e(r);window.boltBridge=s,t(s);function c(e){return n(s,e)}export{a as BOOTSTRAP_METHODS,c as bootstrap,o as createPugpigBridgeService,s as globalBridge,i as triggerPugpigUpdateSequence};
|
package/dist/vue.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as TimelineState, C as StoryEntry, D as TimelineArgs, E as Timeline, M as UpdateTimePayload, N as WebviewInfoPayload, O as TimelineInfoPayload, S as Story, T as Theme, _ as PugpigBridgeService, b as SavedStoriesPayload, c as AnalyticsContext, d as BoltBridgePlugin, f as BootstrapOptions, g as LocaleInfoPayload, h as IssueAuthorisationStatus, i as triggerPugpigUpdateSequence, j as TimelinesInfoPayload, k as TimelineMetadata, l as AnalyticsDimensions, m as Feed, o as GlobalBridge, p as BridgeService, r as BOOTSTRAP_METHODS, s as AdSize, u as AuthorisationStatus, v as ReadStoriesPayload, w as StoryImage, x as StoriesPayload, y as RemoteConfig } from "./index-
|
|
1
|
+
import { A as TimelineState, C as StoryEntry, D as TimelineArgs, E as Timeline, M as UpdateTimePayload, N as WebviewInfoPayload, O as TimelineInfoPayload, S as Story, T as Theme, _ as PugpigBridgeService, b as SavedStoriesPayload, c as AnalyticsContext, d as BoltBridgePlugin, f as BootstrapOptions, g as LocaleInfoPayload, h as IssueAuthorisationStatus, i as triggerPugpigUpdateSequence, j as TimelinesInfoPayload, k as TimelineMetadata, l as AnalyticsDimensions, m as Feed, o as GlobalBridge, p as BridgeService, r as BOOTSTRAP_METHODS, s as AdSize, u as AuthorisationStatus, v as ReadStoriesPayload, w as StoryImage, x as StoriesPayload, y as RemoteConfig } from "./chunks/index-B2cNakTH.mjs";
|
|
2
2
|
import * as _$vue from "vue";
|
|
3
3
|
import { App } from "vue";
|
|
4
4
|
|
|
@@ -13,43 +13,6 @@ declare function registerToolTips({
|
|
|
13
13
|
}?: RegisterTooltipsOptions): void;
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/vue/useBridge.d.ts
|
|
16
|
-
/**
|
|
17
|
-
* @description Returns the reactive bridge service with all store data as refs and all outgoing action methods bound to the reactive store.
|
|
18
|
-
* @usage const { stories, authorisationStatus, openArticle, sendAnalytics, ... } = useBridge()
|
|
19
|
-
* @returns stories {Ref<Story[]>} Derived story array with locked, hidden, saved, and read flags applied
|
|
20
|
-
* @returns rawStories {Ref<Story[]>} Unprocessed raw stories as received from the bridge
|
|
21
|
-
* @returns feed {Ref<Feed>} Current feed metadata
|
|
22
|
-
* @returns timelines {Ref<Timeline[]>} Available timelines
|
|
23
|
-
* @returns timelinesStates {Ref<Record<string, TimelineState>>} Per-timeline state records
|
|
24
|
-
* @returns themeURL {Ref<string[]>} URLs for the active theme files
|
|
25
|
-
* @returns theme {Ref<Theme>} Active light theme data
|
|
26
|
-
* @returns darkTheme {Ref<Theme>} Active dark theme data
|
|
27
|
-
* @returns timelineMode {Ref<string>} Current timeline display mode
|
|
28
|
-
* @returns timelineType {Ref<string>} Current timeline type (e.g. 'Timeline' | 'SavedTimeline')
|
|
29
|
-
* @returns sourceURL {Ref<string | null>} Source URL of the current feed
|
|
30
|
-
* @returns baseUrl {Ref<string>} Base URL used to resolve relative paths
|
|
31
|
-
* @returns metadataLoaded {Ref<boolean>} Whether feed metadata has been loaded
|
|
32
|
-
* @returns initialBatchSize {Ref<number>} Number of stories in the first rendered batch
|
|
33
|
-
* @returns filter {Ref<Record<string, unknown>>} Active filter state
|
|
34
|
-
* @returns authorisationStatus {Ref<AuthorisationStatus>} Current user authorisation status
|
|
35
|
-
* @returns issueAuthorisationStatus {Ref<IssueAuthorisationStatus>} Per-issue authorisation status
|
|
36
|
-
* @returns openArticle {(story: Story, index: number) => Promise<unknown>} Opens a story in the native reader
|
|
37
|
-
* @returns shareStory {(story: Story, index: number) => Promise<unknown>} Triggers the native share sheet
|
|
38
|
-
* @returns setSaved {(story: Story, index: number, saved: boolean) => Promise<unknown>} Updates the saved state for a story
|
|
39
|
-
* @returns setRead {(story: Story, index: number) => Promise<unknown>} Marks a story as read
|
|
40
|
-
* @returns sendAnalytics {(type: string | Record<string, unknown>, story: Story, index?: number, dimensions?: AnalyticsDimensions) => Promise<unknown>} Sends an analytics event
|
|
41
|
-
* @returns call {(action: string, payload?: unknown) => Promise<unknown>} Dispatches an arbitrary bridge action
|
|
42
|
-
* @returns timelineIsReady {() => void} Signals that the Vue app has mounted
|
|
43
|
-
* @returns fireToast {(type: string, action: string) => Promise<unknown>} Displays a native toast notification
|
|
44
|
-
* @returns openAudio {(story: Story, fallback: Record<string, unknown>, index: number) => Promise<unknown>} Opens the native audio player
|
|
45
|
-
* @returns openImageGallery {(images: StoryImage[] | undefined, initialImage?: number) => Promise<unknown>} Opens the native image gallery
|
|
46
|
-
* @returns addToCalendar {(story: Story, index: number) => Promise<unknown>} Adds an event to the device calendar
|
|
47
|
-
* @returns resolveIssueAccess {(story: Story) => boolean} Resolves whether a story is locked based on issue authorisation
|
|
48
|
-
* @returns $on {(event: string, listener: (...args: unknown[]) => void) => () => void} Subscribes to a bridge event; returns an unsubscribe function
|
|
49
|
-
* @returns $emit {(event: string, ...args: unknown[]) => void} Emits a bridge event
|
|
50
|
-
* @returns $once {(event: string, listener: (...args: unknown[]) => void) => void} Subscribes to a bridge event for a single invocation
|
|
51
|
-
* @returns bridge {BridgeService} The raw reactive bridge instance for direct access
|
|
52
|
-
*/
|
|
53
16
|
declare function useBridge(): {
|
|
54
17
|
resolveIssueAccess: (story: Story) => boolean;
|
|
55
18
|
$on: (event: string, listener: (...args: unknown[]) => void) => () => void;
|
|
@@ -77,28 +40,28 @@ declare function useBridge(): {
|
|
|
77
40
|
setRead(story: Story, index: number): Promise<unknown>;
|
|
78
41
|
shareStory(story: Story, index: number): Promise<unknown>;
|
|
79
42
|
addToCalendar(story: Story, index: number): Promise<unknown>;
|
|
43
|
+
timelineType: _$vue.Ref<string, string>;
|
|
44
|
+
debugLogs: _$vue.Ref<boolean, boolean>;
|
|
45
|
+
theme: _$vue.Ref<Theme, Theme>;
|
|
46
|
+
darkTheme: _$vue.Ref<Theme, Theme>;
|
|
80
47
|
filter: _$vue.Ref<Record<string, unknown>, Record<string, unknown>>;
|
|
48
|
+
authorisationStatus: _$vue.Ref<AuthorisationStatus, AuthorisationStatus>;
|
|
49
|
+
actionProviderNames: _$vue.Ref<string[], string[]>;
|
|
50
|
+
stories: _$vue.Ref<Story[], Story[]>;
|
|
81
51
|
feed: _$vue.Ref<Feed, Feed>;
|
|
82
52
|
rawStories: _$vue.Ref<Story[], Story[]>;
|
|
83
53
|
timelines: _$vue.Ref<Timeline[], Timeline[]>;
|
|
84
54
|
timelinesStates: _$vue.Ref<Record<string, TimelineState>, Record<string, TimelineState>>;
|
|
85
55
|
themeURL: _$vue.Ref<string[], string[]>;
|
|
86
|
-
theme: _$vue.Ref<Theme, Theme>;
|
|
87
|
-
darkTheme: _$vue.Ref<Theme, Theme>;
|
|
88
56
|
timelineMode: _$vue.Ref<string, string>;
|
|
89
|
-
timelineType: _$vue.Ref<string, string>;
|
|
90
57
|
sourceURL: _$vue.Ref<string | null, string | null>;
|
|
91
58
|
baseUrl: _$vue.Ref<string, string>;
|
|
92
59
|
metadataLoaded: _$vue.Ref<boolean, boolean>;
|
|
93
60
|
initialBatchSize: _$vue.Ref<number, number>;
|
|
94
61
|
positionOverrides: _$vue.Ref<unknown[], unknown[]>;
|
|
95
|
-
debugLogs: _$vue.Ref<boolean, boolean>;
|
|
96
|
-
actionProviderNames: _$vue.Ref<string[], string[]>;
|
|
97
|
-
authorisationStatus: _$vue.Ref<AuthorisationStatus, AuthorisationStatus>;
|
|
98
62
|
issueAuthorisationStatus: _$vue.Ref<IssueAuthorisationStatus, IssueAuthorisationStatus>;
|
|
99
63
|
read: _$vue.Ref<Set<string>, Set<string>>;
|
|
100
64
|
saved: _$vue.Ref<Set<string>, Set<string>>;
|
|
101
|
-
stories: _$vue.Ref<Story[], Story[]>;
|
|
102
65
|
themeFileNames: _$vue.Ref<string[], string[]>;
|
|
103
66
|
isSavedTimeline: _$vue.Ref<boolean, boolean>;
|
|
104
67
|
isCollection: _$vue.Ref<boolean, boolean>;
|
package/dist/vue.mjs
CHANGED
|
@@ -1,213 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { onUnmounted, reactive, ref, toRefs, watchEffect } from "vue";
|
|
3
|
-
//#region src/vue/tooltip.ts
|
|
4
|
-
const tooltipsQueue = ref([]);
|
|
5
|
-
const tooltipsRequests = ref([]);
|
|
6
|
-
const isScrolling = ref(false);
|
|
7
|
-
const createIntersectionObserver = (id, element) => {
|
|
8
|
-
if (tooltipsRequests.value.includes(id)) return;
|
|
9
|
-
const observer = new IntersectionObserver(([entry]) => {
|
|
10
|
-
if (!entry.isIntersecting) return;
|
|
11
|
-
if (tooltipsRequests.value.includes(id)) return observer.disconnect();
|
|
12
|
-
tooltipsQueue.value.push({
|
|
13
|
-
id,
|
|
14
|
-
el: element
|
|
15
|
-
});
|
|
16
|
-
observer.disconnect();
|
|
17
|
-
}, { threshold: 1 });
|
|
18
|
-
observer.observe(element);
|
|
19
|
-
return observer;
|
|
20
|
-
};
|
|
21
|
-
function initToolTips() {
|
|
22
|
-
window.addEventListener("scroll", () => {
|
|
23
|
-
isScrolling.value = true;
|
|
24
|
-
window.clearTimeout(window.scrollTimeout);
|
|
25
|
-
window.scrollTimeout = setTimeout(() => isScrolling.value = false, 150);
|
|
26
|
-
}, false);
|
|
27
|
-
watchEffect(() => {
|
|
28
|
-
if (isScrolling.value) return;
|
|
29
|
-
tooltipsQueue.value.forEach((tooltip, index) => {
|
|
30
|
-
if (tooltipsRequests.value.includes(tooltip.id)) return;
|
|
31
|
-
const { x, y, width: w, height: h } = tooltip.el.getBoundingClientRect();
|
|
32
|
-
const source = {
|
|
33
|
-
w,
|
|
34
|
-
h,
|
|
35
|
-
x,
|
|
36
|
-
y: y + window.scrollY
|
|
37
|
-
};
|
|
38
|
-
window.parent?.pugpigBridgeService?.showToolTip?.(JSON.stringify({
|
|
39
|
-
id: tooltip.id,
|
|
40
|
-
source
|
|
41
|
-
}));
|
|
42
|
-
tooltipsQueue.value.splice(index, 1);
|
|
43
|
-
tooltipsRequests.value.push(tooltip.id);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
function registerToolTips({ attribute = "tooltip", observerOptions } = {}) {
|
|
48
|
-
if (!window.parent?.pugpigBridgeService?.showToolTip) return;
|
|
49
|
-
initToolTips();
|
|
50
|
-
const mutationObserverCallback = (mutations) => {
|
|
51
|
-
mutations.forEach((mutation) => mutation.addedNodes.forEach((node) => {
|
|
52
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
53
|
-
const el = node;
|
|
54
|
-
const tooltipValue = el.getAttribute(attribute);
|
|
55
|
-
if (!tooltipValue) return;
|
|
56
|
-
if (tooltipsRequests.value.includes(tooltipValue)) return;
|
|
57
|
-
createIntersectionObserver(tooltipValue, el);
|
|
58
|
-
}));
|
|
59
|
-
};
|
|
60
|
-
const mutationObserver = new MutationObserver(mutationObserverCallback);
|
|
61
|
-
mutationObserverCallback([{ addedNodes: document.body.childNodes }]);
|
|
62
|
-
mutationObserver.observe(document.body, observerOptions ?? {
|
|
63
|
-
childList: true,
|
|
64
|
-
subtree: true
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function installTooltipDirective(app) {
|
|
68
|
-
if (!window.parent?.pugpigBridgeService?.showToolTip) {
|
|
69
|
-
app.directive("tooltip", {});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
initToolTips();
|
|
73
|
-
app.directive("tooltip", { mounted: (el, binding) => createIntersectionObserver(binding.value, el) });
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/vue/useBridge.ts
|
|
77
|
-
const reactiveBridge = window.boltBridge || reactive(rawBridge);
|
|
78
|
-
function bindAll(obj, ctx) {
|
|
79
|
-
return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, typeof v === "function" ? v.bind(ctx) : v]));
|
|
80
|
-
}
|
|
81
|
-
const boundActions = bindAll(outgoingActions, reactiveBridge);
|
|
82
|
-
/**
|
|
83
|
-
* @description Returns the reactive bridge service with all store data as refs and all outgoing action methods bound to the reactive store.
|
|
84
|
-
* @usage const { stories, authorisationStatus, openArticle, sendAnalytics, ... } = useBridge()
|
|
85
|
-
* @returns stories {Ref<Story[]>} Derived story array with locked, hidden, saved, and read flags applied
|
|
86
|
-
* @returns rawStories {Ref<Story[]>} Unprocessed raw stories as received from the bridge
|
|
87
|
-
* @returns feed {Ref<Feed>} Current feed metadata
|
|
88
|
-
* @returns timelines {Ref<Timeline[]>} Available timelines
|
|
89
|
-
* @returns timelinesStates {Ref<Record<string, TimelineState>>} Per-timeline state records
|
|
90
|
-
* @returns themeURL {Ref<string[]>} URLs for the active theme files
|
|
91
|
-
* @returns theme {Ref<Theme>} Active light theme data
|
|
92
|
-
* @returns darkTheme {Ref<Theme>} Active dark theme data
|
|
93
|
-
* @returns timelineMode {Ref<string>} Current timeline display mode
|
|
94
|
-
* @returns timelineType {Ref<string>} Current timeline type (e.g. 'Timeline' | 'SavedTimeline')
|
|
95
|
-
* @returns sourceURL {Ref<string | null>} Source URL of the current feed
|
|
96
|
-
* @returns baseUrl {Ref<string>} Base URL used to resolve relative paths
|
|
97
|
-
* @returns metadataLoaded {Ref<boolean>} Whether feed metadata has been loaded
|
|
98
|
-
* @returns initialBatchSize {Ref<number>} Number of stories in the first rendered batch
|
|
99
|
-
* @returns filter {Ref<Record<string, unknown>>} Active filter state
|
|
100
|
-
* @returns authorisationStatus {Ref<AuthorisationStatus>} Current user authorisation status
|
|
101
|
-
* @returns issueAuthorisationStatus {Ref<IssueAuthorisationStatus>} Per-issue authorisation status
|
|
102
|
-
* @returns openArticle {(story: Story, index: number) => Promise<unknown>} Opens a story in the native reader
|
|
103
|
-
* @returns shareStory {(story: Story, index: number) => Promise<unknown>} Triggers the native share sheet
|
|
104
|
-
* @returns setSaved {(story: Story, index: number, saved: boolean) => Promise<unknown>} Updates the saved state for a story
|
|
105
|
-
* @returns setRead {(story: Story, index: number) => Promise<unknown>} Marks a story as read
|
|
106
|
-
* @returns sendAnalytics {(type: string | Record<string, unknown>, story: Story, index?: number, dimensions?: AnalyticsDimensions) => Promise<unknown>} Sends an analytics event
|
|
107
|
-
* @returns call {(action: string, payload?: unknown) => Promise<unknown>} Dispatches an arbitrary bridge action
|
|
108
|
-
* @returns timelineIsReady {() => void} Signals that the Vue app has mounted
|
|
109
|
-
* @returns fireToast {(type: string, action: string) => Promise<unknown>} Displays a native toast notification
|
|
110
|
-
* @returns openAudio {(story: Story, fallback: Record<string, unknown>, index: number) => Promise<unknown>} Opens the native audio player
|
|
111
|
-
* @returns openImageGallery {(images: StoryImage[] | undefined, initialImage?: number) => Promise<unknown>} Opens the native image gallery
|
|
112
|
-
* @returns addToCalendar {(story: Story, index: number) => Promise<unknown>} Adds an event to the device calendar
|
|
113
|
-
* @returns resolveIssueAccess {(story: Story) => boolean} Resolves whether a story is locked based on issue authorisation
|
|
114
|
-
* @returns $on {(event: string, listener: (...args: unknown[]) => void) => () => void} Subscribes to a bridge event; returns an unsubscribe function
|
|
115
|
-
* @returns $emit {(event: string, ...args: unknown[]) => void} Emits a bridge event
|
|
116
|
-
* @returns $once {(event: string, listener: (...args: unknown[]) => void) => void} Subscribes to a bridge event for a single invocation
|
|
117
|
-
* @returns bridge {BridgeService} The raw reactive bridge instance for direct access
|
|
118
|
-
*/
|
|
119
|
-
function useBridge() {
|
|
120
|
-
return {
|
|
121
|
-
...toRefs(reactiveBridge),
|
|
122
|
-
...boundActions,
|
|
123
|
-
resolveIssueAccess: reactiveBridge.resolveIssueAccess,
|
|
124
|
-
$on: (event, listener) => reactiveBridge.$on(event, listener),
|
|
125
|
-
$emit: (event, ...args) => reactiveBridge.$emit(event, ...args),
|
|
126
|
-
$once: (event, listener) => reactiveBridge.$once(event, listener),
|
|
127
|
-
bridge: reactiveBridge
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
//#endregion
|
|
131
|
-
//#region src/vue/bootstrap.ts
|
|
132
|
-
function useBootstrap(options = {}) {
|
|
133
|
-
const { readyTimeout = 4e3 } = options;
|
|
134
|
-
if ("scrollRestoration" in history) history.scrollRestoration = "manual";
|
|
135
|
-
triggerPugpigUpdateSequence();
|
|
136
|
-
injectThemeAndWait(readyTimeout);
|
|
137
|
-
applyFeedClasses();
|
|
138
|
-
}
|
|
139
|
-
function injectThemeAndWait(readyTimeout = 4e3) {
|
|
140
|
-
const loaded = [];
|
|
141
|
-
const forceReady = setTimeout(() => {
|
|
142
|
-
globalBridge.logInfo?.("debug", `${readyTimeout}ms have passed, forcing timelineIsReady`);
|
|
143
|
-
globalBridge.timelineIsReady?.();
|
|
144
|
-
}, readyTimeout);
|
|
145
|
-
function onDepLoaded(name) {
|
|
146
|
-
loaded.push(name);
|
|
147
|
-
if (!["renderedRequiredStyles", ...globalBridge.themeFileNames ?? []].every((dep) => loaded.includes(dep))) return;
|
|
148
|
-
clearTimeout(forceReady);
|
|
149
|
-
document.fonts.ready.then(() => globalBridge.timelineIsReady?.());
|
|
150
|
-
}
|
|
151
|
-
for (const url of globalBridge.themeURL ?? []) {
|
|
152
|
-
const link = document.createElement("link");
|
|
153
|
-
link.rel = "stylesheet";
|
|
154
|
-
link.href = url;
|
|
155
|
-
link.onload = () => onDepLoaded(url);
|
|
156
|
-
link.onerror = () => onDepLoaded(url);
|
|
157
|
-
document.head.appendChild(link);
|
|
158
|
-
}
|
|
159
|
-
onDepLoaded("renderedRequiredStyles");
|
|
160
|
-
}
|
|
161
|
-
function applyFeedClasses(rootSelector = "#app") {
|
|
162
|
-
const rootEl = document.querySelector(rootSelector);
|
|
163
|
-
const classes = [...globalBridge.feed?.classes ?? []];
|
|
164
|
-
if (globalBridge.isSavedTimeline) classes.push("saved-timeline");
|
|
165
|
-
if (rootEl && classes.length) rootEl.classList.add(...classes);
|
|
166
|
-
}
|
|
167
|
-
function useDependencyTracker(options = {}) {
|
|
168
|
-
const { readyTimeout = 4e3 } = options;
|
|
169
|
-
const loadedDependencies = ref([]);
|
|
170
|
-
const forceReady = setTimeout(() => {
|
|
171
|
-
globalBridge.logInfo?.("debug", `${readyTimeout}ms have passed, forcing timelineIsReady`);
|
|
172
|
-
globalBridge.timelineIsReady?.();
|
|
173
|
-
}, readyTimeout);
|
|
174
|
-
function onDependencyLoaded(dependencyName) {
|
|
175
|
-
if (loadedDependencies.value.includes(dependencyName)) return;
|
|
176
|
-
loadedDependencies.value.push(dependencyName);
|
|
177
|
-
const isLoaded = [
|
|
178
|
-
"mainView",
|
|
179
|
-
"renderedRequiredStyles",
|
|
180
|
-
...globalBridge.themeFileNames ?? []
|
|
181
|
-
].every((dep) => loadedDependencies.value.includes(dep));
|
|
182
|
-
globalBridge.logInfo?.("debug", `Theme dependency '${dependencyName}' loaded (${performance.now()}ms)`);
|
|
183
|
-
if (!isLoaded) return;
|
|
184
|
-
clearTimeout(forceReady);
|
|
185
|
-
globalBridge.logInfo?.("debug", `Theme dependencies complete: ${loadedDependencies.value.join(", ")}`);
|
|
186
|
-
document.fonts.ready.then(() => {
|
|
187
|
-
globalBridge.logInfo?.("debug", `Document fonts loaded (${performance.now()}ms)`);
|
|
188
|
-
globalBridge.timelineIsReady?.();
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
onUnmounted(() => {
|
|
192
|
-
clearTimeout(forceReady);
|
|
193
|
-
});
|
|
194
|
-
return {
|
|
195
|
-
loadedDependencies,
|
|
196
|
-
onDependencyLoaded
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
//#endregion
|
|
200
|
-
//#region src/vue/index.ts
|
|
201
|
-
const globalBridge = window.boltBridge || reactive(rawBridge);
|
|
202
|
-
window.boltBridge = globalBridge;
|
|
203
|
-
const isDebug = window.location.search.includes("preview");
|
|
204
|
-
const BoltBridgeVue = (app, callback) => {
|
|
205
|
-
setupPugpigUpdate(globalBridge);
|
|
206
|
-
app.config.globalProperties.$bridge = globalBridge;
|
|
207
|
-
app.provide("globalBridge", globalBridge);
|
|
208
|
-
app.use(installTooltipDirective);
|
|
209
|
-
if (isDebug) import("./development-Bl8-5E3g.mjs").then(({ injectBridge }) => injectBridge(app, callback)).then(() => callback?.());
|
|
210
|
-
else callback?.();
|
|
211
|
-
};
|
|
212
|
-
//#endregion
|
|
213
|
-
export { BOOTSTRAP_METHODS, BoltBridgeVue, applyFeedClasses, globalBridge, injectThemeAndWait, isDebug, registerToolTips, triggerPugpigUpdateSequence, useBootstrap, useBridge, useDependencyTracker };
|
|
1
|
+
import{i as e,o as t,r as n,s as r,t as i}from"./chunks/bootstrap-B7Gwb_jl.mjs";import{onUnmounted as a,reactive as o,ref as s,toRefs as c,watchEffect as l}from"vue";const u=s([]),d=s([]),f=s(!1),p=(e,t)=>{if(d.value.includes(e))return;let n=new IntersectionObserver(([r])=>{if(r.isIntersecting){if(d.value.includes(e))return n.disconnect();u.value.push({id:e,el:t}),n.disconnect()}},{threshold:1});return n.observe(t),n};function m(){window.addEventListener(`scroll`,()=>{f.value=!0,window.clearTimeout(window.scrollTimeout),window.scrollTimeout=setTimeout(()=>f.value=!1,150)},!1),l(()=>{f.value||u.value.forEach((e,t)=>{if(d.value.includes(e.id))return;let{x:n,y:r,width:i,height:a}=e.el.getBoundingClientRect(),o={w:i,h:a,x:n,y:r+window.scrollY};window.parent?.pugpigBridgeService?.showToolTip?.(JSON.stringify({id:e.id,source:o})),u.value.splice(t,1),d.value.push(e.id)})})}function h({attribute:e=`tooltip`,observerOptions:t}={}){if(!window.parent?.pugpigBridgeService?.showToolTip)return;m();let n=t=>{t.forEach(t=>t.addedNodes.forEach(t=>{if(t.nodeType!==Node.ELEMENT_NODE)return;let n=t,r=n.getAttribute(e);r&&(d.value.includes(r)||p(r,n))}))},r=new MutationObserver(n);n([{addedNodes:document.body.childNodes}]),r.observe(document.body,t??{childList:!0,subtree:!0})}function g(e){if(!window.parent?.pugpigBridgeService?.showToolTip){e.directive(`tooltip`,{});return}m(),e.directive(`tooltip`,{mounted:(e,t)=>p(t.value,e)})}const _=window.boltBridge||o(t);function v(e,t){return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,typeof n==`function`?n.bind(t):n]))}const y=v(r,_);function b(){return{...c(_),...y,resolveIssueAccess:_.resolveIssueAccess,$on:(e,t)=>_.$on(e,t),$emit:(e,...t)=>_.$emit(e,...t),$once:(e,t)=>_.$once(e,t),bridge:_}}function x(e={}){let{readyTimeout:t=4e3}=e;`scrollRestoration`in history&&(history.scrollRestoration=`manual`),n(),S(t),C()}function S(e=4e3){let t=[],n=setTimeout(()=>{T.logInfo?.(`debug`,`${e}ms have passed, forcing timelineIsReady`),T.timelineIsReady?.()},e);function r(e){t.push(e),[`renderedRequiredStyles`,...T.themeFileNames??[]].every(e=>t.includes(e))&&(clearTimeout(n),document.fonts.ready.then(()=>T.timelineIsReady?.()))}for(let e of T.themeURL??[]){let t=document.createElement(`link`);t.rel=`stylesheet`,t.href=e,t.onload=()=>r(e),t.onerror=()=>r(e),document.head.appendChild(t)}r(`renderedRequiredStyles`)}function C(e=`#app`){let t=document.querySelector(e),n=[...T.feed?.classes??[]];T.isSavedTimeline&&n.push(`saved-timeline`),t&&n.length&&t.classList.add(...n)}function w(e={}){let{readyTimeout:t=4e3}=e,n=s([]),r=setTimeout(()=>{T.logInfo?.(`debug`,`${t}ms have passed, forcing timelineIsReady`),T.timelineIsReady?.()},t);function i(e){if(n.value.includes(e))return;n.value.push(e);let t=[`mainView`,`renderedRequiredStyles`,...T.themeFileNames??[]].every(e=>n.value.includes(e));T.logInfo?.(`debug`,`Theme dependency '${e}' loaded (${performance.now()}ms)`),t&&(clearTimeout(r),T.logInfo?.(`debug`,`Theme dependencies complete: ${n.value.join(`, `)}`),document.fonts.ready.then(()=>{T.logInfo?.(`debug`,`Document fonts loaded (${performance.now()}ms)`),T.timelineIsReady?.()}))}return a(()=>{clearTimeout(r)}),{loadedDependencies:n,onDependencyLoaded:i}}const T=window.boltBridge||o(t);window.boltBridge=T;const E=window.location.search.includes(`preview`),D=(t,n)=>{e(T),t.config.globalProperties.$bridge=T,t.provide(`globalBridge`,T),t.use(g),E?import(`./chunks/development-CzUmtUQR.mjs`).then(({injectBridge:e})=>e(t,n)).then(()=>n?.()):n?.()};export{i as BOOTSTRAP_METHODS,D as BoltBridgeVue,C as applyFeedClasses,T as globalBridge,S as injectThemeAndWait,E as isDebug,h as registerToolTips,n as triggerPugpigUpdateSequence,x as useBootstrap,b as useBridge,w as useDependencyTracker};
|