gtfs-garage-web 0.0.2 → 0.1.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.
package/README.md CHANGED
@@ -9,19 +9,12 @@ be mounted in another application.
9
9
 
10
10
  ```sh
11
11
  npm install gtfs-garage-web
12
- ```
13
-
14
- The map is a separate entry point, and MapLibre an **optional** peer. Install
15
- it only if you want one:
16
-
17
- ```sh
18
12
  npm install maplibre-gl # only with the map
19
13
  ```
20
14
 
21
- Nothing in the main entry mentions MapLibre, so a viewer without a map neither
22
- downloads it nor needs it installed to build. That is why the map arrives as an
23
- import rather than a flag: a bundler resolves `import()` specifiers whether or
24
- not the branch runs, so a flag would still have made MapLibre mandatory.
15
+ ESM only — a bundler or native ES modules, no `<script>` drop-in. MapLibre is an
16
+ **optional** peer behind its own entry point, so a viewer without a map neither
17
+ downloads it nor needs it installed to build.
25
18
 
26
19
  ## React
27
20
 
@@ -35,14 +28,10 @@ import "maplibre-gl/dist/maplibre-gl.css";
35
28
 
36
29
  export default function Feed() {
37
30
  return <GtfsGarage map={mapPart} baseUrl="https://example.org" style={{ height: "80vh" }} />;
38
- }```
39
-
40
- Drop the two `map` imports and the MapLibre stylesheet for a table-only viewer:
41
-
42
- ```tsx
43
- <GtfsGarage baseUrl="https://example.org" style={{ height: "80vh" }} />
31
+ }
44
32
  ```
45
33
 
34
+ Drop the two `map` imports and the MapLibre stylesheet for a table-only viewer.
46
35
  `"use client"` is required: the viewer builds DOM and cannot render on a server.
47
36
 
48
37
  **Give the container a height.** The viewer fills whatever box it is given, and
@@ -62,12 +51,25 @@ const viewer = await mount(document.querySelector("#feed")!, {
62
51
  viewer.destroy(); // releases the map, the history subscription and the markup
63
52
  ```
64
53
 
54
+ ## A dataset that is still being prepared
55
+
56
+ `GtfsGarageDataset` waits for one, and draws the being-prepared, not-prepared
57
+ and failed states itself — so no host writes a progress bar:
58
+
59
+ ```tsx
60
+ import { GtfsGarageDataset } from "gtfs-garage-web/react";
61
+
62
+ <GtfsGarageDataset dataset={provider} description="mdb-1210" style={{ height: "80vh" }} />
63
+ ```
64
+
65
65
  ## Where the data comes from
66
66
 
67
67
  By default the viewer talks to a GTFS Garage server at `baseUrl`. To drive it
68
- from your own backend instead, pass a `source` implementing `ViewerSource` —
69
- `GtfsSource` for the table, plus `geojsonStream` for the map, which draws a
70
- large feed's shapes as they arrive rather than all at the end.
68
+ from your own backend, either serve the same API — specified in
69
+ [`docs/GtfsGarageAPI.yaml`](https://github.com/MobilityData/gtfs-garage/blob/main/docs/GtfsGarageAPI.yaml)
70
+ — or pass a `source` implementing `ViewerSource`, which is the escape hatch for
71
+ a backend of any other shape, for authentication, or for reading Parquet in the
72
+ browser with no server at all.
71
73
 
72
74
  ## Styling
73
75
 
@@ -81,6 +83,14 @@ page. The design tokens are declared on that class and are the theming API:
81
83
  }
