Skip to content

Commit a9826e2

Browse files
committed
Add crmAPI.fetch and crmAPI.fetchBackground functions (fixes #36)
1 parent 0c36793 commit a9826e2

4 files changed

Lines changed: 157 additions & 0 deletions

File tree

app/js/background/messagehandling.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,48 @@ export namespace MessageHandling {
148148
}> {
149149
action: string;
150150
}
151+
export function doFetch(url: string): Promise<string> {
152+
if ('fetch' in window && window.fetch !== undefined) {
153+
return fetch(url).then(r => r.text()) as unknown as Promise<string>;
154+
}
155+
156+
return new Promise<string>((resolve, reject) => {
157+
const xhr = new window.XMLHttpRequest();
158+
xhr.open('GET', url);
159+
xhr.onreadystatechange = () => {
160+
if (xhr.readyState === 4) {
161+
if (xhr.status >= 200 && xhr.status < 300) {
162+
resolve(xhr.responseText);
163+
} else {
164+
reject(xhr.status);
165+
}
166+
}
167+
}
168+
xhr.send();
169+
});
170+
}
171+
export function backgroundFetch(message: CRMAPIMessageInstance<string, {
172+
url: string;
173+
onFinish: number;
174+
}>) {
175+
const url = message.data.url;
176+
doFetch(url).then((responseText) => {
177+
modules.globalObject.globals.sendCallbackMessage(message.tabId,
178+
message.tabIndex, message.id, {
179+
err: false,
180+
args: [false, responseText],
181+
callbackId: message.data.onFinish
182+
});
183+
}).catch((err) => {
184+
modules.globalObject.globals.sendCallbackMessage(message.tabId,
185+
message.tabIndex, message.id, {
186+
// Don't signify an error so the promise can be handled
187+
err: false,
188+
args: [true, `Failed with status ${err}`],
189+
callbackId: message.data.onFinish
190+
});
191+
});
192+
}
151193

152194
async function handleRuntimeMessage(message: CRMAPIMessageInstance<string, any>,
153195
messageSender?: _browser.runtime.MessageSender,
@@ -240,6 +282,9 @@ export namespace MessageHandling {
240282
modules.Storages.clearStorages();
241283
await modules.Storages.loadStorages();
242284
break;
285+
case 'fetch':
286+
await backgroundFetch(message);
287+
243288
}
244289
respond && respond(response);
245290
}

app/js/crmapi.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5934,6 +5934,67 @@ export type CRMAPIMessage = {
59345934
}
59355935
};
59365936

5937+
/**
5938+
* Fetches resource at given url. If this keeps failing with
5939+
* a CORB error, try crmAPI.fetchBackground
5940+
*
5941+
* @param {string} url - The url to fetch the data from
5942+
* @returns {Promise<string>} A promise that resolves to the content
5943+
*/
5944+
fetch(url: string): Promise<string> {
5945+
if ('fetch' in window && window.fetch !== undefined) {
5946+
return fetch(url).then(r => r.text()) as unknown as Promise<string>;
5947+
}
5948+
5949+
return new Promise<string>((resolve, reject) => {
5950+
const xhr = new window.XMLHttpRequest();
5951+
xhr.open('GET', url);
5952+
xhr.onreadystatechange = () => {
5953+
if (xhr.readyState === 4) {
5954+
if (xhr.status >= 200 && xhr.status < 300) {
5955+
resolve(xhr.responseText);
5956+
} else {
5957+
reject(new Error(`Failed xhr with status ${xhr.status}`));
5958+
}
5959+
}
5960+
}
5961+
xhr.send();
5962+
});
5963+
}
5964+
5965+
/**
5966+
* Fetches resource at given url through the background-page, bypassing
5967+
* any CORS or CORB-like blocking
5968+
*
5969+
* @param {string} url - The url to fetch the data from
5970+
* @returns {Promise<string>} A promise that resolves to the content
5971+
*/
5972+
fetchBackground(url: string): Promise<string> {
5973+
return new Promise<string>((resolve, reject) => {
5974+
this.__privates._sendMessage({
5975+
id: this.__privates._id,
5976+
type: 'fetch',
5977+
tabId: this.__privates._tabData.id,
5978+
tabIndex: this.__privates._tabIndex,
5979+
data: {
5980+
url: url,
5981+
onFinish: this.__privates._createCallbackFunction((err: boolean, data: string) => {
5982+
if (err) {
5983+
reject(data);
5984+
} else {
5985+
resolve(data);
5986+
}
5987+
}, new Error(), {
5988+
maxCalls: 1
5989+
}),
5990+
id: this.__privates._id,
5991+
tabIndex: this.__privates._tabIndex,
5992+
tabId: this.__privates._tabData.id
5993+
}
5994+
})
5995+
});
5996+
}
5997+
59375998
/**
59385999
* Returns the elements matching given selector within given context
59396000
*

test/test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6037,4 +6037,37 @@ describe('CRMAPI', () => {
60376037
});
60386038
});
60396039
});
6040+
describe('#fetch()', () => {
6041+
it('should return the data at the URL', async function() {
6042+
this.timeout(5000);
6043+
this.slow(2500);
6044+
6045+
assert.isFunction(crmAPI.fetch);
6046+
await asyncDoesNotThrow(() => {
6047+
return new Promise(async (resolve) => {
6048+
const result = await crmAPI.fetch('https://www.example.com');
6049+
assert.isTrue(result.indexOf('example') > -1,
6050+
'page is successfully loaded');
6051+
resolve(null);
6052+
});
6053+
});
6054+
});
6055+
});
6056+
describe('#fetchBackground()', () => {
6057+
it('should return the data at the URL', async function() {
6058+
this.timeout(5000);
6059+
this.slow(2500);
6060+
6061+
assert.isFunction(crmAPI.fetchBackground);
6062+
await asyncDoesNotThrow(() => {
6063+
return new Promise(async (resolve) => {
6064+
debugger;
6065+
const result = await crmAPI.fetchBackground('https://www.example.com');
6066+
assert.isTrue(result.indexOf('example') > -1,
6067+
'page is successfully loaded');
6068+
resolve(null);
6069+
});
6070+
});
6071+
});
6072+
});
60406073
});

tools/definitions/crmapi.d.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,6 +3160,24 @@ declare namespace CRM {
31603160
*/
31613161
GM: GM_Fns;
31623162

3163+
/**
3164+
* Fetches resource at given url. If this keeps failing with
3165+
* a CORB error, try crmAPI.fetchBackground
3166+
*
3167+
* @param {string} url - The url to fetch the data from
3168+
* @returns {Promise<string>} A promise that resolves to the content
3169+
*/
3170+
fetch(url: string): Promise<string>;
3171+
3172+
/**
3173+
* Fetches resource at given url through the background-page, bypassing
3174+
* any CORS or CORB-like blocking
3175+
*
3176+
* @param {string} url - The url to fetch the data from
3177+
* @returns {Promise<string>} A promise that resolves to the content
3178+
*/
3179+
fetchBackground(url: string): Promise<string>
3180+
31633181
/**
31643182
* Logs given arguments to the background page and logger page
31653183
*

0 commit comments

Comments
 (0)