@globalfishingwatch/skills 0.0.1
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 +89 -0
- package/dist/decode-url/SKILL.md +51 -0
- package/dist/decode-url/index.js +20339 -0
- package/dist/decode-url/scripts/decode-url.mjs +18 -0
- package/dist/decode-url/scripts/register-gfw-resolver.mjs +24 -0
- package/dist/encode-url/MAINTENANCE.md +53 -0
- package/dist/encode-url/SKILL.md +135 -0
- package/dist/encode-url/index.js +20211 -0
- package/dist/encode-url/references/areas.json +1401 -0
- package/dist/encode-url/references/examples-conversations.md +113 -0
- package/dist/encode-url/references/examples.md +234 -0
- package/dist/encode-url/references/filters.md +67 -0
- package/dist/encode-url/references/highlighted-workspaces.md +65 -0
- package/dist/encode-url/references/layers.md +96 -0
- package/dist/encode-url/references/ports.json +27507 -0
- package/dist/encode-url/references/query-params.md +114 -0
- package/dist/encode-url/references/routes.md +24 -0
- package/dist/encode-url/scripts/encode-url.mjs +26 -0
- package/dist/encode-url/scripts/register-gfw-resolver.mjs +24 -0
- package/dist/index.js +20514 -0
- package/dist/package.json +35 -0
- package/package.json +35 -0
- package/src/decode-url/SKILL.md +51 -0
- package/src/decode-url/decode.ts +87 -0
- package/src/decode-url/index.ts +4 -0
- package/src/decode-url/scripts/decode-url.mjs +18 -0
- package/src/decode-url/scripts/register-gfw-resolver.mjs +24 -0
- package/src/decode-url/workspaces.ts +34 -0
- package/src/encode-url/MAINTENANCE.md +53 -0
- package/src/encode-url/SKILL.md +135 -0
- package/src/encode-url/config.ts +8 -0
- package/src/encode-url/dictionary.ts +305 -0
- package/src/encode-url/encode.ts +79 -0
- package/src/encode-url/index.ts +4 -0
- package/src/encode-url/references/areas.json +1401 -0
- package/src/encode-url/references/examples-conversations.md +113 -0
- package/src/encode-url/references/examples.md +234 -0
- package/src/encode-url/references/filters.md +67 -0
- package/src/encode-url/references/highlighted-workspaces.md +65 -0
- package/src/encode-url/references/layers.md +96 -0
- package/src/encode-url/references/ports.json +27507 -0
- package/src/encode-url/references/query-params.md +114 -0
- package/src/encode-url/references/routes.md +24 -0
- package/src/encode-url/routes.ts +166 -0
- package/src/encode-url/scripts/encode-url.mjs +26 -0
- package/src/encode-url/scripts/register-gfw-resolver.mjs +24 -0
- package/src/index.ts +6 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# GFW map query params (state)
|
|
2
|
+
|
|
3
|
+
Pass these unabbreviated in `state` — the encoder abbreviates them.
|
|
4
|
+
Source of truth (params documented with JSDoc — read these when a param is missing here):
|
|
5
|
+
`apps/fishing-map/types/index.ts` (`WorkspaceState`/`AppState`/`QueryParams`), `apps/fishing-map/features/reports/reports.types.ts` (`ReportState`), `apps/fishing-map/features/vessel/vessel.types.ts` (`VesselProfileState`), `apps/fishing-map/features/search/search.types.ts` (`VesselSearchState`).
|
|
6
|
+
Defaults live in `DEFAULT_WORKSPACE` (`apps/fishing-map/data/config.ts`) and `DEFAULT_REPORT_STATE` (`features/reports/reports.config.ts`).
|
|
7
|
+
|
|
8
|
+
## Core (all routes)
|
|
9
|
+
|
|
10
|
+
| Param | Type | Notes |
|
|
11
|
+
| ------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| `latitude`, `longitude`, `zoom` | number | Viewport. zoom 0 = world, ~4-6 = country, ~12 = port |
|
|
13
|
+
| `start`, `end` | ISO datetime | Time range, e.g. `2026-07-01T00:00:00.000Z` |
|
|
14
|
+
| `dataviewInstances` | array | The layers (see layers.md) |
|
|
15
|
+
| `timebarVisualisation` | string | `heatmap` (activity) \| `heatmapDetections` \| `events` \| `vessel` \| `vesselGroup` \| `environment` |
|
|
16
|
+
| `visibleEvents` | array \| `all` \| `none` | Event types on vessel tracks: `fishing`, `encounter`, `port_visit`, `loitering`, `gaps` (default `all`) |
|
|
17
|
+
| `timebarGraph` | string | `speed` \| `elevation` \| `none` |
|
|
18
|
+
| `sidebarOpen` | boolean | |
|
|
19
|
+
| `readOnly` | boolean | Share links that shouldn't be edited |
|
|
20
|
+
| `daysFromLatest` | number | Rolling window ending at latest available day |
|
|
21
|
+
| `bivariateDataviews` | [id, id] | Two activity layers compared in one bivariate ramp |
|
|
22
|
+
| `mapAnnotations`, `mapRulers` | arrays | User drawings/measurements; toggle without removing via `mapAnnotationsVisible` / `mapRulersVisible` (booleans, default `true`) |
|
|
23
|
+
| `mapDrawing` | `polygons` \| `points` \| false | Enables the draw-on-map feature; `mapDrawingEditId` targets an existing drawn feature for edit |
|
|
24
|
+
| `activityVisualizationMode` | string | Render mode for activity layers: `heatmap` (default) \| `heatmap-high-res` \| `heatmap-low-res` \| `positions` |
|
|
25
|
+
| `detectionsVisualizationMode` | string | Same values as activity; for detections layers (default `heatmap`) |
|
|
26
|
+
| `environmentVisualizationMode` | string | `heatmap` \| `heatmap-low-res` (default) — no high res for environment layers |
|
|
27
|
+
| `vesselGroupsVisualizationMode` | string | `footprint` (default) \| `footprint-high-res` |
|
|
28
|
+
| `vesselsColorBy` | string | Property coloring vessel tracks/points: `track` \| `speed` \| `elevation` |
|
|
29
|
+
|
|
30
|
+
Internal/auto-generated params — never set them: `reportAreaBounds`, `skipColorDomainSampling`, `migramarLayer`, `includeRelatedIdentities`, `trackCorrectionId`, `sidePanelId`/`sidePanelSubcontentId`/`sidePanelContent`.
|
|
31
|
+
|
|
32
|
+
## dataviewInstances item
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"id": "ais", // instance id (layers.md)
|
|
37
|
+
"dataviewId": "apparent-fishing-effort-ais-v-{PIPE_DATASET_VERSION}", // only for layers added on top of defaults; version token resolved by the encoder
|
|
38
|
+
"config": {
|
|
39
|
+
"visible": true,
|
|
40
|
+
"color": "#9CA4FF", // set together with colorRamp — use that ramp's hex (see palette below)
|
|
41
|
+
"colorRamp": "lilac", // teal|orange|magenta|yellow|lilac|sky|green|red|salmon
|
|
42
|
+
"filters": { "flag": ["FRA"], "geartype": ["trawlers"] }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`color`/`colorRamp` are one choice, not two. Pick a ramp and set `color` to its paired hex:
|
|
48
|
+
|
|
49
|
+
| colorRamp | color | colorRamp | color | colorRamp | color |
|
|
50
|
+
| --------- | --------- | --------- | --------- | --------- | --------- |
|
|
51
|
+
| teal | `#00FFBC` | sky | `#00EEFF` | green | `#A6FF59` |
|
|
52
|
+
| lilac | `#9CA4FF` | red | `#FF6854` | orange | `#FFAA0D` |
|
|
53
|
+
| salmon | `#FFAE9B` | yellow | `#FFEA00` | magenta | `#FF64CE` |
|
|
54
|
+
|
|
55
|
+
To show the SAME dataset twice with different filters (e.g. Spanish vs French fishing), reuse the default instance (`ais`) for one and add a second instance with a unique id (`fishing-effort-ais__<timestamp>`) + `dataviewId`.
|
|
56
|
+
|
|
57
|
+
## Area report (`report` route)
|
|
58
|
+
|
|
59
|
+
| Param | Values |
|
|
60
|
+
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
61
|
+
| `reportCategory` | `activity` (default) \| `detections` \| `events` \| `environment` \| `others` \| `vessel-groups` |
|
|
62
|
+
| `reportActivitySubCategory` | `fishing` \| `presence` — sub-filter within an activity report |
|
|
63
|
+
| `reportDetectionsSubCategory` | `sar` \| `viirs` \| `sentinel-2` — sub-filter within a detections report |
|
|
64
|
+
| `reportEventsSubCategory` | event type within an events report: `encounter` (default) \| `loitering` \| `port_visit` \| `gap` |
|
|
65
|
+
| `reportVesselsSubCategory` | vessels-tab sub-tab: `flag` (default) \| `geartype` \| `vesselType` \| `source` \| `coverage` |
|
|
66
|
+
| `reportActivityGraph` | `evolution` (default) \| `beforeAfter` \| `periodComparison` \| `datasetComparison` |
|
|
67
|
+
| `reportTimeComparison` | `{ "start", "compareStart", "duration", "durationType": "days"\|"months" }` — for `beforeAfter`/`periodComparison` |
|
|
68
|
+
| `reportComparisonDataviewIds` | `{ "main", "compare" }` dataview ids — for `datasetComparison` |
|
|
69
|
+
| `reportVesselGraph` | `flag` (default) \| `geartype` \| `vesselType` |
|
|
70
|
+
| `reportBufferValue` / `reportBufferUnit` / `reportBufferOperation` | number / `nauticalmiles`\|`kilometers` / `dissolve`\|`difference` |
|
|
71
|
+
| `reportVesselFilter` | free-text filter on the vessels list — see syntax below |
|
|
72
|
+
| `reportVesselPage`, `reportResultsPerPage` | pagination (page is 0-based; per-page min 10, max 50, default 10) |
|
|
73
|
+
| `reportVesselOrderProperty` / `reportVesselOrderDirection` | sort: `shipname` (default) \| `flag` \| `shiptype` / `asc` (default) \| `desc` |
|
|
74
|
+
| `reportLoadVessels` | boolean, load vessel list immediately |
|
|
75
|
+
| `reportEventsGraph` | events-report chart: `evolution` (default) \| `byFlag` \| `byRFMO` \| `byFAO` \| `byEEZ` |
|
|
76
|
+
| `reportEventsPortsFilter`, `reportEventsPortsPage`, `reportEventsPortsResultsPerPage` | ports list controls in an events report (same semantics as the vessel-table ones) |
|
|
77
|
+
|
|
78
|
+
Note: the URL param is `reportResultsPerPage` even though the app state field is named `reportVesselResultsPerPage` — always use `reportResultsPerPage` in `state`.
|
|
79
|
+
|
|
80
|
+
`reportVesselFilter` syntax (also `reportEventsPortsFilter`): comma = search by multiple fields, `|` = OR, leading `-` = exclude. E.g. `flag:china, gear:trawlers`, `-spain`, `cargo|passenger`.
|
|
81
|
+
|
|
82
|
+
## Ports report (`ports-report` route)
|
|
83
|
+
|
|
84
|
+
`portsReportName` (e.g. `CAMARONES`), `portsReportCountry` (ISO3), `portsReportDatasetId` (`public-global-port-visits-events:v4.0`).
|
|
85
|
+
|
|
86
|
+
## Vessel profile (`vessel` route)
|
|
87
|
+
|
|
88
|
+
| Param | Values |
|
|
89
|
+
| ------------------------------------------- | --------------------------------------------------------------- |
|
|
90
|
+
| `vesselDatasetId` | `public-global-vessel-identity:v4.0` |
|
|
91
|
+
| `vesselSelfReportedId` / `vesselRegistryId` | vessel identity ids |
|
|
92
|
+
| `vesselIdentitySource` | `selfReportedInfo` \| `registryInfo` |
|
|
93
|
+
| `vesselSection` | `activity` \| `related_vessels` \| `areas` \| `insights` |
|
|
94
|
+
| `vesselArea` | `fao` \| `eez` \| `mpa` \| `rfmo` |
|
|
95
|
+
| `vesselRelated` | `encounters` \| `owners` — when `vesselSection=related_vessels` |
|
|
96
|
+
| `vesselActivityMode` | `voyage` \| `type` |
|
|
97
|
+
|
|
98
|
+
## Vessel search (`vessel-search` route)
|
|
99
|
+
|
|
100
|
+
| Param | Notes |
|
|
101
|
+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| `query` | free text: name, MMSI, IMO, callsign |
|
|
103
|
+
| `searchOption` | `basic` (default) \| `advanced` |
|
|
104
|
+
| `sources` | dataset ids restricting the search (advanced only) |
|
|
105
|
+
| advanced fields | `flag` (array ISO3), `owner`, `ssvid` (MMSI), `imo`, `callsign`, `geartypes`, `shiptypes`, `transmissionDateFrom`/`transmissionDateTo` |
|
|
106
|
+
| `infoSource` | identity source filter |
|
|
107
|
+
|
|
108
|
+
`transmissionDateFrom`/`transmissionDateTo` are advanced search FIELDS (dates, `YYYY-MM-DD`) — different namespace from the `firstTransmissionDate`/`lastTransmissionDate` URL params (`fTD`/`lTD`) that always appear (often empty) in search URLs.
|
|
109
|
+
|
|
110
|
+
## User page (`user` route)
|
|
111
|
+
|
|
112
|
+
`userTab`: `info` | `workspaces` | `datasets` | `reports` | `vesselGroups`.
|
|
113
|
+
|
|
114
|
+
<!-- Maintainers: every enumerated value above maps to a source symbol — see "Value sources" in ../MAINTENANCE.md for update checks. -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# GFW map routes
|
|
2
|
+
|
|
3
|
+
App served under basename `/map` (already included in the script's `path` output).
|
|
4
|
+
Source: `apps/fishing-map/routes/_app` (TanStack Router file routes).
|
|
5
|
+
|
|
6
|
+
| Route type | Path pattern | Path params | When to use |
|
|
7
|
+
| --------------------- | ------------------------------------------------------------ | --------------------- | ------------------------------------------------------------------------------------ |
|
|
8
|
+
| `workspace` | `/` or `/$category/$workspaceId` | category, workspaceId | Browse/compare layers on the map |
|
|
9
|
+
| `workspaces-list` | `/$category` | category | List curated workspaces of a category |
|
|
10
|
+
| `report` | `/$category/$workspaceId/report/$datasetId/$areaId` | + datasetId, areaId | Aggregated report over an area (EEZ/FAO/RFMO/MPA) |
|
|
11
|
+
| `report` (global) | `/$category/$workspaceId/report` | — (no datasetId/areaId) | Whole-world aggregated report; omit `datasetId`+`areaId`, category defaults to `reports` |
|
|
12
|
+
| `report` (saved) | `/report/$reportId` | reportId | Open a user-saved report |
|
|
13
|
+
| `vessel` | `/$category/$workspaceId/vessel/$vesselId` | + vesselId | Vessel profile (identity, track, events) |
|
|
14
|
+
| `vessel-search` | `/$category/$workspaceId/vessel-search` | — | Search vessels by name/MMSI/IMO or advanced filters |
|
|
15
|
+
| `vessel-group-report` | `/$category/$workspaceId/vessel-group-report/$vesselGroupId` | + vesselGroupId | Report over a vessel group |
|
|
16
|
+
| `ports-report` | `/$category/$workspaceId/ports-report/$portId` | + portId | Port activity profile (visits, vessels) |
|
|
17
|
+
| `user` | `/user` | — | User info, saved workspaces (`userTab=workspaces`), datasets, reports, vessel groups |
|
|
18
|
+
|
|
19
|
+
- `category`: `fishing-activity` (default) | `marine-manager` | `reports`
|
|
20
|
+
- `workspaceId`: `default-public` (default public workspace)
|
|
21
|
+
- report `datasetId` values: `public-eez-areas`, `public-fao-major`, `public-rfmo`, `public-mpa-all`
|
|
22
|
+
- `areaId`: numeric for EEZs (see `areas.json`), FAO major area code, RFMO id
|
|
23
|
+
- `vesselId`: GFW vessel id (uuid-like, from vessel search results)
|
|
24
|
+
- `portId`: e.g. `arg-camarones` (see `ports.json`)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import './register-gfw-resolver.mjs'
|
|
3
|
+
|
|
4
|
+
const readStdin = async () => {
|
|
5
|
+
let data = ''
|
|
6
|
+
for await (const chunk of process.stdin) data += chunk
|
|
7
|
+
return data
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const input = process.argv[2] && process.argv[2] !== '-' ? process.argv[2] : await readStdin()
|
|
11
|
+
if (!input?.trim()) {
|
|
12
|
+
console.error(
|
|
13
|
+
`Usage: node encode-url.mjs '{"route":{"type":"workspace"},"state":{...}}' (or pipe JSON via stdin)`
|
|
14
|
+
)
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { encodeMapUrl } = await import('@globalfishingwatch/skills/encode-url')
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const result = encodeMapUrl(JSON.parse(input))
|
|
22
|
+
console.log(JSON.stringify(result, null, 2))
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(error.message)
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { registerHooks } from 'node:module'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
5
|
+
|
|
6
|
+
// Each skill ships its own self-contained bundle next to it. Resolve it from either layout:
|
|
7
|
+
// - dist/<skill>/scripts (dist output, this skill copied standalone) -> ../index.js
|
|
8
|
+
// - <skill>/scripts (monorepo source, unbuilt) -> ../../dist/<skill>/index.js
|
|
9
|
+
const skillDir = fileURLToPath(new URL('..', import.meta.url))
|
|
10
|
+
const skillName = path.basename(skillDir)
|
|
11
|
+
const SPECIFIER = `@globalfishingwatch/skills/${skillName}`
|
|
12
|
+
const BUNDLE = [
|
|
13
|
+
path.join(skillDir, 'index.js'),
|
|
14
|
+
path.join(skillDir, '..', '..', 'dist', skillName, 'index.js'),
|
|
15
|
+
].find(existsSync)
|
|
16
|
+
|
|
17
|
+
registerHooks({
|
|
18
|
+
resolve(specifier, context, nextResolve) {
|
|
19
|
+
if (specifier === SPECIFIER && BUNDLE) {
|
|
20
|
+
return { url: pathToFileURL(BUNDLE).href, format: 'module', shortCircuit: true }
|
|
21
|
+
}
|
|
22
|
+
return nextResolve(specifier, context)
|
|
23
|
+
},
|
|
24
|
+
})
|