@motionstudies/core 0.1.0-alpha.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/air-search.d.ts +11 -0
  4. package/air-search.js +32 -0
  5. package/domain/air-day.d.ts +34 -0
  6. package/domain/air-day.js +17 -0
  7. package/domain/air.d.ts +48 -0
  8. package/domain/air.js +83 -0
  9. package/domain/airport.d.ts +17 -0
  10. package/domain/airport.js +41 -0
  11. package/domain/boundary.d.ts +14 -0
  12. package/domain/boundary.js +1 -0
  13. package/domain/corridor.d.ts +64 -0
  14. package/domain/corridor.js +1 -0
  15. package/domain/hub.d.ts +57 -0
  16. package/domain/hub.js +137 -0
  17. package/domain/journey.d.ts +19 -0
  18. package/domain/journey.js +23 -0
  19. package/domain/lakes.d.ts +21 -0
  20. package/domain/lakes.js +1 -0
  21. package/domain/map-reference.d.ts +20 -0
  22. package/domain/map-reference.js +1 -0
  23. package/domain/network-day.d.ts +4 -0
  24. package/domain/network-day.js +21 -0
  25. package/domain/network-layers.d.ts +7 -0
  26. package/domain/network-layers.js +131 -0
  27. package/domain/network.d.ts +173 -0
  28. package/domain/network.js +106 -0
  29. package/domain/operations.d.ts +85 -0
  30. package/domain/operations.js +191 -0
  31. package/domain/realtime.d.ts +41 -0
  32. package/domain/realtime.js +116 -0
  33. package/domain/road-day.d.ts +65 -0
  34. package/domain/road-day.js +76 -0
  35. package/domain/road.d.ts +153 -0
  36. package/domain/road.js +78 -0
  37. package/domain/spatial-layout.d.ts +42 -0
  38. package/domain/spatial-layout.js +12 -0
  39. package/domain/train-time-index.d.ts +14 -0
  40. package/domain/train-time-index.js +28 -0
  41. package/edition.d.ts +34 -0
  42. package/edition.js +1 -0
  43. package/package.json +154 -0
  44. package/road-search.d.ts +11 -0
  45. package/road-search.js +24 -0
  46. package/search-navigation.d.ts +2 -0
  47. package/search-navigation.js +14 -0
  48. package/search-text.d.ts +1 -0
  49. package/search-text.js +12 -0
  50. package/theme.d.ts +19 -0
  51. package/theme.js +16 -0
