Compare commits

..

3 Commits

Author SHA1 Message Date
4a81cbf321 Bump version to 9.2.2 2024-10-15 17:13:21 +02:00
b1d846de32 gm-fetch aktualisiert 2024-10-15 17:12:35 +02:00
748a8740eb Revert "gm-fetch für Firefox gefixt"
This reverts commit 20e011bb5507948894f9500355b457aa349556e9.
2024-10-15 16:45:21 +02:00
10 changed files with 26 additions and 233 deletions

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name 3CX TAPI
// @namespace http://cp-solutions.at
// @version 9.2.1
// @version 9.2.2
// @author Daniel Triendl <d.triendl@cp-solutions.at>
// @copyright Copyright 2021 CP Solutions GmbH
// @source https://source.cp-austria.at/git/CPATRD/3cx_tapi.git
@ -9,6 +9,8 @@
// @match https://192.168.0.154:5001/*
// @match https://cpsolution.my3cx.at:5001/*
// @require https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js
// @require https://cdn.jsdelivr.net/npm/axios@undefined/dist/axios.min.js
// @require https://cdn.jsdelivr.net/npm/axios-userscript-adapter@undefined/dist/axiosGmxhrAdapter.min.js
// @grant GM.xmlHttpRequest
// @grant GM.notification
// @grant GM.getValue
@ -4249,7 +4251,7 @@ function fireChangeEvents(element) {
console.debug('change event dispatched for element: ' + element.id);
}
;// ./src/gm-fetch/utils.ts
;// ./node_modules/@trim21/gm-fetch/dist/index.mjs
function parseRawHeaders(h) {
const s = h.trim();
if (!s) {
@ -4271,20 +4273,10 @@ function parseGMResponse(req, res) {
});
}
class ResImpl {
_bodyUsed;
rawBody;
init;
body;
headers;
redirected;
status;
statusText;
type;
url;
constructor(body, init) {
this.rawBody = body;
this.init = init;
//this.body = toReadableStream(body);
this.body = body.stream();
const { headers, statusCode, statusText, finalUrl, redirected } = init;
this.headers = headers;
this.status = statusCode;
@ -4358,18 +4350,6 @@ function decode(body) {
});
return form;
}
/*
function toReadableStream(value: Blob) {
return new ReadableStream({
start(controller) {
controller.enqueue(value);
controller.close();
},
});
}
*/
;// ./src/gm-fetch/index.ts
async function GM_fetch(input, init) {
const request = new Request(input, init);
@ -4417,6 +4397,9 @@ function gmXHRMethod(method) {
throw new Error(`unsupported http method ${method}`);
}
//# sourceMappingURL=index.mjs.map
;// ./src/call-history.ts

View File

@ -14,6 +14,8 @@ module.exports = {
],
require: [
'https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js',
`https://cdn.jsdelivr.net/npm/axios@${pkg.dependencies.axios}/dist/axios.min.js`,
`https://cdn.jsdelivr.net/npm/axios-userscript-adapter@${pkg.dependencies['axios-userscript-adapter']}/dist/axiosGmxhrAdapter.min.js`
],
grant: [
'GM.xmlHttpRequest',

11
package-lock.json generated
View File

@ -1,13 +1,14 @@
{
"name": "3cx-tapi",
"version": "9.2.0",
"version": "9.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "3cx-tapi",
"version": "9.2.0",
"version": "9.2.2",
"dependencies": {
"@trim21/gm-fetch": "^0.1.16",
"chrono-node": "^2.7.7"
},
"devDependencies": {
@ -1863,6 +1864,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/@trim21/gm-fetch": {
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/@trim21/gm-fetch/-/gm-fetch-0.1.16.tgz",
"integrity": "sha512-FoLbc1lsMvs/1xDgOZVbS+SYS4oFnp1RLdYT4lTrUFEIpbVR5t+b/E3Mg2oKl/yjgqEh2Ty2kI0U//gODz1V6w==",
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",

View File

@ -1,7 +1,7 @@
{
"name": "3cx-tapi",
"description": "3CX CP Tapi and Projectmanager integration",
"version": "9.2.1",
"version": "9.2.2",
"author": {
"name": "Daniel Triendl",
"email": "d.triendl@cp-solutions.at"
@ -24,7 +24,8 @@
},
"private": true,
"dependencies": {
"chrono-node": "^2.7.7"
"chrono-node": "^2.7.7",
"@trim21/gm-fetch": "^0.1.16"
},
"devDependencies": {
"@types/greasemonkey": "^4.0.7",

View File

@ -1,7 +1,7 @@
import * as chrono from 'chrono-node'
import { TapiContact } from './tapi-contact'
import { extractNumber } from './utils'
import GM_fetch from './gm-fetch'
import GM_fetch from '@trim21/gm-fetch'
export class CallHistory {
private callerIds: { [number: string]: TapiContact } = {}

View File

@ -1,4 +1,4 @@
import GM_fetch from './gm-fetch'
import GM_fetch from '@trim21/gm-fetch'
import { TapiContact } from './tapi-contact'
import { extractNumber } from './utils'

View File

@ -1,55 +0,0 @@
import { parseGMResponse } from "./utils";
export default async function GM_fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
const request = new Request(input, init);
let data: string | undefined;
if (init?.body) {
data = await request.text();
}
return await XHR(request, init, data);
}
function XHR(request: Request, init: RequestInit | undefined, data: string | undefined): Promise<Response> {
return new Promise((resolve, reject) => {
if (request.signal && request.signal.aborted) {
return reject(new DOMException("Aborted", "AbortError"));
}
GM.xmlHttpRequest({
url: request.url,
method: gmXHRMethod(request.method.toUpperCase()),
headers: Object.fromEntries(new Headers(init?.headers).entries()),
data: data,
responseType: "blob",
onload(res) {
resolve(parseGMResponse(request, res));
},
onabort() {
reject(new DOMException("Aborted", "AbortError"));
},
ontimeout() {
reject(new TypeError("Network request failed, timeout"));
},
onerror(err) {
reject(new TypeError("Failed to fetch: " + err.finalUrl));
},
});
});
}
const httpMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "TRACE", "OPTIONS", "CONNECT"] as const;
// a ts type helper to narrow type
function includes<T extends U, U>(array: ReadonlyArray<T>, element: U): element is T {
return array.includes(element as T);
}
function gmXHRMethod(method: string): (typeof httpMethods)[number] {
if (includes(httpMethods, method)) {
return method;
}
throw new Error(`unsupported http method ${method}`);
}

View File

@ -1,145 +0,0 @@
export function parseRawHeaders(h: string): Headers {
const s = h.trim();
if (!s) {
return new Headers();
}
const array: [string, string][] = s.split("\r\n").map((value) => {
let s = value.split(":");
return [s[0].trim(), s[1].trim()];
});
return new Headers(array);
}
export function parseGMResponse(req: Request, res: GM.Response<any>): Response {
return new ResImpl(res.response as Blob, {
statusCode: res.status,
statusText: res.statusText,
headers: parseRawHeaders(res.responseHeaders),
finalUrl: res.finalUrl,
redirected: res.finalUrl === req.url,
});
}
interface ResInit {
redirected: boolean;
headers: Headers;
statusCode: number;
statusText: string;
finalUrl: string;
}
class ResImpl implements Response {
private _bodyUsed: boolean;
private readonly rawBody: Blob;
private readonly init: ResInit;
readonly body: ReadableStream<Uint8Array> | null;
readonly headers: Headers;
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly type: ResponseType;
readonly url: string;
constructor(body: Blob, init: ResInit) {
this.rawBody = body;
this.init = init;
//this.body = toReadableStream(body);
const { headers, statusCode, statusText, finalUrl, redirected } = init;
this.headers = headers;
this.status = statusCode;
this.statusText = statusText;
this.url = finalUrl;
this.type = "basic";
this.redirected = redirected;
this._bodyUsed = false;
}
get bodyUsed(): boolean {
return this._bodyUsed;
}
get ok(): boolean {
return this.status < 300;
}
arrayBuffer(): Promise<ArrayBuffer> {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'arrayBuffer' on 'Response': body stream already read");
}
this._bodyUsed = true;
return this.rawBody.arrayBuffer();
}
blob(): Promise<Blob> {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'blob' on 'Response': body stream already read");
}
this._bodyUsed = true;
// `slice` will use empty string as default value, so need to pass all arguments.
return Promise.resolve(this.rawBody.slice(0, this.rawBody.size, this.rawBody.type));
}
clone(): Response {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'clone' on 'Response': body stream already read");
}
return new ResImpl(this.rawBody, this.init);
}
formData(): Promise<FormData> {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'formData' on 'Response': body stream already read");
}
this._bodyUsed = true;
return this.rawBody.text().then(decode);
}
async json(): Promise<any> {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'json' on 'Response': body stream already read");
}
this._bodyUsed = true;
return JSON.parse(await this.rawBody.text());
}
text(): Promise<string> {
if (this.bodyUsed) {
throw new TypeError("Failed to execute 'text' on 'Response': body stream already read");
}
this._bodyUsed = true;
return this.rawBody.text();
}
}
function decode(body: string) {
const form = new FormData();
body
.trim()
.split("&")
.forEach(function (bytes) {
if (bytes) {
const split = bytes.split("=");
const name = split.shift()?.replace(/\+/g, " ");
const value = split.join("=").replace(/\+/g, " ");
form.append(decodeURIComponent(name!), decodeURIComponent(value));
}
});
return form;
}
/*
function toReadableStream(value: Blob) {
return new ReadableStream({
start(controller) {
controller.enqueue(value);
controller.close();
},
});
}
*/

View File

@ -2,7 +2,7 @@ import './search.css'
import { TapiContact } from './tapi-contact'
import { debounce } from './debounce'
import { fireChangeEvents } from './utils'
import GM_fetch from './gm-fetch'
import GM_fetch from '@trim21/gm-fetch'
export class Search {
private currentSearchText = ''

View File

@ -1,6 +1,6 @@
import GM_fetch from './gm-fetch';
import './status.css';
import { ZcStatus } from './zc-status';
import GM_fetch from "@trim21/gm-fetch";
declare function waitForKeyElements(selectorOrFunction: any, callback: any, waitOnce: boolean): any;