82
84
  ```
83
85
 
86
+ ## Documentation
87
+
88
+ **[Embedding the viewer](https://github.com/MobilityData/gtfs-garage/blob/main/docs/INTEGRATION.md)**
89
+ — every option, the three ways to supply data, what your server has to provide
90
+ (including CORS and authentication, which the API document deliberately leaves
91
+ to you), the dataset-preparation lifecycle, and a worked adapter for driving the
92
+ viewer from an API of your own.
93
+
84
94
  ## Licence
85
95
 
86
96
  Apache-2.0
package/dist/dataset.js CHANGED
@@ -1,4 +1,4 @@
1
- import { m as h, p as L } from "./mount-CHJb5mxA.js";
1
+ import { m as h, p as L } from "./mount-EvMk5jp_.js";
2
2
  function P(e, s) {
3
3
  const { description: a, canPrepare: n, asked: c, phrase: f } = s;
4
4
  switch (e.state) {
@@ -295,7 +295,7 @@ function ie(n) {
295
295
  e.push([se[n.kind], `${p(n.acquire_ms)}${t}`]);
296
296
  }
297
297
  if (n.extract_ms != null && e.push(["Unzip", `${p(n.extract_ms)} · ${f(n.total_bytes)} archive`]), n.register_ms != null && e.push(["Read headers", p(n.register_ms)]), n.convert_ms != null) {
298
- const t = n.stored_bytes === null ? "" : ` · ${f(n.stored_bytes)} stored`;
298
+ const t = n.stored_bytes == null ? "" : ` · ${f(n.stored_bytes)} stored`;
299
299
  e.push(["Convert to Parquet", `${p(n.convert_ms)}${t}`]);
300
300
  }
301
301
  return n.count_ms != null && e.push(["Count rows", p(n.count_ms)]), e;
@@ -306,19 +306,19 @@ function le(n) {
306
306
  name: t.name,
307
307
  bytes: f(t.bytes),
308
308
  share: e === 0 ? 0 : Math.round(t.bytes / e * 100),
309
- compressed: t.compressed_bytes === null ? "—" : f(t.compressed_bytes),
310
- stored: t.parquet_bytes === null ? "—" : f(t.parquet_bytes),
309
+ compressed: t.compressed_bytes == null ? "—" : f(t.compressed_bytes),
310
+ stored: t.parquet_bytes == null ? "—" : f(t.parquet_bytes),
311
311
  costMs: re(n, t),
312
- rows: t.row_count === null ? "—" : t.row_count.toLocaleString(),
312
+ rows: t.row_count == null ? "—" : t.row_count.toLocaleString(),
313
313
  columns: t.columns
314
314
  }));
315
315
  }
316
316
  function O(n) {
317
- return n.convert_ms !== null;
317
+ return n.convert_ms != null;
318
318
  }
319
319
  function re(n, e) {
320
320
  const t = O(n) ? e.convert_ms : e.count_ms;
321
- return t === null ? "—" : p(t);
321
+ return t == null ? "—" : p(t);
322
322
  }
323
323
  function de(n) {
324
324
  const e = n.phases ? null : O(n) ? {
package/dist/mount.d.ts CHANGED
@@ -14,6 +14,16 @@ import { type AppState } from "./state";
14
14
  import { type HistoryPort } from "./ui/history";
15
15
  export type { ViewerParts } from "./markup";
16
16
  export type { GtfsSource, ViewerSource } from "./sources/types";
17
+ /**
18
+ * The payload types, re-exported so a host implementing `ViewerSource` can name
19
+ * what its methods return. They are generated from `docs/GtfsGarageAPI.yaml`,
20
+ * so an implementation written against them is checked against the contract at
21
+ * compile time - which is the whole point of generating them, and is worth
22
+ * nothing if they stop at the package boundary.
23
+ */
24
+ export type { AppConfig, ColumnInfo, ConditionOutcome, DatasetManifest, FeatureCollection, FileCondition, FileMetrics, Filter, FilterOperator, GeoFeature, GeoJsonKind, ImpliedValue, LoadMetrics, LoadProgress, MissingFile, PageResponse, RelatedLink, Row, TableInfo, TablesResponse, ValueCount, } from "./sources/types";
25
+ /** `geojsonStream` hands these to its callback, so an implementer names them too. */
26
+ export type { NdjsonMessage } from "./sources/ndjson";
17
27
  export { RestSource } from "./sources/rest";
18
28
  export { browserHistory, memoryHistory, type HistoryPort } from "./ui/history";
19
29
  export interface ViewerOptions {
package/dist/mount.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R as s, b as a, a as e, m } from "./mount-CHJb5mxA.js";
1
+ import { R as s, b as a, a as e, m } from "./mount-EvMk5jp_.js";
2
2
  export {
3
3
  s as RestSource,
4
4
  a as browserHistory,
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as f } from "react/jsx-runtime";
2
2
  import { useRef as c, useEffect as i } from "react";
3
3
  import { mountDataset as m } from "./dataset.js";
4
- import { m as d } from "./mount-CHJb5mxA.js";
4
+ import { m as d } from "./mount-EvMk5jp_.js";
5
5
  function p({ className: l, style: u, ...e }) {
6
6
  const o = c(null), n = c(e);
7
7
  return n.current = e, i(() => {
package/dist/schema.d.ts CHANGED
@@ -10,9 +10,9 @@ import type { ColumnInfo, MissingFile } from "./sources/types";
10
10
  interface Field {
11
11
  type?: string;
12
12
  values?: Record<string, string>;
13
- required?: string;
13
+ required?: ColumnInfo["required"];
14
14
  condition?: string;
15
- conditionScope?: string;
15
+ conditionScope?: ColumnInfo["condition_scope"];
16
16
  primaryKey?: boolean;
17
17
  references?: {
18
18
  table: string;