@@ -0,0 +1,21 @@
1
+ import type { BoundaryCoordinate } from './boundary.ts';
2
+ export interface MapWaterBody {
3
+ readonly id: string;
4
+ readonly name: string;
5
+ readonly areaSquareKilometres: number;
6
+ readonly polygons: readonly (readonly (readonly BoundaryCoordinate[])[])[];
7
+ }
8
+ export interface MapWaterBodies {
9
+ readonly metadata: {
10
+ readonly source: string;
11
+ readonly sourceUrl: string;
12
+ readonly productUrl: string;
13
+ readonly edition: string;
14
+ readonly attribution: string;
15
+ readonly sourceCrs: string;
16
+ readonly outputCrs: string;
17
+ readonly simplificationToleranceMetres: number;
18
+ readonly minimumAreaSquareKilometres: number;
19
+ };
20
+ readonly lakes: readonly MapWaterBody[];
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import type { BoundaryCoordinate } from './boundary.ts';
2
+ export interface MapReferencePath {
3
+ readonly id: string;
4
+ readonly name: string;
5
+ readonly color?: string;
6
+ readonly paths: readonly (readonly BoundaryCoordinate[])[];
7
+ }
8
+ export interface MapReferencePaths {
9
+ readonly metadata: {
10
+ readonly source: string;
11
+ readonly sourceUrl: string;
12
+ readonly productUrl: string;
13
+ readonly edition: string;
14
+ readonly attribution: string;
15
+ readonly sourceCrs: string;
16
+ readonly outputCrs: string;
17
+ readonly simplificationToleranceMetres: number;
18
+ };
19
+ readonly references: readonly MapReferencePath[];
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { NetworkDayChunk, NetworkDayChunkDescriptor, NetworkDayManifest, NetworkSnapshot } from './network.ts';
2
+ export declare function dayChunkForTime(manifest: NetworkDayManifest, time: number): NetworkDayChunkDescriptor;
3
+ export declare function adjacentDayChunks(manifest: NetworkDayManifest, current: NetworkDayChunkDescriptor): readonly NetworkDayChunkDescriptor[];
4
+ export declare function networkSnapshotForDayChunk(manifest: NetworkDayManifest, chunk?: NetworkDayChunk): NetworkSnapshot;
@@ -0,0 +1,21 @@
1
+ export function dayChunkForTime(manifest, time) {
2
+ const last = manifest.chunks.at(-1);
3
+ const match = manifest.chunks.find((chunk) => time >= chunk.windowStart &&
4
+ (time < chunk.windowEnd || (chunk === last && time <= chunk.windowEnd)));
5
+ return match ?? (time < manifest.metadata.windowStart ? manifest.chunks[0] : last);
6
+ }
7
+ export function adjacentDayChunks(manifest, current) {
8
+ const index = manifest.chunks.findIndex((chunk) => chunk.id === current.id);
9
+ return manifest.chunks.slice(Math.max(0, index - 1), index + 2);
10
+ }
11
+ export function networkSnapshotForDayChunk(manifest, chunk) {
12
+ return {
13
+ metadata: manifest.metadata,
14
+ bounds: manifest.bounds,
15
+ stops: manifest.stops,
16
+ edges: manifest.edges,
17
+ paths: manifest.paths,
18
+ edgePaths: manifest.edgePaths,
19
+ trains: chunk?.trains ?? [],
20
+ };
21
+ }
@@ -0,0 +1,7 @@
1
+ import type { NetworkSnapshot } from './network.ts';
2
+ /**
3
+ * Combines independently loaded data layers without changing their source IDs.
4
+ * This is intentionally a runtime composition: each source artifact retains an
5
+ * independent payload budget and can remain outside the opening request graph.
6
+ */
7
+ export declare function mergeNetworkLayers(snapshots: readonly NetworkSnapshot[]): NetworkSnapshot;
@@ -0,0 +1,131 @@
1
+ function mergeInterchangeComplexes(snapshots) {
2
+ const studies = snapshots.flatMap(({ metadata }) => metadata.interchangeStudy ? [metadata.interchangeStudy] : []);
3
+ if (!studies.length)
4
+ return undefined;
5
+ const complexes = new Map();
6
+ for (const study of studies) {
7
+ for (const complex of study.complexes) {
8
+ const existing = complexes.get(complex.id);
9
+ if (!existing) {
10
+ complexes.set(complex.id, complex);
11
+ continue;
12
+ }
13
+ const links = new Map([...existing.links, ...complex.links].map((link) => [
14
+ `${link.fromStopId}:${link.toStopId}:${link.minimumTransferSeconds}`,
15
+ link,
16
+ ]));
17
+ complexes.set(complex.id, {
18
+ ...existing,
19
+ stopIds: [...new Set([...existing.stopIds, ...complex.stopIds])],
20
+ links: [...links.values()],
21
+ });
22
+ }
23
+ }
24
+ return {
25
+ model: studies.map(({ model }) => model).join(' '),
26
+ complexes: [...complexes.values()],
27
+ };
28
+ }
29
+ /**
30
+ * Combines independently loaded data layers without changing their source IDs.
31
+ * This is intentionally a runtime composition: each source artifact retains an
32
+ * independent payload budget and can remain outside the opening request graph.
33
+ */
34
+ export function mergeNetworkLayers(snapshots) {
35
+ const primary = snapshots[0];
36
+ if (!primary)
37
+ throw new Error('At least one network layer is required');
38
+ for (const snapshot of snapshots.slice(1)) {
39
+ if (snapshot.metadata.serviceDate !== primary.metadata.serviceDate ||
40
+ snapshot.metadata.windowStart !== primary.metadata.windowStart ||
41
+ snapshot.metadata.windowEnd !== primary.metadata.windowEnd) {
42
+ throw new Error('Network layers must share a service date and study window');
43
+ }
44
+ }
45
+ const stops = [];
46
+ const stopIndexByIdentity = new Map();
47
+ const paths = [];
48
+ const pathIndexByCoordinates = new Map();
49
+ const edges = [];
50
+ const edgePaths = [];
51
+ const trains = [];
52
+ const trainIds = new Set();
53
+ for (const snapshot of snapshots) {
54
+ const stopRemap = snapshot.stops.map((stop) => {
55
+ const identity = stop[4] ?? `${stop[0]}:${stop[1]}:${stop[2]}`;
56
+ const existing = stopIndexByIdentity.get(identity);
57
+ if (existing !== undefined)
58
+ return existing;
59
+ const index = stops.length;
60
+ stops.push(stop);
61
+ stopIndexByIdentity.set(identity, index);
62
+ return index;
63
+ });
64
+ const pathRemap = (snapshot.paths ?? []).map((path) => {
65
+ const identity = JSON.stringify(path);
66
+ const existing = pathIndexByCoordinates.get(identity);
67
+ if (existing !== undefined)
68
+ return existing;
69
+ const index = paths.length;
70
+ paths.push(path);
71
+ pathIndexByCoordinates.set(identity, index);
72
+ return index;
73
+ });
74
+ snapshot.edges.forEach(([from, to], edgeIndex) => {
75
+ edges.push([stopRemap[from], stopRemap[to]]);
76
+ const sourcePathIndex = snapshot.edgePaths?.[edgeIndex];
77
+ edgePaths.push(sourcePathIndex === null || sourcePathIndex === undefined
78
+ ? null
79
+ : (pathRemap[sourcePathIndex] ?? null));
80
+ });
81
+ for (const train of snapshot.trains) {
82
+ if (trainIds.has(train.id))
83
+ continue;
84
+ trainIds.add(train.id);
85
+ trains.push({
86
+ ...train,
87
+ stops: train.stops.map(([stopIndex, arrival, departure]) => [
88
+ stopRemap[stopIndex],
89
+ arrival,
90
+ departure,
91
+ ]),
92
+ pathSegments: train.pathSegments?.map((pathIndex) => pathIndex === null ? null : (pathRemap[pathIndex] ?? null)),
93
+ });
94
+ }
95
+ }
96
+ const geometry = primary.metadata.geometry
97
+ ? {
98
+ ...primary.metadata.geometry,
99
+ model: `Runtime composition of ${snapshots.length} independently loaded geometry layers`,
100
+ matchedSegments: edgePaths.filter((pathIndex) => pathIndex !== null).length,
101
+ totalSegments: edges.length,
102
+ resolvedStops: stops.length,
103
+ totalStops: stops.length,
104
+ }
105
+ : undefined;
106
+ return {
107
+ metadata: {
108
+ ...primary.metadata,
109
+ feedVersion: snapshots.map(({ metadata }) => metadata.feedVersion).join('+'),
110
+ model: snapshots.map(({ metadata }) => metadata.model).join(' + '),
111
+ note: `${snapshots.length} independently loaded network layers composed in the browser.`,
112
+ modes: [...new Set(snapshots.flatMap(({ metadata }) => metadata.modes ?? []))],
113
+ localRouteIds: [
114
+ ...new Set(snapshots.flatMap(({ metadata }) => metadata.localRouteIds ?? [])),
115
+ ],
116
+ interchangeStudy: mergeInterchangeComplexes(snapshots),
117
+ geometry,
118
+ },
119
+ bounds: {
120
+ minLongitude: Math.min(...snapshots.map(({ bounds }) => bounds.minLongitude)),
121
+ minLatitude: Math.min(...snapshots.map(({ bounds }) => bounds.minLatitude)),
122
+ maxLongitude: Math.max(...snapshots.map(({ bounds }) => bounds.maxLongitude)),
123
+ maxLatitude: Math.max(...snapshots.map(({ bounds }) => bounds.maxLatitude)),
124
+ },
125
+ stops,
126
+ edges,
127
+ paths,
128
+ edgePaths,
129
+ trains,
130
+ };
131
+ }
@@ -0,0 +1,173 @@
1
+ export type NetworkStop = readonly [
2
+ longitude: number,
3
+ latitude: number,
4
+ name: string,
5
+ platformCode?: string,
6
+ sourceId?: string,
7
+ labelRank?: number
8
+ ];
9
+ export type NetworkEdge = readonly [from: number, to: number];
10
+ export type NetworkPathPoint = readonly [longitude: number, latitude: number];
11
+ export type NetworkPath = readonly NetworkPathPoint[];
12
+ export type TrainStop = readonly [stopIndex: number, arrival: number, departure: number];
13
+ export type ServiceCategory = 'international' | 'intercity' | 'interregio' | 'regional-express' | 's-bahn' | 'regional' | 'tram' | 'metro' | 'bus' | 'ferry' | 'cableway' | 'funicular' | 'other';
14
+ export interface NetworkTrain {
15
+ readonly id: string;
16
+ readonly route: string;
17
+ readonly headsign: string;
18
+ readonly shortName: string;
19
+ readonly category: ServiceCategory;
20
+ readonly mode?: string;
21
+ readonly servicePattern?: 'local' | 'express';
22
+ readonly start: number;
23
+ readonly end: number;
24
+ readonly stops: readonly TrainStop[];
25
+ readonly pathSegments?: readonly (number | null)[];
26
+ readonly realtime?: RealtimeTrainState;
27
+ readonly operations?: ObservedTrainState;
28
+ }
29
+ export interface ObservedTrainState {
30
+ readonly kind: 'prediction-derived';
31
+ readonly observedAt: string;
32
+ readonly vehicleId: string;
33
+ }
34
+ export interface RealtimeTrainState {
35
+ readonly status: 'adjusted' | 'cancelled';
36
+ readonly delaySeconds: number;
37
+ readonly skippedStops: number;
38
+ readonly generatedAt: string;
39
+ }
40
+ export interface NetworkSnapshot {
41
+ readonly metadata: {
42
+ readonly publisher: string;
43
+ readonly feedVersion: string;
44
+ readonly serviceDate: string;
45
+ readonly windowStart: number;
46
+ readonly windowEnd: number;
47
+ readonly focusTime: number;
48
+ readonly sourceUrl: string;
49
+ readonly sourceSha256?: string;
50
+ readonly retrievedAt?: string;
51
+ readonly license?: string;
52
+ readonly licenseUrl?: string;
53
+ readonly model: string;
54
+ readonly note: string;
55
+ readonly modes?: readonly string[];
56
+ readonly labelHierarchy?: {
57
+ readonly model: string;
58
+ readonly stationCount: number;
59
+ };
60
+ readonly localAgencyIds?: readonly string[];
61
+ readonly localRouteIds?: readonly string[];
62
+ readonly servicePatternStudy?: {
63
+ readonly model: string;
64
+ readonly localTrips: number;
65
+ readonly expressTrips: number;
66
+ readonly passEvents: readonly ServicePatternPassEvent[];
67
+ };
68
+ readonly interchangeStudy?: {
69
+ readonly model: string;
70
+ readonly complexes: readonly InterchangeComplex[];
71
+ };
72
+ readonly geometry?: {
73
+ readonly publisher: string;
74
+ readonly feedVersion: string;
75
+ readonly sourceUrl: string;
76
+ readonly sourceSha256?: string;
77
+ readonly productUrl?: string;
78
+ readonly model: string;
79
+ readonly matchedSegments: number;
80
+ readonly totalSegments: number;
81
+ readonly resolvedStops?: number;
82
+ readonly totalStops?: number;
83
+ readonly simplificationToleranceMetres?: number;
84
+ };
85
+ };
86
+ readonly bounds: {
87
+ readonly minLongitude: number;
88
+ readonly minLatitude: number;
89
+ readonly maxLongitude: number;
90
+ readonly maxLatitude: number;
91
+ };
92
+ readonly stops: readonly NetworkStop[];
93
+ readonly edges: readonly NetworkEdge[];
94
+ readonly paths?: readonly NetworkPath[];
95
+ readonly edgePaths?: readonly (number | null)[];
96
+ readonly trains: readonly NetworkTrain[];
97
+ }
98
+ export interface InterchangeLink {
99
+ readonly fromStopId: string;
100
+ readonly toStopId: string;
101
+ readonly minimumTransferSeconds: number;
102
+ }
103
+ export interface InterchangeComplex {
104
+ readonly id: string;
105
+ readonly name: string;
106
+ readonly longitude: number;
107
+ readonly latitude: number;
108
+ readonly stopIds: readonly string[];
109
+ readonly links: readonly InterchangeLink[];
110
+ }
111
+ export interface ServicePatternPassEvent {
112
+ readonly id: string;
113
+ readonly localTrainId: string;
114
+ readonly expressTrainId: string;
115
+ readonly fromStopId: string;
116
+ readonly toStopId: string;
117
+ readonly time: number;
118
+ readonly startDeltaSeconds: number;
119
+ readonly endDeltaSeconds: number;
120
+ }
121
+ export interface NetworkDayChunkDescriptor {
122
+ readonly id: string;
123
+ readonly windowStart: number;
124
+ readonly windowEnd: number;
125
+ readonly path: string;
126
+ readonly tripCount: number;
127
+ readonly bytes?: number;
128
+ readonly sha256?: string;
129
+ }
130
+ export interface NetworkDayManifest {
131
+ readonly metadata: NetworkSnapshot['metadata'];
132
+ readonly bounds: NetworkSnapshot['bounds'];
133
+ readonly stops: NetworkSnapshot['stops'];
134
+ readonly edges: NetworkSnapshot['edges'];
135
+ readonly paths?: NetworkSnapshot['paths'];
136
+ readonly edgePaths?: NetworkSnapshot['edgePaths'];
137
+ readonly tripCount: number;
138
+ readonly chunks: readonly NetworkDayChunkDescriptor[];
139
+ }
140
+ export interface NetworkDayChunk {
141
+ readonly windowStart: number;
142
+ readonly windowEnd: number;
143
+ readonly trains: readonly NetworkTrain[];
144
+ }
145
+ export interface StationRoute {
146
+ readonly name: string;
147
+ readonly category: ServiceCategory;
148
+ }
149
+ export interface StationIndexEntry {
150
+ readonly name: string;
151
+ readonly labelRank?: number;
152
+ readonly stopIndexes: readonly number[];
153
+ readonly trainIds: readonly string[];
154
+ readonly routes: readonly StationRoute[];
155
+ }
156
+ export interface NetworkRouteIndexEntry {
157
+ readonly id: string;
158
+ readonly name: string;
159
+ readonly category: ServiceCategory;
160
+ readonly trainIds: readonly string[];
161
+ readonly stopIndexes: readonly number[];
162
+ readonly headsigns: readonly string[];
163
+ }
164
+ export declare function buildRouteIndex(snapshot: NetworkSnapshot): readonly NetworkRouteIndexEntry[];
165
+ export declare function buildStationIndex(snapshot: NetworkSnapshot): readonly StationIndexEntry[];
166
+ export interface TrainPosition {
167
+ readonly fromStop: number;
168
+ readonly toStop: number;
169
+ readonly progress: number;
170
+ readonly segmentIndex?: number;
171
+ }
172
+ export declare function positionForTrain(train: NetworkTrain, time: number): TrainPosition | undefined;
173
+ export declare function formatServiceTime(totalSeconds: number): string;
@@ -0,0 +1,106 @@
1
+ export function buildRouteIndex(snapshot) {
2
+ const records = new Map();
3
+ for (const train of snapshot.trains) {
4
+ const id = `${train.category}:${train.route}`;
5
+ const record = records.get(id) ?? {
6
+ name: train.route,
7
+ category: train.category,
8
+ trainIds: new Set(),
9
+ stopIndexes: new Set(),
10
+ headsigns: new Set(),
11
+ };
12
+ record.trainIds.add(train.id);
13
+ train.stops.forEach(([stopIndex]) => record.stopIndexes.add(stopIndex));
14
+ if (train.headsign)
15
+ record.headsigns.add(train.headsign);
16
+ records.set(id, record);
17
+ }
18
+ return [...records.entries()]
19
+ .map(([id, record]) => ({
20
+ id,
21
+ name: record.name,
22
+ category: record.category,
23
+ trainIds: [...record.trainIds],
24
+ stopIndexes: [...record.stopIndexes],
25
+ headsigns: [...record.headsigns].sort((first, second) => first.localeCompare(second, 'de-CH')),
26
+ }))
27
+ .sort((first, second) => first.category.localeCompare(second.category, 'en') ||
28
+ first.name.localeCompare(second.name, 'de-CH', { numeric: true }));
29
+ }
30
+ export function buildStationIndex(snapshot) {
31
+ const records = new Map();
32
+ snapshot.stops.forEach((stop, index) => {
33
+ const record = records.get(stop[2]) ?? {
34
+ stopIndexes: [],
35
+ trainIds: new Set(),
36
+ routes: new Map(),
37
+ labelRank: stop[5],
38
+ };
39
+ record.stopIndexes.push(index);
40
+ if (stop[5] !== undefined) {
41
+ record.labelRank = Math.min(record.labelRank ?? Number.POSITIVE_INFINITY, stop[5]);
42
+ }
43
+ records.set(stop[2], record);
44
+ });
45
+ for (const train of snapshot.trains) {
46
+ const visitedNames = new Set();
47
+ for (const [stopIndex] of train.stops) {
48
+ const name = snapshot.stops[stopIndex]?.[2];
49
+ if (!name || visitedNames.has(name))
50
+ continue;
51
+ visitedNames.add(name);
52
+ const record = records.get(name);
53
+ if (!record)
54
+ continue;
55
+ record.trainIds.add(train.id);
56
+ record.routes.set(`${train.category}:${train.route}`, {
57
+ name: train.route,
58
+ category: train.category,
59
+ });
60
+ }
61
+ }
62
+ return [...records.entries()]
63
+ .filter(([, record]) => record.trainIds.size > 0)
64
+ .map(([name, record]) => ({
65
+ name,
66
+ labelRank: record.labelRank,
67
+ stopIndexes: record.stopIndexes,
68
+ trainIds: [...record.trainIds],
69
+ routes: [...record.routes.values()].sort((first, second) => first.name.localeCompare(second.name, 'de-CH')),
70
+ }));
71
+ }
72
+ export function positionForTrain(train, time) {
73
+ if (train.realtime?.status === 'cancelled' ||
74
+ time < train.start ||
75
+ time > train.end ||
76
+ train.stops.length < 2) {
77
+ return undefined;
78
+ }
79
+ for (let index = 1; index < train.stops.length; index += 1) {
80
+ const previous = train.stops[index - 1];
81
+ const next = train.stops[index];
82
+ if (time <= previous[2]) {
83
+ return { fromStop: previous[0], toStop: previous[0], progress: 0 };
84
+ }
85
+ if (time <= next[1]) {
86
+ const duration = Math.max(1, next[1] - previous[2]);
87
+ return {
88
+ fromStop: previous[0],
89
+ toStop: next[0],
90
+ progress: Math.min(1, Math.max(0, (time - previous[2]) / duration)),
91
+ segmentIndex: index - 1,
92
+ };
93
+ }
94
+ if (time <= next[2]) {
95
+ return { fromStop: next[0], toStop: next[0], progress: 0 };
96
+ }
97
+ }
98
+ const last = train.stops.at(-1);
99
+ return { fromStop: last[0], toStop: last[0], progress: 0 };
100
+ }
101
+ export function formatServiceTime(totalSeconds) {
102
+ const normalized = ((Math.round(totalSeconds) % 86400) + 86400) % 86400;
103
+ const hours = Math.floor(normalized / 3600);
104
+ const minutes = Math.floor((normalized % 3600) / 60);
105
+ return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
106
+ }
@@ -0,0 +1,85 @@
1
+ export interface ObservedStopPrediction {
2
+ readonly stopId: string;
3
+ readonly stopName: string;
4
+ readonly platformName?: string;
5
+ readonly expectedArrival: string;
6
+ readonly secondsToStop: number;
7
+ }
8
+ export interface ObservedTransitVehicle {
9
+ readonly id: string;
10
+ readonly lineId: string;
11
+ readonly lineName: string;
12
+ readonly modeName?: string;
13
+ readonly destinationStopId?: string;
14
+ readonly destinationName?: string;
15
+ readonly direction?: string;
16
+ readonly currentLocation?: string;
17
+ readonly towards?: string;
18
+ readonly observedAt: string;
19
+ readonly predictions: readonly ObservedStopPrediction[];
20
+ }
21
+ export interface ObservedLineStatus {
22
+ readonly lineId: string;
23
+ readonly lineName: string;
24
+ readonly severity: number;
25
+ readonly severityDescription: string;
26
+ readonly reason?: string;
27
+ }
28
+ export interface TransitOperationsSnapshot {
29
+ readonly metadata: {
30
+ readonly kind: 'observed-operations';
31
+ readonly publisher: string;
32
+ readonly sourceUrl: string;
33
+ readonly collectedAt: string;
34
+ readonly scheduledAt: string;
35
+ readonly lineIds: readonly string[];
36
+ readonly model: string;
37
+ };
38
+ readonly vehicles: readonly ObservedTransitVehicle[];
39
+ readonly lineStatuses: readonly ObservedLineStatus[];
40
+ }
41
+ export interface TransitOperationsDayFrame {
42
+ readonly time: number;
43
+ readonly observedAt: string;
44
+ readonly vehicles: readonly ObservedTransitVehicle[];
45
+ readonly lineStatuses: readonly ObservedLineStatus[];
46
+ }
47
+ export interface TransitOperationsDayChunk {
48
+ readonly windowStart: number;
49
+ readonly windowEnd: number;
50
+ readonly frames: readonly TransitOperationsDayFrame[];
51
+ }
52
+ export interface TransitOperationsDayChunkDescriptor {
53
+ readonly id: string;
54
+ readonly windowStart: number;
55
+ readonly windowEnd: number;
56
+ readonly path: string;
57
+ readonly frameCount: number;
58
+ readonly bytes: number;
59
+ readonly sha256: string;
60
+ }
61
+ export interface TransitOperationsDayManifest {
62
+ readonly metadata: {
63
+ readonly kind: 'observed-operations-day';
64
+ readonly publisher: string;
65
+ readonly serviceDate: string;
66
+ readonly timezone: string;
67
+ readonly sourceUrl: string;
68
+ readonly model: string;
69
+ readonly note: string;
70
+ readonly sampleIntervalSeconds: number;
71
+ readonly completeMinutes: number;
72
+ readonly longestGapSeconds: number;
73
+ readonly lineIds: readonly string[];
74
+ };
75
+ readonly chunks: readonly TransitOperationsDayChunkDescriptor[];
76
+ }
77
+ export interface ObservedNetworkProjection {
78
+ readonly snapshot: import('./network.ts').NetworkSnapshot;
79
+ readonly serviceTime: number;
80
+ readonly matchedVehicleCount: number;
81
+ readonly unmatchedVehicleCount: number;
82
+ }
83
+ export declare function operationsServiceTime(snapshot: TransitOperationsSnapshot, timeZone: string): number;
84
+ export declare function operationsAgeSeconds(snapshot: TransitOperationsSnapshot, now?: number): number;
85
+ export declare function projectOperationsOntoNetwork(reference: import('./network.ts').NetworkSnapshot, operations: TransitOperationsSnapshot, serviceTime: number): ObservedNetworkProjection;