@profullstack/nichedb 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +54 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/nichedb",
3
- "version": "0.62.0",
3
+ "version": "0.64.0",
4
4
  "description": "CLI and MCP bridge for NicheDB: browse collections, manage sources and feeds, search items, from any deployment",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -15,7 +15,7 @@ import { homedir, tmpdir } from 'node:os';
15
15
  import { join } from 'node:path';
16
16
  import { createInterface } from 'node:readline';
17
17
 
18
- export const VERSION = '0.62.0';
18
+ export const VERSION = '0.64.0';
19
19
  const GEO_FLAGS = ['lat', 'long', 'radius', 'unit', 'bbox', 'sort', 'offset'];
20
20
  const DEFAULT_API = process.env.NICHEDB_API ?? 'https://nichedb.dev';
21
21
  const CONFIG_DIR = join(process.env.XDG_CONFIG_HOME ?? join(homedir(), '.config'), 'nichedb');
@@ -252,6 +252,20 @@ export const COMMANDS = [
252
252
  'A satellite, rocket stage or piece of debris: GCAT catalogue entry and where it is over the Earth right now.',
253
253
  options: ['--json'],
254
254
  },
255
+ {
256
+ name: 'train',
257
+ usage: 'train <number | station | words> [--json]',
258
+ summary:
259
+ 'A train run (Amtrak, VIA Rail, Finland): where it is, its next stop and how late; or a European station.',
260
+ options: ['--json'],
261
+ },
262
+ {
263
+ name: 'transit',
264
+ usage: 'transit [<city> [<station id>]] [--json]',
265
+ summary:
266
+ 'Public transit: the cities, a city’s lines and alerts, or a station’s next arrivals and timetable.',
267
+ options: ['--json'],
268
+ },
255
269
  {
256
270
  name: 'ship',
257
271
  usage: 'ship <MMSI | IMO | name> [--json]',
@@ -1200,10 +1214,16 @@ export async function run(
1200
1214
  }
1201
1215
  case 'airplane':
1202
1216
  case 'satellite':
1203
- case 'ship': {
1217
+ case 'ship':
1218
+ case 'train': {
1204
1219
  const term = rest.join(' ').trim();
1205
1220
  if (!term) throw new Error(`${cmd} <id or name>`);
1206
- const path = { airplane: 'airplanes', satellite: 'satellites', ship: 'ships' }[cmd];
1221
+ const path = {
1222
+ airplane: 'airplanes',
1223
+ satellite: 'satellites',
1224
+ ship: 'ships',
1225
+ train: 'trains',
1226
+ }[cmd];
1207
1227
  const r = await client.get(`/api/v1/${path}/${encodeURIComponent(term)}`);
1208
1228
  if (json) {
1209
1229
  out(JSON.stringify(r, null, 2));
@@ -1215,6 +1235,8 @@ export async function run(
1215
1235
  return 0;
1216
1236
  }
1217
1237
  if (r.record) out(r.record.summary);
1238
+ if (cmd === 'train' && r.live?.delay)
1239
+ out(`now: ${r.live.delay}${r.live.nextStop ? `, next ${r.live.nextStop.name}` : ''}`);
1218
1240
  const now = r.position ?? r.live?.[0] ?? (Array.isArray(r.live) ? null : r.live);
1219
1241
  if (now?.lat !== undefined && now?.lat !== null) {
1220
1242
  const extra = [
@@ -1231,6 +1253,35 @@ export async function run(
1231
1253
  if (r.record?.url) out(r.record.url);
1232
1254
  return 0;
1233
1255
  }
1256
+ case 'transit': {
1257
+ const [city, station] = rest;
1258
+ const path = ['/api/v1/transit', city, station]
1259
+ .filter(Boolean)
1260
+ .map((p, i) => (i ? encodeURIComponent(p) : p))
1261
+ .join('/');
1262
+ const r = await client.get(path);
1263
+ if (json) {
1264
+ out(JSON.stringify(r, null, 2));
1265
+ return 0;
1266
+ }
1267
+ if (r.cities)
1268
+ for (const c of r.cities) out(`${pad(c.slug, 14)} ${c.name}: ${c.system} (${c.live})`);
1269
+ else if (r.arrivals) {
1270
+ out(`${r.station.name}: ${r.station.lines.join(', ')}`);
1271
+ if (!r.arrivals.length) out(' no live arrivals');
1272
+ for (const a of r.arrivals.slice(0, 15))
1273
+ out(
1274
+ ` ${pad(String(a.inMinutes === 0 ? 'now' : `${a.inMinutes} min`), 8)} ${pad(a.line ?? a.route ?? '', 14)} ${a.toward ?? ''}`,
1275
+ );
1276
+ } else {
1277
+ out(`${r.name}: ${r.system}`);
1278
+ out(
1279
+ ` ${r.lines.length} lines, ${r.stations.length} stations, ${r.alerts.length} alerts in force`,
1280
+ );
1281
+ for (const a of r.alerts.slice(0, 10)) out(` ! ${a.title}`);
1282
+ }
1283
+ return 0;
1284
+ }
1234
1285
  case 'business': {
1235
1286
  const qs = new URLSearchParams();
1236
1287
  const name = rest.join(' ');