Compare commits

14 Commits

Author SHA1 Message Date
d10dabf604 Adjust generateGeohash from static to standard method to support singleton approach in Svelte without additonal import/exports
All checks were successful
Publish Package / build-and-publish (push) Successful in 3s
2026-03-30 22:57:57 +01:00
26886f8a7d Fix pathing to stationDate.js file
All checks were successful
Publish Package / build-and-publish (push) Successful in 3s
2026-03-30 22:52:09 +01:00
46dcf65de6 Ensure StationDataModule is exported
All checks were successful
Publish Package / build-and-publish (push) Successful in 2s
2026-03-30 22:49:53 +01:00
d160ad87f9 Ensure staitionData module is available in Client
All checks were successful
Publish Package / build-and-publish (push) Successful in 2s
2026-03-30 22:11:33 +01:00
fc74e933d6 Add StationDataModule, implementing getNearestStations & a Geohash generator method
All checks were successful
Publish Package / build-and-publish (push) Successful in 6s
2026-03-30 21:53:01 +01:00
ad355fe15e Re-export API Schema types
All checks were successful
Publish Package / build-and-publish (push) Successful in 4s
2026-03-25 10:22:34 +00:00
4dd8bd1108 Fix import paths
All checks were successful
Publish Package / build-and-publish (push) Successful in 3s
2026-03-24 12:40:07 +00:00
e2f4433042 Add LocationFilterModule
All checks were successful
Publish Package / build-and-publish (push) Successful in 7s
2026-03-24 00:53:29 +00:00
7775abbbca Adjust tagging strategy
All checks were successful
Publish Package / build-and-publish (push) Successful in 7s
2026-03-19 20:04:21 +00:00
f340c57ffd Ensure dynamic versioning for NPM pubslishing
Some checks failed
Publish Package / build-and-publish (push) Failing after 5s
2026-03-19 19:55:47 +00:00
6c6a603cd8 Ensure all paths are relative
Some checks failed
Publish Package / build-and-publish (push) Failing after 7s
2026-03-19 19:51:41 +00:00
35167f1853 And again...
All checks were successful
Publish Package / build-and-publish (push) Successful in 7s
2026-03-19 10:52:46 +00:00
815ae473db Try again
Some checks failed
Publish Package / build-and-publish (push) Failing after 6s
2026-03-19 10:49:43 +00:00
ff3052f3b0 Fix casing in NPM configuration for build/push job
Some checks failed
Publish Package / build-and-publish (push) Failing after 5s
2026-03-19 10:46:12 +00:00
10 changed files with 121 additions and 25 deletions

View File

