diff --git a/README.md b/README.md
index 809de75..e46d88a 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ npm install @cityssm/faster-url-builder
import { FasterUrlBuilder } from '@cityssm/faster-url-builder'
console.log(new FasterUrlBuilder('test-tenant').loginUrl)
-// => https://test-tenant.fasterwebcloud.com/FASTER
+// => https://test-tenant.fasterwebcloud.com/FASTER/Login
```
## Included URLs
@@ -40,8 +40,8 @@ console.log(new FasterUrlBuilder('test-tenant').loginUrl)
## Related Projects
-[FASTER Web Report Exporter](https://github.com/cityssm/node-faster-report-exporter)
+[**FASTER Web Report Exporter**](https://github.com/cityssm/node-faster-report-exporter)
On demand exports of selected reports from the FASTER Web Fleet Management System.
-[FASTER Web Helper](https://github.com/cityssm/faster-web-helper)
+[**FASTER Web Helper**](https://github.com/cityssm/faster-web-helper)
A service to support integrations with the FASTER Web fleet management system.
diff --git a/eslint.config.d.ts b/eslint.config.d.ts
index 29528c9..a1905cc 100644
--- a/eslint.config.d.ts
+++ b/eslint.config.d.ts
@@ -1 +1,3 @@
-export { default } from 'eslint-config-cityssm';
+import { type Config } from 'eslint-config-cityssm';
+declare const config: Config;
+export default config;
diff --git a/eslint.config.js b/eslint.config.js
index 29528c9..fa3adae 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1 +1,14 @@
-export { default } from 'eslint-config-cityssm';
+import eslintConfigCityssm, { cspellWords, tseslint } from 'eslint-config-cityssm';
+const config = tseslint.config(...eslintConfigCityssm, {
+ rules: {
+ '@cspell/spellchecker': [
+ 'warn',
+ {
+ cspell: {
+ words: [...cspellWords, 'fasterwebcloud']
+ }
+ }
+ ]
+ }
+});
+export default config;
diff --git a/eslint.config.ts b/eslint.config.ts
index a6257c1..24890e2 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -1 +1,20 @@
-export { default } from 'eslint-config-cityssm'
+import eslintConfigCityssm, {
+ type Config,
+ cspellWords,
+ tseslint
+} from 'eslint-config-cityssm'
+
+const config = tseslint.config(...eslintConfigCityssm, {
+ rules: {
+ '@cspell/spellchecker': [
+ 'warn',
+ {
+ cspell: {
+ words: [...cspellWords, 'fasterwebcloud']
+ }
+ }
+ ]
+ }
+}) as Config
+
+export default config
diff --git a/index.d.ts b/index.d.ts
index 03583e8..d515f65 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,4 +1,10 @@
-type FasterBaseUrl = `https://${string}.fasterwebcloud.com/FASTER`;
+export type FasterBaseUrl = `https://${string}.fasterwebcloud.com/FASTER`;
+/**
+ * Tests if a base URL is valid.
+ * @param fasterBaseUrl - A possible FASTER Web base URL.
+ * @returns `true` if the base URL is valid.
+ */
+export declare function isValidBaseUrl(fasterBaseUrl: string): fasterBaseUrl is FasterBaseUrl;
export declare class FasterUrlBuilder {
#private;
/** Base URL */
@@ -9,9 +15,10 @@ export declare class FasterUrlBuilder {
readonly reportViewerUrl: `${FasterBaseUrl}/Domains/Reports/ReportViewer.aspx`;
/**
* Initializes the FasterUrlBuilder
- * @param fasterTenant - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * @param fasterTenantOrBaseUrl - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * or the full domain and path including "/FASTER"
*/
- constructor(fasterTenant: string);
+ constructor(fasterTenantOrBaseUrl: string);
/**
* Builds a URL for the inventory search.
* @param searchString - Item number search string
diff --git a/index.js b/index.js
index 97c855f..8b813f7 100644
--- a/index.js
+++ b/index.js
@@ -1,23 +1,39 @@
+/**
+ * Tests if a base URL is valid.
+ * @param fasterBaseUrl - A possible FASTER Web base URL.
+ * @returns `true` if the base URL is valid.
+ */
+export function isValidBaseUrl(fasterBaseUrl) {
+ return (fasterBaseUrl.startsWith('https://') && fasterBaseUrl.endsWith('/FASTER'));
+}
export class FasterUrlBuilder {
/** Base URL */
baseUrl;
/** Login URL */
loginUrl;
#inventorySearchUrl;
+ // eslint-disable-next-line no-secrets/no-secrets
#workOrderSearchUrl;
#workOrderUrl;
/** Report Viewer URL - Parameters required */
reportViewerUrl;
/**
* Initializes the FasterUrlBuilder
- * @param fasterTenant - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * @param fasterTenantOrBaseUrl - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * or the full domain and path including "/FASTER"
*/
- constructor(fasterTenant) {
- this.baseUrl = `https://${fasterTenant}.fasterwebcloud.com/FASTER`;
+ constructor(fasterTenantOrBaseUrl) {
+ this.baseUrl = fasterTenantOrBaseUrl.startsWith('https')
+ ? fasterTenantOrBaseUrl
+ : `https://${fasterTenantOrBaseUrl}.fasterwebcloud.com/FASTER`;
+ if (!isValidBaseUrl(this.baseUrl)) {
+ throw new Error(`Invalid base URL: ${this.baseUrl}`);
+ }
this.loginUrl = `${this.baseUrl}/Login`;
/* Inventory */
this.#inventorySearchUrl = `${this.baseUrl}/Domains/Parts/Search/Default.aspx?xact=False&type=False&str=`;
/* Maintenance */
+ // eslint-disable-next-line no-secrets/no-secrets
this.#workOrderSearchUrl = `${this.baseUrl}/Domains/Maintenance/WorkOrder/Search/Default.aspx?xact=False&type=False&str=`;
this.#workOrderUrl = `${this.baseUrl}/Domains/Maintenance/WorkOrder/WorkOrderMaster.aspx?workOrderID=`;
/* Reports */
diff --git a/index.ts b/index.ts
index c0c33e0..bb8f220 100644
--- a/index.ts
+++ b/index.ts
@@ -1,4 +1,17 @@
-type FasterBaseUrl = `https://${string}.fasterwebcloud.com/FASTER`
+export type FasterBaseUrl = `https://${string}.fasterwebcloud.com/FASTER`
+
+/**
+ * Tests if a base URL is valid.
+ * @param fasterBaseUrl - A possible FASTER Web base URL.
+ * @returns `true` if the base URL is valid.
+ */
+export function isValidBaseUrl(
+ fasterBaseUrl: string
+): fasterBaseUrl is FasterBaseUrl {
+ return (
+ fasterBaseUrl.startsWith('https://') && fasterBaseUrl.endsWith('/FASTER')
+ )
+}
export class FasterUrlBuilder {
/** Base URL */
@@ -9,6 +22,7 @@ export class FasterUrlBuilder {
readonly #inventorySearchUrl: `${FasterBaseUrl}/Domains/Parts/Search/Default.aspx?xact=False&type=False&str=`
+ // eslint-disable-next-line no-secrets/no-secrets
readonly #workOrderSearchUrl: `${FasterBaseUrl}/Domains/Maintenance/WorkOrder/Search/Default.aspx?xact=False&type=False&str=`
readonly #workOrderUrl: `${FasterBaseUrl}/Domains/Maintenance/WorkOrder/WorkOrderMaster.aspx?workOrderID=`
@@ -17,16 +31,25 @@ export class FasterUrlBuilder {
/**
* Initializes the FasterUrlBuilder
- * @param fasterTenant - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * @param fasterTenantOrBaseUrl - The subdomain of the FASTER Web URL before ".fasterwebcloud.com"
+ * or the full domain and path including "/FASTER"
*/
- constructor(fasterTenant: string) {
- this.baseUrl = `https://${fasterTenant}.fasterwebcloud.com/FASTER`
+ constructor(fasterTenantOrBaseUrl: string) {
+ this.baseUrl = fasterTenantOrBaseUrl.startsWith('https')
+ ? (fasterTenantOrBaseUrl as FasterBaseUrl)
+ : `https://${fasterTenantOrBaseUrl}.fasterwebcloud.com/FASTER`
+
+ if (!isValidBaseUrl(this.baseUrl)) {
+ throw new Error(`Invalid base URL: ${this.baseUrl as string}`)
+ }
+
this.loginUrl = `${this.baseUrl}/Login`
/* Inventory */
this.#inventorySearchUrl = `${this.baseUrl}/Domains/Parts/Search/Default.aspx?xact=False&type=False&str=`
/* Maintenance */
+ // eslint-disable-next-line no-secrets/no-secrets
this.#workOrderSearchUrl = `${this.baseUrl}/Domains/Maintenance/WorkOrder/Search/Default.aspx?xact=False&type=False&str=`
this.#workOrderUrl = `${this.baseUrl}/Domains/Maintenance/WorkOrder/WorkOrderMaster.aspx?workOrderID=`
diff --git a/package-lock.json b/package-lock.json
index f76c543..43c3246 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "@cityssm/faster-url-builder",
- "version": "0.1.0",
+ "version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@cityssm/faster-url-builder",
- "version": "0.1.0",
+ "version": "0.2.0",
"license": "MIT",
"devDependencies": {
- "@types/node": "^22.9.0",
+ "@types/node": "^22.9.1",
"eslint-config-cityssm": "^15.2.0",
"prettier-config-cityssm": "^1.0.0"
}
@@ -3092,9 +3092,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.9.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
- "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
+ "version": "22.9.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz",
+ "integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==",
"dev": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index f8ea9e8..22b479d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@cityssm/faster-url-builder",
"type": "module",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "Builds URLs for the FASTER Web Fleet Management System",
"exports": "./index.js",
"scripts": {
@@ -22,7 +22,7 @@
},
"homepage": "https://github.com/cityssm/node-faster-url-builder#readme",
"devDependencies": {
- "@types/node": "^22.9.0",
+ "@types/node": "^22.9.1",
"eslint-config-cityssm": "^15.2.0",
"prettier-config-cityssm": "^1.0.0"
}
diff --git a/test/test.js b/test/test.js
index 9f97bd6..1d67b5e 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,10 +1,15 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
-import { FasterUrlBuilder } from '../index.js';
+import { FasterUrlBuilder, isValidBaseUrl } from '../index.js';
await describe('faster-url-builder', async () => {
const tenant = 'faster-tenant';
const fasterUrlBuilder = new FasterUrlBuilder(tenant);
- await it('Constructs a proper base URL', () => {
+ await it('Initializes with a full base URL', () => {
+ const testBaseUrl = 'https://test.example.com/FASTER';
+ const fasterUrlBuilderFromUrl = new FasterUrlBuilder(testBaseUrl);
+ assert.strictEqual(fasterUrlBuilderFromUrl.baseUrl, testBaseUrl);
+ });
+ await it('Constructs a proper base URL from a tenant', () => {
assert(fasterUrlBuilder.baseUrl.includes(tenant));
});
await it('Constructs a proper login URL', () => {
@@ -32,3 +37,22 @@ await describe('faster-url-builder', async () => {
assert(workOrderUrl.endsWith(workOrderNumber.toString()));
});
});
+await describe('faster-url-builder/errors', async () => {
+ await it('Rejects invalid base URLs', () => {
+ // http link
+ assert.strictEqual(isValidBaseUrl('http://test.example.com/FASTER'), false);
+ // missing "/FASTER"
+ assert.strictEqual(isValidBaseUrl('https://test.example.com'), false);
+ let declaredSuccessfully = false;
+ // eslint-disable-next-line @typescript-eslint/init-declarations
+ let builder;
+ try {
+ builder = new FasterUrlBuilder('https://test.example.com/FASTE');
+ declaredSuccessfully = true;
+ }
+ catch { }
+ if (declaredSuccessfully) {
+ assert.fail(`URL builder declared successfully with invalid URL: ${builder.baseUrl}`);
+ }
+ });
+});
diff --git a/test/test.ts b/test/test.ts
index bd6b7de..15371bf 100644
--- a/test/test.ts
+++ b/test/test.ts
@@ -1,13 +1,19 @@
import assert from 'node:assert'
import { describe, it } from 'node:test'
-import { FasterUrlBuilder } from '../index.js'
+import { FasterUrlBuilder, isValidBaseUrl } from '../index.js'
await describe('faster-url-builder', async () => {
const tenant = 'faster-tenant'
const fasterUrlBuilder = new FasterUrlBuilder(tenant)
- await it('Constructs a proper base URL', () => {
+ await it('Initializes with a full base URL', () => {
+ const testBaseUrl = 'https://test.example.com/FASTER'
+ const fasterUrlBuilderFromUrl = new FasterUrlBuilder(testBaseUrl)
+ assert.strictEqual(fasterUrlBuilderFromUrl.baseUrl, testBaseUrl)
+ })
+
+ await it('Constructs a proper base URL from a tenant', () => {
assert(fasterUrlBuilder.baseUrl.includes(tenant))
})
@@ -51,3 +57,28 @@ await describe('faster-url-builder', async () => {
assert(workOrderUrl.endsWith(workOrderNumber.toString()))
})
})
+
+await describe('faster-url-builder/errors', async () => {
+ await it('Rejects invalid base URLs', () => {
+ // http link
+ assert.strictEqual(isValidBaseUrl('http://test.example.com/FASTER'), false)
+
+ // missing "/FASTER"
+ assert.strictEqual(isValidBaseUrl('https://test.example.com'), false)
+
+ let declaredSuccessfully = false
+
+ // eslint-disable-next-line @typescript-eslint/init-declarations
+ let builder: FasterUrlBuilder | undefined
+
+ try {
+ builder = new FasterUrlBuilder('https://test.example.com/FASTE')
+ declaredSuccessfully = true
+ } catch {}
+ if (declaredSuccessfully) {
+ assert.fail(
+ `URL builder declared successfully with invalid URL: ${(builder as FasterUrlBuilder).baseUrl}`
+ )
+ }
+ })
+})