matrix-appservice
Advanced tools
Comparing version 0.6.0 to 0.7.0
@@ -1,4 +0,13 @@ | ||
0.6.0 (2020-10-08) | ||
0.7.0 (2020-10-30) | ||
=================== | ||
Bugfixes | ||
-------- | ||
- Fix issue where `AppServiceRegistration.getOutput()` would fail if `de.sorunome.msc2409.push_ephemeral` is undefined. ([\#34](https://github.com/matrix-org/matrix-appservice-node/issues/34)) | ||
0.6.0 (2020-10-08) | ||
=================== | ||
Features | ||
@@ -5,0 +14,0 @@ -------- |
@@ -5,2 +5,17 @@ interface RegexObj { | ||
} | ||
interface AppServiceOutput { | ||
url: string | null; | ||
id: string; | ||
hs_token: string; | ||
as_token: string; | ||
sender_localpart: string; | ||
rate_limited?: boolean; | ||
protocols?: string[] | null; | ||
"de.sorunome.msc2409.push_ephemeral"?: boolean; | ||
namespaces?: { | ||
users?: RegexObj[]; | ||
rooms?: RegexObj[]; | ||
aliases?: RegexObj[]; | ||
}; | ||
} | ||
export declare class AppServiceRegistration { | ||
@@ -16,7 +31,6 @@ private url; | ||
* @static | ||
* @param {Object} obj The registration object | ||
* @return {?AppServiceRegistration} The registration or null if the object | ||
* cannot be coerced into a registration. | ||
* @param obj The registration object | ||
* @return The registration. | ||
*/ | ||
static fromObject(obj: any): AppServiceRegistration | null; | ||
static fromObject(obj: AppServiceOutput): AppServiceRegistration; | ||
/** | ||
@@ -36,7 +50,7 @@ * Construct a new application service registration. | ||
*/ | ||
pushEphemeral: boolean; | ||
pushEphemeral: boolean | undefined; | ||
private namespaces; | ||
private protocols; | ||
private cachedRegex; | ||
constructor(url: string); | ||
constructor(url: string | null); | ||
/** | ||
@@ -48,2 +62,6 @@ * Set the URL which the home server will hit in order to talk to the AS. | ||
/** | ||
* Get the URL which the home server will hit in order to talk to the AS. | ||
*/ | ||
getAppServiceUrl(): string | null; | ||
/** | ||
* Set the ID of the appservice; must be unique across the homeserver and never change. | ||
@@ -95,2 +113,6 @@ * @param {string} id The ID | ||
/** | ||
* Get whether requests from this AS are rate-limited by the home server. | ||
*/ | ||
isRateLimited(): boolean; | ||
/** | ||
* Set whether requests from this AS are rate-limited by the home server. | ||
@@ -102,2 +124,9 @@ * @param {boolean} isRateLimited The flag which is set to true to enable rate | ||
/** | ||
* **Experimental** | ||
* | ||
* Should the appservice receive ephemeral events. Note this requires | ||
* a homeserver implementing MSC2409. | ||
*/ | ||
pushEphemeralEnabled(): boolean; | ||
/** | ||
* Get the desired user_id localpart for the app service itself. | ||
@@ -124,20 +153,5 @@ * @return {?string} The user_id localpart ("alice" in "@alice:domain") | ||
* Get the key-value output which should be written to a YAML file. | ||
* @return {Object} | ||
* @throws If required fields hs_token, as-token, url, sender_localpart are missing. | ||
*/ | ||
getOutput(): { | ||
id: string; | ||
hs_token: string; | ||
as_token: string; | ||
namespaces: { | ||
users: RegexObj[]; | ||
aliases: RegexObj[]; | ||
rooms: RegexObj[]; | ||
}; | ||
url: string; | ||
sender_localpart: string; | ||
rate_limited: boolean; | ||
protocols: string[] | null; | ||
"de.sorunome.msc2409.push_ephemeral": boolean; | ||
}; | ||
getOutput(): AppServiceOutput; | ||
/** | ||
@@ -167,4 +181,4 @@ * Check if a user_id meets this registration regex. | ||
isRoomMatch(roomId: string, onlyExclusive: boolean): boolean; | ||
_isMatch(regexList: RegexObj[], sample: string, onlyExclusive: boolean): boolean; | ||
_isMatch(regexList: RegexObj[] | undefined, sample: string, onlyExclusive: boolean): boolean; | ||
} | ||
export {}; |
@@ -22,3 +22,3 @@ "use strict"; | ||
this.senderLocalpart = null; | ||
this.rateLimited = true; | ||
this.rateLimited = undefined; | ||
/** | ||
@@ -28,4 +28,4 @@ * **Experimental** | ||
*/ | ||
this.pushEphemeral = false; | ||
this.namespaces = { users: [], aliases: [], rooms: [] }; | ||
this.pushEphemeral = undefined; | ||
this.namespaces = {}; | ||
this.protocols = null; | ||
@@ -44,11 +44,6 @@ this.cachedRegex = {}; | ||
* @static | ||
* @param {Object} obj The registration object | ||
* @return {?AppServiceRegistration} The registration or null if the object | ||
* cannot be coerced into a registration. | ||
* @param obj The registration object | ||
* @return The registration. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
static fromObject(obj) { | ||
if (!obj.url) { | ||
return null; | ||
} | ||
const reg = new AppServiceRegistration(obj.url); | ||
@@ -59,15 +54,18 @@ reg.setId(obj.id); | ||
reg.setSenderLocalpart(obj.sender_localpart); | ||
reg.setRateLimited(obj.rate_limited); | ||
reg.setProtocols(obj.protocols); | ||
if (obj.rate_limited !== undefined) | ||
reg.setRateLimited(obj.rate_limited); | ||
if (obj.protocols) | ||
reg.setProtocols(obj.protocols); | ||
reg.pushEphemeral = obj["de.sorunome.msc2409.push_ephemeral"]; | ||
if (obj.namespaces) { | ||
const kinds = ["users", "aliases", "rooms"]; | ||
kinds.forEach((kind) => { | ||
if (!obj.namespaces[kind]) { | ||
return; | ||
for (const kind of kinds) { | ||
const namespace = obj.namespaces[kind]; | ||
if (!namespace) { | ||
continue; | ||
} | ||
obj.namespaces[kind].forEach((regexObj) => { | ||
namespace.forEach((regexObj) => { | ||
reg.addRegexPattern(kind, regexObj.regex, regexObj.exclusive); | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -84,2 +82,8 @@ return reg; | ||
/** | ||
* Get the URL which the home server will hit in order to talk to the AS. | ||
*/ | ||
getAppServiceUrl() { | ||
return this.url; | ||
} | ||
/** | ||
* Set the ID of the appservice; must be unique across the homeserver and never change. | ||
@@ -149,2 +153,8 @@ * @param {string} id The ID | ||
/** | ||
* Get whether requests from this AS are rate-limited by the home server. | ||
*/ | ||
isRateLimited() { | ||
return this.rateLimited === undefined ? true : this.rateLimited; | ||
} | ||
/** | ||
* Set whether requests from this AS are rate-limited by the home server. | ||
@@ -158,2 +168,11 @@ * @param {boolean} isRateLimited The flag which is set to true to enable rate | ||
/** | ||
* **Experimental** | ||
* | ||
* Should the appservice receive ephemeral events. Note this requires | ||
* a homeserver implementing MSC2409. | ||
*/ | ||
pushEphemeralEnabled() { | ||
return this.pushEphemeral || false; | ||
} | ||
/** | ||
* Get the desired user_id localpart for the app service itself. | ||
@@ -184,3 +203,9 @@ * @return {?string} The user_id localpart ("alice" in "@alice:domain") | ||
}; | ||
this.namespaces[type].push(regexObject); | ||
const namespace = this.namespaces[type]; | ||
if (namespace) { | ||
namespace.push(regexObject); | ||
} | ||
else { | ||
this.namespaces[type] = [regexObject]; | ||
} | ||
} | ||
@@ -198,20 +223,37 @@ /** | ||
* Get the key-value output which should be written to a YAML file. | ||
* @return {Object} | ||
* @throws If required fields hs_token, as-token, url, sender_localpart are missing. | ||
*/ | ||
getOutput() { | ||
if (!this.id || !this.hsToken || !this.asToken || !this.url || !this.senderLocalpart) { | ||
throw new Error("Missing required field(s): id, hs_token, as_token, url, sender_localpart"); | ||
// Typescript will default any string array to a set of strings, even if it's a static array. | ||
const requiredFields = [ | ||
"id", "hsToken", "asToken", "senderLocalpart" | ||
]; | ||
const missingFields = requiredFields.filter((key) => !this[key]); | ||
if (missingFields.length) { | ||
throw new Error(`Missing required field(s): ${missingFields}`); | ||
} | ||
return { | ||
const responseFormat = { | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
id: this.id, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
hs_token: this.hsToken, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
as_token: this.asToken, | ||
namespaces: this.namespaces, | ||
url: this.url, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
sender_localpart: this.senderLocalpart, | ||
rate_limited: this.rateLimited, | ||
protocols: this.protocols, | ||
"de.sorunome.msc2409.push_ephemeral": this.pushEphemeral, | ||
}; | ||
if (this.pushEphemeral !== undefined) { | ||
responseFormat["de.sorunome.msc2409.push_ephemeral"] = this.pushEphemeral; | ||
} | ||
if (this.protocols) { | ||
responseFormat.protocols = this.protocols; | ||
} | ||
if (Object.keys(this.namespaces).length > 0) { | ||
responseFormat.namespaces = this.namespaces; | ||
} | ||
if (this.rateLimited !== undefined) { | ||
responseFormat.rate_limited = this.rateLimited; | ||
} | ||
return responseFormat; | ||
} | ||
@@ -249,2 +291,5 @@ /** | ||
_isMatch(regexList, sample, onlyExclusive) { | ||
if (!regexList) { | ||
return false; | ||
} | ||
onlyExclusive = Boolean(onlyExclusive); | ||
@@ -251,0 +296,0 @@ for (const regexObj of regexList) { |
{ | ||
"name": "matrix-appservice", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "Matrix Application Service Framework", | ||
@@ -12,3 +12,3 @@ "main": "lib/index.js", | ||
"gendoc": "typedoc", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"test": "mocha -r ts-node/register test/*.ts", | ||
"lint": "eslint -c .eslintrc --max-warnings 0 src/**/*.ts", | ||
@@ -35,3 +35,5 @@ "build": "tsc --project tsconfig.json", | ||
"@types/body-parser": "^1.19.0", | ||
"@types/chai": "^4.2.14", | ||
"@types/js-yaml": "^3.12.5", | ||
"@types/mocha": "^8.0.3", | ||
"@types/morgan": "^1.9.1", | ||
@@ -41,3 +43,6 @@ "@types/node": "^10.17.29", | ||
"@typescript-eslint/parser": "^3.10.1", | ||
"chai": "^4.2.0", | ||
"eslint": "^7.8.1", | ||
"mocha": "^8.2.0", | ||
"ts-node": "^9.0.0", | ||
"typedoc": "^0.19.1", | ||
@@ -44,0 +49,0 @@ "typescript": "^3.9.7" |
@@ -10,2 +10,22 @@ import { randomBytes } from "crypto"; | ||
interface AppServiceOutput { | ||
url: string|null; | ||
id: string; | ||
// eslint-disable-next-line camelcase | ||
hs_token: string; | ||
// eslint-disable-next-line camelcase | ||
as_token: string; | ||
// eslint-disable-next-line camelcase | ||
sender_localpart: string; | ||
// eslint-disable-next-line camelcase | ||
rate_limited?: boolean; | ||
protocols?: string[]|null; | ||
"de.sorunome.msc2409.push_ephemeral"?: boolean; | ||
namespaces?: { | ||
users?: RegexObj[]; | ||
rooms?: RegexObj[]; | ||
aliases?: RegexObj[]; | ||
} | ||
} | ||
export class AppServiceRegistration { | ||
@@ -24,11 +44,6 @@ | ||
* @static | ||
* @param {Object} obj The registration object | ||
* @return {?AppServiceRegistration} The registration or null if the object | ||
* cannot be coerced into a registration. | ||
* @param obj The registration object | ||
* @return The registration. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public static fromObject(obj: any): AppServiceRegistration|null { | ||
if (!obj.url) { | ||
return null; | ||
} | ||
public static fromObject(obj: AppServiceOutput): AppServiceRegistration { | ||
const reg = new AppServiceRegistration(obj.url); | ||
@@ -39,17 +54,18 @@ reg.setId(obj.id); | ||
reg.setSenderLocalpart(obj.sender_localpart); | ||
reg.setRateLimited(obj.rate_limited); | ||
reg.setProtocols(obj.protocols); | ||
if (obj.rate_limited !== undefined) reg.setRateLimited(obj.rate_limited); | ||
if (obj.protocols) reg.setProtocols(obj.protocols); | ||
reg.pushEphemeral = obj["de.sorunome.msc2409.push_ephemeral"]; | ||
if (obj.namespaces) { | ||
const kinds = ["users", "aliases", "rooms"]; | ||
kinds.forEach((kind) => { | ||
if (!obj.namespaces[kind]) { | ||
return; | ||
const kinds: ("users"|"aliases"|"rooms")[] = ["users", "aliases", "rooms"]; | ||
for (const kind of kinds) { | ||
const namespace = obj.namespaces[kind]; | ||
if (!namespace) { | ||
continue; | ||
} | ||
obj.namespaces[kind].forEach((regexObj: RegexObj) => { | ||
namespace.forEach((regexObj: RegexObj) => { | ||
reg.addRegexPattern( | ||
kind as "users"|"aliases"|"rooms", regexObj.regex, regexObj.exclusive, | ||
kind, regexObj.regex, regexObj.exclusive, | ||
); | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -68,3 +84,3 @@ return reg; | ||
private senderLocalpart: string|null = null; | ||
private rateLimited = true; | ||
private rateLimited: boolean|undefined = undefined; | ||
/** | ||
@@ -74,11 +90,11 @@ * **Experimental** | ||
*/ | ||
public pushEphemeral = false; | ||
public pushEphemeral: boolean|undefined = undefined; | ||
private namespaces: { | ||
users: RegexObj[]; | ||
aliases: RegexObj[]; | ||
rooms: RegexObj[]; | ||
} = { users: [], aliases: [], rooms: []}; | ||
users?: RegexObj[]; | ||
aliases?: RegexObj[]; | ||
rooms?: RegexObj[]; | ||
} = {}; | ||
private protocols: string[]|null = null; | ||
private cachedRegex: {[regextext: string]: RegExp} = {}; | ||
constructor (private url: string) { } | ||
constructor (private url: string|null) { } | ||
@@ -94,2 +110,9 @@ /** | ||
/** | ||
* Get the URL which the home server will hit in order to talk to the AS. | ||
*/ | ||
public getAppServiceUrl() { | ||
return this.url; | ||
} | ||
/** | ||
* Set the ID of the appservice; must be unique across the homeserver and never change. | ||
@@ -168,2 +191,9 @@ * @param {string} id The ID | ||
/** | ||
* Get whether requests from this AS are rate-limited by the home server. | ||
*/ | ||
public isRateLimited() { | ||
return this.rateLimited === undefined ? true : this.rateLimited; | ||
} | ||
/** | ||
* Set whether requests from this AS are rate-limited by the home server. | ||
@@ -178,2 +208,12 @@ * @param {boolean} isRateLimited The flag which is set to true to enable rate | ||
/** | ||
* **Experimental** | ||
* | ||
* Should the appservice receive ephemeral events. Note this requires | ||
* a homeserver implementing MSC2409. | ||
*/ | ||
public pushEphemeralEnabled() { | ||
return this.pushEphemeral || false; | ||
} | ||
/** | ||
* Get the desired user_id localpart for the app service itself. | ||
@@ -207,3 +247,8 @@ * @return {?string} The user_id localpart ("alice" in "@alice:domain") | ||
this.namespaces[type].push(regexObject); | ||
const namespace = this.namespaces[type]; | ||
if (namespace) { | ||
namespace.push(regexObject); | ||
} else { | ||
this.namespaces[type] = [regexObject]; | ||
} | ||
} | ||
@@ -223,22 +268,39 @@ | ||
* Get the key-value output which should be written to a YAML file. | ||
* @return {Object} | ||
* @throws If required fields hs_token, as-token, url, sender_localpart are missing. | ||
*/ | ||
public getOutput() { | ||
if (!this.id || !this.hsToken || !this.asToken || !this.url || !this.senderLocalpart) { | ||
public getOutput(): AppServiceOutput { | ||
// Typescript will default any string array to a set of strings, even if it's a static array. | ||
const requiredFields: ("id"|"hsToken"|"asToken"|"senderLocalpart")[] = [ | ||
"id", "hsToken", "asToken", "senderLocalpart" | ||
]; | ||
const missingFields = requiredFields.filter((key) => !this[key]); | ||
if (missingFields.length) { | ||
throw new Error( | ||
"Missing required field(s): id, hs_token, as_token, url, sender_localpart" | ||
`Missing required field(s): ${missingFields}` | ||
); | ||
} | ||
return { | ||
id: this.id, | ||
hs_token: this.hsToken, | ||
as_token: this.asToken, | ||
namespaces: this.namespaces, | ||
const responseFormat: AppServiceOutput = { | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
id: this.id!, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
hs_token: this.hsToken!, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
as_token: this.asToken!, | ||
url: this.url, | ||
sender_localpart: this.senderLocalpart, | ||
rate_limited: this.rateLimited, | ||
protocols: this.protocols, | ||
"de.sorunome.msc2409.push_ephemeral": this.pushEphemeral, | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
sender_localpart: this.senderLocalpart!, | ||
}; | ||
if (this.pushEphemeral !== undefined) { | ||
responseFormat["de.sorunome.msc2409.push_ephemeral"] = this.pushEphemeral; | ||
} | ||
if (this.protocols) { | ||
responseFormat.protocols = this.protocols; | ||
} | ||
if (Object.keys(this.namespaces).length > 0) { | ||
responseFormat.namespaces = this.namespaces; | ||
} | ||
if(this.rateLimited !== undefined) { | ||
responseFormat.rate_limited = this.rateLimited; | ||
} | ||
return responseFormat; | ||
} | ||
@@ -279,3 +341,6 @@ | ||
public _isMatch(regexList: RegexObj[], sample: string, onlyExclusive: boolean) { | ||
public _isMatch(regexList: RegexObj[]|undefined, sample: string, onlyExclusive: boolean) { | ||
if (!regexList) { | ||
return false; | ||
} | ||
onlyExclusive = Boolean(onlyExclusive); | ||
@@ -282,0 +347,0 @@ for (const regexObj of regexList) { |
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
76739
20
1591
2
14