@@ -20,7 +20,7 @@ jobs:
with: with:
node-version: 20 node-version: 20
registry-url: 'https://git.fjla.uk/api/packages/owlboard/npm' registry-url: 'https://git.fjla.uk/api/packages/owlboard/npm'
scope: '@owlboard' scope: '@OwlBoard'
- name: Install Dependencies - name: Install Dependencies
run: npm ci run: npm ci
@@ -28,12 +28,10 @@ jobs:
- name: Build - name: Build
run: npm run build run: npm run build
# - name: Publish to NPM
# run: npm publish --access public
# env:
# NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish to Gitea Repo - name: Publish to Gitea Repo
run: | run: |
VERSION=${GITHUB_REF_NAME#v}
npm version $VERSION --no-git-tag-version
npm config set //git.fjla.uk/api/packages/owlboard/npm/:_authToken ${{ secrets.REPO_TOKEN }} npm config set //git.fjla.uk/api/packages/owlboard/npm/:_authToken ${{ secrets.REPO_TOKEN }}
npm config set //git.fjla.uk/api/packages/OwlBoard/npm/:_authToken ${{ secrets.REPO_TOKEN }}
npm publish --registry=https://git.fjla.uk npm publish --registry=https://git.fjla.uk

30
package-lock.json generated
View File

@@ -1,15 +1,19 @@
{ {
"name": "owlboard-ts", "name": "@owlboard/owlboard-ts",
"version": "3.0.0", "version": "3.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "owlboard-ts", "name": "@owlboard/owlboard-ts",
"version": "3.0.0", "version": "3.0.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": {
"@owlboard/api-schema-types": "^3.0.2-alpha3",
"latlon-geohash": "^2.0.0"
},
"devDependencies": { "devDependencies": {
"@owlboard/api-schema-types": "^3.0.1-alpha3", "@types/latlon-geohash": "^2.0.4",
"@types/node": "^25.3.0", "@types/node": "^25.3.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsx": "^4.21.0", "tsx": "^4.21.0",
@@ -500,10 +504,9 @@
} }
}, },
"node_modules/@owlboard/api-schema-types": { "node_modules/@owlboard/api-schema-types": {
"version": "3.0.1-alpha3", "version": "3.0.2-alpha3",
"resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fapi-schema-types/-/3.0.1-alpha3/api-schema-types-3.0.1-alpha3.tgz", "resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fapi-schema-types/-/3.0.2-alpha3/api-schema-types-3.0.2-alpha3.tgz",
"integrity": "sha512-5CVm1k/C++/VrtAw4NkvclDunH+RmYLnDZZMSWTM1mm+WlEVnmD+MVnTgC/FhcsAmsNHV8swm66RCqkCuhbOnA==", "integrity": "sha512-3NFP21QdSfjziwlGQixlNnUWC55HlKZGyWANIOimWu0FZejWQWExJiaAVfb6m3Sbv+zvQMu3B8mzcMCcGadZCQ==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@tsconfig/node10": { "node_modules/@tsconfig/node10": {
@@ -534,6 +537,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/latlon-geohash": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/latlon-geohash/-/latlon-geohash-2.0.4.tgz",
"integrity": "sha512-R/wb/V8lhhI0hyRGDTkT6F4C3lynkF/D29iMSN5B4bYswaa4R+wajgcTv9z73BotGArf4Q8BnDNtmLeI+WiKkQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "25.3.0", "version": "25.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz",
@@ -664,6 +674,12 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
} }
}, },
"node_modules/latlon-geohash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/latlon-geohash/-/latlon-geohash-2.0.0.tgz",
"integrity": "sha512-OKBswTwrvTdtenV+9C9euBmvgGuqyjJNAzpQCarRz1m8/pYD2nz9fKkXmLs2S3jeXaLi3Ry76twQplKKUlgS/g==",
"license": "MIT"
},
"node_modules/make-error": { "node_modules/make-error": {
"version": "1.3.6", "version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",

View File

@@ -6,7 +6,9 @@
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"files": ["dist"], "files": [
"dist"
],
"exports": { "exports": {
".": { ".": {
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
@@ -28,9 +30,11 @@
"author": "Frederick Boniface", "author": "Frederick Boniface",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"@owlboard/api-schema-types": "^3.0.1-alpha3" "@owlboard/api-schema-types": "^3.0.2-alpha3",
"latlon-geohash": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/latlon-geohash": "^2.0.4",
"@types/node": "^25.3.0", "@types/node": "^25.3.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsx": "^4.21.0", "tsx": "^4.21.0",

View File

@@ -1,5 +1,10 @@
export * from './lib/base.js'; export { OwlBoardClient } from './lib/client.js';
export * from './lib/client.js'; export { ValidationError, ApiError } from './lib/errors.js';
export * from './lib/errors.js';
export * from './modules/pis.js'; // Re-export API Schema types
export type * from '@owlboard/api-schema-types'
// Useful exports for Type Hinting
export { PisModule } from './modules/pis.js';
export { LocationFilterModule } from './modules/locationFilter.js';
export { StationDataModule } from './modules/stationData.js';

View File

@@ -1,12 +1,18 @@
import { BaseClient } from "./base.js"; import { BaseClient } from "./base.js";
import { PisModule } from "../modules/pis.js"; import { PisModule } from "../modules/pis.js";
import { LocationFilterModule } from "../modules/locationFilter.js";
import { StationDataModule } from "../modules/stationData.js";
export class OwlBoardClient extends BaseClient { export class OwlBoardClient extends BaseClient {
public readonly pis: PisModule; public readonly pis: PisModule;
public readonly locationFilter: LocationFilterModule;
public readonly stationData: StationDataModule;
constructor(baseUrl: string, apiKey?: string) { constructor(baseUrl: string, apiKey?: string) {
super(baseUrl, apiKey); super(baseUrl, apiKey);
this.pis = new PisModule(this); this.pis = new PisModule(this);
this.locationFilter = new LocationFilterModule(this);
this.stationData = new StationDataModule(this);
} }
} }

View File

@@ -1,6 +1,7 @@
/** /**
* Checks if a string is a valid CRS * Checks if a string is a valid CRS (Syntactically Only)
* using byte level checking for max performance * using byte level checking for max performance
* @param CRS The CRS Code to be validated
*/ */
export const IsValidCrs = (CRS: string): boolean => { export const IsValidCrs = (CRS: string): boolean => {
if (CRS.length !== 3) return false; if (CRS.length !== 3) return false;
@@ -15,8 +16,9 @@ export const IsValidCrs = (CRS: string): boolean => {
} }
/** /**
* Checks if a string is a valid TIPLOC * Checks if a string is a valid TIPLOC (Syntactically Only)
* using byte level checking for max performance * using byte level checking for max performance
* @param TIPLOC The TIPLOC to be validated
*/ */
export const IsValidTiploc = (TIPLOC: string): boolean => { export const IsValidTiploc = (TIPLOC: string): boolean => {
const l = TIPLOC.length; const l = TIPLOC.length;
@@ -33,9 +35,10 @@ export const IsValidTiploc = (TIPLOC: string): boolean => {
} }
/** /**
* Checks if a string is a valid PIS Code * Checks if a string is a valid PIS Code (Syntactically Only)
* using byte level checking for max performance * using byte level checking for max performance
* ONLY GWR (4-digit) CODES SUPPORTED * ONLY GWR (4-digit) CODES SUPPORTED
* @param PIS The PIS Code to be validated
*/ */
export const IsValidPis = (PIS: string): boolean => { export const IsValidPis = (PIS: string): boolean => {
if (PIS.length !== 4) return false; if (PIS.length !== 4) return false;
@@ -45,3 +48,14 @@ export const IsValidPis = (PIS: string): boolean => {
} }
return true; return true;
} }
/**
* Validates Geohash string against standard b32 alphabet
* (Syntactically Only validation)
* @param hash The geohash to be validated
* @param maxLen Defaults to 6 - which is enforced by the server, should not need changing
*/
export const IsValidGeoHash = (hash: string, maxLen: number = 6): boolean => {
const geoHashRegex = new RegExp(`^[0-9bcdefghjkmnpqrstuvwxyz]{1,${maxLen}}$`, 'i');
return geoHashRegex.test(hash);
}

View File

@@ -0,0 +1,15 @@
import { ApiLocationFilter } from "@owlboard/api-schema-types";
import type { BaseClient, ApiResult } from '../lib/base.js';
export class LocationFilterModule {
constructor(private client: BaseClient) {}
async getLocationFilterData(): Promise<ApiResult<ApiLocationFilter.LocationFilterObject[]>> {
const path = '/locationFilter/data';
return this.client.request<ApiLocationFilter.LocationFilterObject[]>(
path,
{method: "GET"}
);
}
}

View File

@@ -1,7 +1,7 @@
import { ApiPisObject } from '@owlboard/api-schema-types'; import { ApiPisObject } from '@owlboard/api-schema-types';
import type { BaseClient, ApiResult } from '../lib/base.js'; import type { BaseClient, ApiResult } from '../lib/base.js';
import { IsValidCrs, IsValidTiploc, IsValidPis } from 'src/lib/validation.js'; import { IsValidCrs, IsValidPis } from '../lib/validation.js';
import { ValidationError } from 'src/lib/errors.js'; import { ValidationError } from '../lib/errors.js';
export class PisModule { export class PisModule {
constructor(private client: BaseClient) {} constructor(private client: BaseClient) {}

View File

@@ -0,0 +1,37 @@
import { ApiStationsNearestStations } from '@owlboard/api-schema-types';
import type { BaseClient, ApiResult } from '../lib/base.js';
import { IsValidGeoHash } from '../lib/validation.js';
import { ValidationError } from '../lib/errors.js';
import Geohash from 'latlon-geohash';
export class StationDataModule {
constructor(private client: BaseClient) {}
/**
* Generates a 6-char Geohash for the given co-ordinates
* @param lt Latitude
* @param ln Longitude
* @returns Geohash as string
*/
generateGeohash(lt: number, ln: number): string {
return Geohash.encode(lt, ln, 6);
}
/**
*
* @param geohash Geohash as string (up to six characters), generate using this.generateGeohash()
* @returns Nearest Stations API Response (CRS, Name)
*/
async getNearestStations(geohash: string): Promise<ApiResult<ApiStationsNearestStations.StationsNearestStations[]>> {
if (!IsValidGeoHash(geohash)) {
throw new ValidationError("hash", "Invalid Geohash requested");
}
const path = `/stationData/nearest/${geohash}`;
return this.client.request<ApiStationsNearestStations.StationsNearestStations[]>(path, {
method: 'GET',
})
}
// getStationSate(crs: string){}
}

View File

@@ -21,6 +21,7 @@
"sourceMap": true, "sourceMap": true,
"declaration": true, "declaration": true,
"declarationMap": true, "declarationMap": true,
"composite": true,
// Stricter Typechecking Options // Stricter Typechecking Options
"noUncheckedIndexedAccess": true, "noUncheckedIndexedAccess": true,