PageSourceSearch

https://yaqeeninstitute.org/yqn-interaction-ww.js

js yaqeeninstitute.org collected 2026-10-01 11:26:37 UTC 4,048 bytes, 153 lines download raw bytes

1const DB_NAME = 'yaqeenInteraction'
2const DB_VERSION = 1
3const STORE_NAME = 'interactions'
4
5async function onSync(token) {
6  if (!token) {
7    console.error('No token found')
8    return
9  }
10
11  const interactions = await fetchWithToken(token)
12
13  if (interactions?.data?.length === 0) {
14    console.debug('No interactions found')
15    return
16  }
17
18  const openRequest = indexedDB.open(DB_NAME, DB_VERSION);
19
20  openRequest.onsuccess = (event) => {
21    const db = event.target.result;
22    const transaction = db.transaction(STORE_NAME, 'readwrite');
23    const store = transaction.objectStore(STORE_NAME);
24    // clear the store
25    store.clear()
26
27    // populate the store
28    interactions.data.forEach((interaction) => {
29      store.add(interaction, interaction.object.id)
30    })
31
32    console.debug('IndexedDB populated with', interactions.data.length, 'interactions')
33  };
34
35  openRequest.onerror = (err) => {
36    console.error('Error opening IndexedDB:', err)
37  }
38}
39
40/**
41 * Returns a list of interactions to be deleted. We aim to keep only the recent 200 interactions.
42 * Refer to src/constants/x-api.ts for the definition of the interaction object.
43 * @typedef {Object} Interaction
44 * @property {string} id
45 * @property {Object} actor
46 * @property {string} actor.objectType
47 * @property {string} actor.name
48 * @property {Object} actor.account
49 * @property {string} actor.account.homePage
50 * @property {string} actor.account.name
51 * @property {Object} verb
52 * @property {string} verb.id
53 * @property {Object} verb.display
54 * @param {{
55 *  id: string,
56 *  actor: {
57 *    objectType: 'Agent',
58 *    name?: string,
59 *    account?: {
60 *      homePage: string,
61 *      name: string
62 *    }
63 *  },
64 *  verb: {
65 *    id: string,
66 *    display: {
67 *      'en-US': string
68 *    }
69 *  },
70 *  object: {
71 *    id: string,
72 *    objectType: 'Activity',
73 *    definition: {
74 *      name: {
75 *        'en-US': string
76 *      },
77 *      description?: {
78 *        'en-US': string
79 *      },
80 *      extensions: {
81 *        'http://yqn.io/extensions/post-type': string,
82 *        'http://yqn.io/extensions/post-title': string,
83 *        'http://yqn.io/extensions/post-thumbnail': string,
84 *        'http://yqn.io/extensions/post-authors': string[]
85 *      }
86 *    }
87 *  },
88 *  result?: {
89 *    score: {
90 *      raw: number
91 *    }
92 *  },
93 *  timestamp: string,
94 *  version: string
95 * }[]} data
96 *
97 * @returns string[]
98 */
99function getDeletionList(data) {
100  const MAX_INTERACTIONS = 800
101  // sort by timestamp and retrieve only the last 800 interactions
102  const sortedData = data.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
103  const trimmedData = sortedData.slice(0, MAX_INTERACTIONS);
104
105  // retrieve data that is not in the trimmed data
106  const remainingData = data.filter((interaction) => !trimmedData.some((t) => t.id === interaction.id));
107  return remainingData.map((interaction) => interaction.id)
108}
109
110async function fetchWithToken(token) {
111  const response = await fetch('https://webhooks.yaqeeninstitute.org/web-api-dev/api/v1/interactions', {
112    headers: {
113      Authorization: token,
114    },
115  })
116  return response.json()
117}
118
119async function onLimit() {
120  const openRequest = indexedDB.open(DB_NAME, DB_VERSION);
121
122  openRequest.onsuccess = (event) => {
123    const db = event.target.result;
124    const transaction = db.transaction(STORE_NAME, 'readwrite');
125    const store = transaction.objectStore(STORE_NAME);
126    const deletionList = getDeletionList(store.getAll())
127    deletionList.forEach((id) => {
128      store.delete(id)
129    })
130
131    console.debug('Deleted', deletionList.length, 'interactions')
132  };
133
134  openRequest.onerror = (err) => {
135    console.error('Error opening IndexedDB:', err)
136  }
137}
138
139self.onmessage = async (event) => {
140  console.debug('Received message from main', event)
141  try {
142    const eventData = event.data
143    if (eventData.action === 'sync') {
144      onSync(eventData.token)
145    }
146
147    if (eventData.action === 'limit') {
148      onLimit()
149    }
150  } catch (e) {
151    console.error('Error starting interaction tracker', e)
152  }
153};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.