Files
omnivore/pkg/extension/src/scripts/api.js
Tom Rogers 4e582fb55d Improving Self-Hosting and Removing 3rd Party dependencies. (#4513)
* fix: Library Header layout shift

* Bump Github Actions versions.

* Self-Hosting Changes

* Fix Minio Environment Variable

* Just make pdfs successful, due to lack of PDFHandler

* Fix issue where flag was set wrong

* Added an NGINX Example file

* Add some documentation for self-hosting via Docker Compose

* Make some adjustments to Puppeteer due to failing sites.

* adjust timings

* Add start of Mail Service

* Fix Docker Files

* More email service stuff

* Add Guide to use Zapier for Email-Importing.

* Ensure that if no env is provided it uses the old email settings

* Add some instructions for self-hosted email

* Add SNS Endpoints for Mail Watcher

* Add steps and functionality for using SES and SNS for email

* Uncomment a few jobs.

* Added option for Firefox for parser. Was having issues with Chromium on Docker.

* Add missing space.

Co-authored-by: Russ Taylor <729694+russtaylor@users.noreply.github.com>

* Fix some wording on the Guide

* update browser extension to handle self-hosted instances

* add slight documentation to options page

* Fix MV

* Do raw handlers for Medium

* Fix images in Medium

* Update self-hosting/GUIDE.md

Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com>

* Update Guide with other variables

* Add The Verge to JS-less handlers

* Update regex and image-proxy

* Update self-hosting/nginx/nginx.conf

Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com>

* Update regex and image-proxy

* Update self-hosting/docker-compose/docker-compose.yml

Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com>

* Fix Minio for Export

* Merge to main

* Update GUIDE with newer NGINX

* Update nginx config to include api/save route

* Enable Native PDF View for PDFS

* Enable Native PDF View for PDFS

* feat:lover packages test

* feat:working build

* feat:alpine build

* docs:api dockerfile docs

* Write a PDF.js wrapper to replace pspdfkit

* Revert changes for replication, set settings to have default mode

* build folder got removed due to gitignore on pdf

* Add Box shadow to pdf pages

* Add Toggle for Progress in PDFS, enabled native viewer toggle

* Update node version to LTS

* Update node version to LTS

* Fix Linting issues

* Fix Linting issues

* Make env variable nullable

* Add touchend listener for mobile

* Make changes to PDF for mobile

* fix(android): change serverUrl to selfhosted first

* feat:2 stage alpine content fetch

* feat:separated start script

* fix:changed to node 22

* Add back youtube functionality and add guide

* trigger build

* Fix cache issue on YouTube

* Allow empty AWS_S3_ENDPOINT

* Allow empty AWS_S3_ENDPOINT

* Add GCHR for all images

* Add GCHR For self hosting.

* Add GCHR For self hosting.

* Test prebuilt.

* Test prebuilt

* Test prebuilt...

* Fix web image

* Remove Web Image (For now)

* Move docker-compose to images

* Move docker-compose files to correct locations

* Remove the need for ARGS

* Update packages, and Typescript versions

* Fix

* Fix issues with build on Web

* Correct push

* Fix Linting issues

* Fix Trace import

* Add missing types

* Fix Tasks

* Add information into guide about self-build

* Fix issues with PDF Viewer

---------

Co-authored-by: keumky2 <keumky2@woowahan.com>
Co-authored-by: William Theaker <wtheaker@nvidia.com>
Co-authored-by: Russ Taylor <729694+russtaylor@users.noreply.github.com>
Co-authored-by: David Adams <david@dadams2.com>
Co-authored-by: Mike Baker <1426795+mbaker3@users.noreply.github.com>
Co-authored-by: m1xxos <66390094+m1xxos@users.noreply.github.com>
Co-authored-by: Adil <mr.adil777@gmail.com>
2025-01-27 13:33:16 +01:00

350 lines
8.0 KiB
JavaScript

function gqlRequest(apiUrl, query) {
return Promise.all([getStorageItem('apiKey'), getStorageItem('apiUrl')])
.then(([apiKey, savedUrl]) => {
const auth = apiKey ? { Authorization: apiKey } : {}
const url = savedUrl ? `${savedUrl}/graphql` : apiUrl
return fetch(url, {
method: 'POST',
redirect: 'follow',
credentials: 'include',
mode: 'cors',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...auth,
},
body: query,
})
})
.then((response) => response.json())
.then((json) => {
if (!json['data']) {
throw new Error('No response data')
}
return json['data']
})
}
async function updateLabelsCache(apiUrl, tab) {
const query = JSON.stringify({
query: `query GetLabels {
labels {
... on LabelsSuccess {
labels {
...LabelFields
}
}
... on LabelsError {
errorCodes
}
}
}
fragment LabelFields on Label {
id
name
color
description
createdAt
}
`,
})
const data = await gqlRequest(apiUrl, query)
if (!data.labels || data.labels['errorCodes'] || !data.labels['labels']) {
console.log('GQL Error updating label cache response:', data, data)
console.log(!data.labels, data.labels['errorCodes'], !data.labels['labels'])
return []
}
await setStorage({
labels: data.labels.labels,
labelsLastUpdated: new Date().toISOString(),
})
return data.labels.labels
}
async function updatePageTitle(apiUrl, pageId, title) {
const mutation = JSON.stringify({
query: `mutation UpdatePage($input: UpdatePageInput!) {
updatePage(input: $input) {
... on UpdatePageSuccess {
updatedPage {
id
}
}
... on UpdatePageError {
errorCodes
}
}
}
`,
variables: {
input: {
pageId,
title,
},
},
})
const data = await gqlRequest(apiUrl, mutation)
if (
!data.updatePage ||
data.updatePage['errorCodes'] ||
!data.updatePage['updatedPage']
) {
console.log('GQL Error updating page:', data)
throw new Error('Error updating title.')
}
return data.updatePage.updatePage
}
async function setLabels(apiUrl, pageId, labels) {
const mutation = JSON.stringify({
query: `mutation SetLabels($input: SetLabelsInput!) {
setLabels(input: $input) {
... on SetLabelsSuccess {
labels {
id
name
color
}
}
... on SetLabelsError {
errorCodes
}
}
}
`,
variables: {
input: {
pageId,
labels,
},
},
})
const data = await gqlRequest(apiUrl, mutation)
if (
!data.setLabels ||
data.setLabels['errorCodes'] ||
!data.setLabels['labels']
) {
console.log('GQL Error setting labels:', data)
throw new Error('Error setting labels.')
}
await appendLabelsToCache(data.setLabels.labels)
return data.setLabels.labels
}
async function appendLabelsToCache(labels) {
const cachedLabels = await getStorageItem('labels')
if (cachedLabels) {
labels.forEach((l) => {
const existing = cachedLabels.find((cached) => cached.name === l.name)
if (!existing) {
cachedLabels.unshift(l)
}
})
await setStorage({
labels: cachedLabels,
labelsLastUpdated: new Date().toISOString(),
})
} else {
await setStorage({
labels: labels,
labelsLastUpdated: new Date().toISOString(),
})
}
}
async function addNote(apiUrl, pageId, noteId, shortId, note) {
const query = JSON.stringify({
query: `query GetArticle(
$username: String!
$slug: String!
$includeFriendsHighlights: Boolean
) {
article(username: $username, slug: $slug) {
... on ArticleSuccess {
article {
highlights(input: { includeFriends: $includeFriendsHighlights }) {
...HighlightFields
}
}
}
... on ArticleError {
errorCodes
}
}
}
fragment HighlightFields on Highlight {
id
type
annotation
}
`,
variables: {
username: 'me',
slug: pageId,
includeFriendsHighlights: false,
},
})
const data = await gqlRequest(apiUrl, query)
if (!data.article || data.article['errorCodes'] || !data.article['article']) {
console.log('GQL Error getting existing highlights:', data)
return
}
const existingNote = data.article.article.highlights.find(
(h) => h.type == 'NOTE'
)
if (existingNote) {
const mutation = JSON.stringify({
query: `
mutation UpdateHighlight($input: UpdateHighlightInput!) {
updateHighlight(input: $input) {
... on UpdateHighlightSuccess {
highlight {
id
}
}
... on UpdateHighlightError {
errorCodes
}
}
}
`,
variables: {
input: {
highlightId: existingNote.id,
annotation: existingNote.annotation
? existingNote.annotation + '\n\n' + note
: note,
},
},
})
const result = await gqlRequest(apiUrl, mutation)
if (
!result.updateHighlight ||
result.updateHighlight['errorCodes'] ||
!result.updateHighlight.highlight
) {
console.log('GQL Error updating note:', result)
return
}
return result.updateHighlight.highlight.id
} else {
const mutation = JSON.stringify({
query: `
mutation CreateHighlight($input: CreateHighlightInput!) {
createHighlight(input: $input) {
... on CreateHighlightSuccess {
highlight {
id
}
}
... on CreateHighlightError {
errorCodes
}
}
}
`,
variables: {
input: {
id: noteId,
shortId: shortId,
type: 'NOTE',
articleId: pageId,
annotation: note,
},
},
})
const result = await gqlRequest(apiUrl, mutation)
if (
!result.createHighlight ||
result.createHighlight['errorCodes'] ||
!result.createHighlight.highlight
) {
console.log('GQL Error setting note:', result)
return
}
return result.createHighlight.highlight.id
}
}
async function archive(apiUrl, pageId) {
const mutation = JSON.stringify({
query: `mutation SetLinkArchived($input: ArchiveLinkInput!) {
setLinkArchived(input: $input) {
... on ArchiveLinkSuccess {
linkId
message
}
... on ArchiveLinkError {
message
errorCodes
}
}
}
`,
variables: {
input: {
linkId: pageId,
archived: true,
},
},
})
const data = await gqlRequest(apiUrl, mutation)
if (
!data.setLinkArchived ||
data.setLinkArchived['errorCodes'] ||
!data.setLinkArchived.linkId
) {
console.log('GQL Error archiving:', data)
throw new Error('Error archiving.')
}
return data.setLinkArchived.linkId
}
async function deleteItem(apiUrl, pageId) {
const mutation = JSON.stringify({
query: `mutation SetBookmarkArticle($input: SetBookmarkArticleInput!) {
setBookmarkArticle(input: $input) {
... on SetBookmarkArticleSuccess {
bookmarkedArticle {
id
}
}
... on SetBookmarkArticleError {
errorCodes
}
}
}
`,
variables: {
input: {
articleID: pageId,
bookmark: false,
},
},
})
const data = await gqlRequest(apiUrl, mutation)
if (
!data.setBookmarkArticle ||
data.setBookmarkArticle['errorCodes'] ||
!data.setBookmarkArticle.bookmarkedArticle
) {
console.log('GQL Error deleting:', data)
throw new Error('Error deleting.')
}
return data.setBookmarkArticle.bookmarkedArticle
}