tileflow 0.1.0-alpha.2 → 0.1.0-alpha.3
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 +35 -0
- package/dist/index.js +360 -11
- package/package.json +9 -10
- package/GENERATED_OUTPUT_LICENSE.md +0 -21
- package/NOTICE +0 -9
- package/TRADEMARKS.md +0 -10
package/README.md
CHANGED
|
@@ -131,6 +131,41 @@ Each manifest command entry declares its `outputKind`, `outputVersion`, and stab
|
|
|
131
131
|
`outputSchemaRef`. `raw-authoring-manifest` and `raw-config-reference` identify the two bootstrap
|
|
132
132
|
documents above; `command-envelope` identifies the ordinary version-1 CLI contract.
|
|
133
133
|
|
|
134
|
+
## Coordinates
|
|
135
|
+
|
|
136
|
+
These local commands require an explicitly provided compatible runtime distribution. No public
|
|
137
|
+
native runtime download is currently offered; package installation or the default setup URL does
|
|
138
|
+
not supply one. The verified production profile is Linux x64 on Debian 12, glibc 2.36 and Node 24.
|
|
139
|
+
The examples below use development artifacts and do not establish public platform support.
|
|
140
|
+
|
|
141
|
+
Coordinates commands use a locally provisioned execution release. They do not use Map
|
|
142
|
+
configuration, account state, or a Hosted fallback. Provision first from a distribution source, then
|
|
143
|
+
run the local commands against the active cache entry or an explicit runtime directory.
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
tileflow setup coordinates --source /path/to/distribution.json --cache-dir /path/to/coordinates-cache --development --json
|
|
147
|
+
tileflow coordinates search --query ETRS89 --runtime-dir /path/to/installed-release --development --json
|
|
148
|
+
tileflow coordinates describe --id EPSG:25830 --runtime-dir /path/to/installed-release --development --json
|
|
149
|
+
tileflow coordinates operations --from EPSG:4258 --to EPSG:25832 --runtime-dir /path/to/installed-release --development --json
|
|
150
|
+
tileflow coordinates transform --from EPSG:4258 --to EPSG:25832 --positions '[[12,55]]' --runtime-dir /path/to/installed-release --development --json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`setup coordinates --source` accepts a distribution URL, a local `distribution.json`, or a directory
|
|
154
|
+
that contains one. `--archive` is a local archive alias and rejects URLs. Setup verifies every asset
|
|
155
|
+
declared by the selected distribution before it records the active release. `--development` is
|
|
156
|
+
required for a development distribution.
|
|
157
|
+
|
|
158
|
+
Every execution command accepts `--runtime-dir`, `--release`, and `--development`. With no
|
|
159
|
+
`--runtime-dir`, it opens the cache entry selected by setup. `search` accepts `--query`, `describe`
|
|
160
|
+
accepts `--id`, `operations` accepts `--from` and `--to`, and `transform` also accepts JSON
|
|
161
|
+
`--positions`.
|
|
162
|
+
|
|
163
|
+
For a complete request, use exactly one of `--request '<json>'` or `--input <file|->`. These forms
|
|
164
|
+
cannot be combined with the command's convenience request flags. Input is limited to 32 KiB, must be
|
|
165
|
+
valid UTF-8 JSON, and `-` reads standard input. Success writes one JSON document to stdout. A
|
|
166
|
+
structured failure writes one JSON document to stderr and exits with status 1. Plain `--help` remains
|
|
167
|
+
human-readable; `--help --json` is a structured failure.
|
|
168
|
+
|
|
134
169
|
`tileflow explain` compiles exactly one map/theme selection through `createStyleResult()` and emits
|
|
135
170
|
its structured `report` and safe compiler `diagnostics`; it deliberately omits the usually large
|
|
136
171
|
MapLibre `style`. In a singular config, `--map` is optional; a multi-map workbench requires it.
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { hostname } from "os";
|
|
|
10
10
|
import { dirname as dirname10, isAbsolute as isAbsolute4, relative as relative5, resolve as resolve7, sep as sep5 } from "path";
|
|
11
11
|
import { createInterface } from "readline/promises";
|
|
12
12
|
import pc3 from "picocolors";
|
|
13
|
+
import { createLocalCoordinates, setupCoordinates } from "@tileflow/coordinates-runtime";
|
|
13
14
|
import {
|
|
14
15
|
auditTileflowMapThemeValues,
|
|
15
16
|
getTileflowStyleFontFaces,
|
|
@@ -1589,6 +1590,353 @@ function printHumanConfigInspection(inspection) {
|
|
|
1589
1590
|
console.log("Run tileflow inspect --json for the complete machine-readable result.");
|
|
1590
1591
|
}
|
|
1591
1592
|
|
|
1593
|
+
// src/coordinates-command.ts
|
|
1594
|
+
import { lstat as lstat2, open as open3 } from "fs/promises";
|
|
1595
|
+
import { CoordinatesSetupError } from "@tileflow/coordinates-runtime";
|
|
1596
|
+
import {
|
|
1597
|
+
CoordinatesContractError,
|
|
1598
|
+
coordinatesFailureSchema,
|
|
1599
|
+
coordinatesLimits,
|
|
1600
|
+
parseCoordinatesJsonRequest,
|
|
1601
|
+
parseCoordinatesRequest
|
|
1602
|
+
} from "@tileflow/coordinates/contract";
|
|
1603
|
+
var CoordinatesInputError = class extends Error {
|
|
1604
|
+
constructor(reason) {
|
|
1605
|
+
super("Coordinates input could not be read.");
|
|
1606
|
+
this.reason = reason;
|
|
1607
|
+
}
|
|
1608
|
+
reason;
|
|
1609
|
+
};
|
|
1610
|
+
function registerCoordinatesCommands(program2, dependencies) {
|
|
1611
|
+
const setup = program2.commands.find((command2) => command2.name() === "setup") ?? program2.command("setup").description("Provision local Tileflow tooling");
|
|
1612
|
+
configureCommand(
|
|
1613
|
+
setup.command("coordinates").description("Provision an offline Coordinates execution release").option("--source <url-or-path>", "distribution manifest URL or offline path").option("--archive <path>", "offline archive path alias").option("--cache-dir <path>", "Coordinates cache directory").option("--release <release-id>", "required Coordinates release identity").option("--development", "allow a development distribution").option("--json", "print one JSON receipt")
|
|
1614
|
+
).action(async (options, command2) => {
|
|
1615
|
+
if (options.help) {
|
|
1616
|
+
printHelp(command2, options.json, () => printSetupFailure());
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
if (command2.args.length > 0 || options.source && options.archive || options.archive && isRemoteLocation(options.archive)) {
|
|
1620
|
+
printSetupFailure(new CoordinatesSetupError("COORDINATES_SETUP_INVALID_REQUEST"));
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
const controller = (dependencies.createSignalController ?? installSignalAbortController)();
|
|
1624
|
+
try {
|
|
1625
|
+
const receipt = await dependencies.setupCoordinates({
|
|
1626
|
+
source: options.archive ?? options.source,
|
|
1627
|
+
cacheDirectory: options.cacheDir,
|
|
1628
|
+
requiredReleaseId: options.release,
|
|
1629
|
+
allowDevelopment: options.development,
|
|
1630
|
+
signal: controller.signal
|
|
1631
|
+
});
|
|
1632
|
+
printDocument(receipt);
|
|
1633
|
+
} catch (error) {
|
|
1634
|
+
printSetupFailure(error);
|
|
1635
|
+
} finally {
|
|
1636
|
+
controller.close();
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
const coordinates = program2.command("coordinates").description("Inspect and execute Coordinates requests using a provisioned local release");
|
|
1640
|
+
configureCommand(coordinates).option("--json", "print one JSON response");
|
|
1641
|
+
coordinates.action((options, command2) => {
|
|
1642
|
+
if (options.help) {
|
|
1643
|
+
printHelp(
|
|
1644
|
+
command2,
|
|
1645
|
+
options.json,
|
|
1646
|
+
() => printFailure(invalidRequest(null, "INVALID_VALUE", { path: ["command"] }))
|
|
1647
|
+
);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
const reason = command2.args.length === 0 ? "INVALID_VALUE" : "UNKNOWN_FIELD";
|
|
1651
|
+
printFailure(invalidRequest(null, reason, { path: ["command"] }));
|
|
1652
|
+
});
|
|
1653
|
+
registerOperation(
|
|
1654
|
+
coordinates,
|
|
1655
|
+
"search",
|
|
1656
|
+
dependencies,
|
|
1657
|
+
(options) => parseRequest("search", options, { query: options.query })
|
|
1658
|
+
);
|
|
1659
|
+
registerOperation(
|
|
1660
|
+
coordinates,
|
|
1661
|
+
"describe",
|
|
1662
|
+
dependencies,
|
|
1663
|
+
(options) => parseRequest("describe", options, { id: options.id })
|
|
1664
|
+
);
|
|
1665
|
+
registerOperation(
|
|
1666
|
+
coordinates,
|
|
1667
|
+
"operations",
|
|
1668
|
+
dependencies,
|
|
1669
|
+
(options) => parseRequest("operations", options, { from: options.from, to: options.to })
|
|
1670
|
+
);
|
|
1671
|
+
registerOperation(
|
|
1672
|
+
coordinates,
|
|
1673
|
+
"transform",
|
|
1674
|
+
dependencies,
|
|
1675
|
+
(options) => parseTransformRequest(options)
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
function registerOperation(coordinates, name, dependencies, parse3) {
|
|
1679
|
+
const command2 = configureCommand(
|
|
1680
|
+
coordinates.command(name).description(`Run the local Coordinates ${name} operation`).option("--request <json>", "complete JSON request").option("--input <path-or-dash>", "complete JSON request file, or - for standard input").option("--runtime-dir <path>", "prepared Coordinates runtime directory").option("--release <release-id>", "required Coordinates release identity").option("--development", "allow a development runtime").option("--json", "print one JSON response")
|
|
1681
|
+
);
|
|
1682
|
+
if (name === "search") command2.option("--query <text>", "search query");
|
|
1683
|
+
if (name === "describe") command2.option("--id <crs-id>", "CRS identifier");
|
|
1684
|
+
if (name === "operations" || name === "transform") {
|
|
1685
|
+
command2.option("--from <crs-id>", "source CRS identifier").option("--to <crs-id>", "target CRS identifier");
|
|
1686
|
+
}
|
|
1687
|
+
if (name === "transform") command2.option("--positions <json>", "JSON coordinate positions");
|
|
1688
|
+
command2.action(async (options, invoked) => {
|
|
1689
|
+
const parent = invoked.parent?.opts();
|
|
1690
|
+
const wantsHelp = options.help ?? parent?.help;
|
|
1691
|
+
const wantsJson = options.json ?? parent?.json;
|
|
1692
|
+
if (wantsHelp) {
|
|
1693
|
+
printHelp(
|
|
1694
|
+
invoked,
|
|
1695
|
+
wantsJson,
|
|
1696
|
+
() => printFailure(invalidRequest(name, "INVALID_VALUE", { path: ["command"] }))
|
|
1697
|
+
);
|
|
1698
|
+
return;
|
|
1699
|
+
}
|
|
1700
|
+
if (invoked.args.length > 0) {
|
|
1701
|
+
printFailure(invalidRequest(name, "UNKNOWN_FIELD", { path: ["options"] }));
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
const controller = (dependencies.createSignalController ?? installSignalAbortController)();
|
|
1705
|
+
let local;
|
|
1706
|
+
try {
|
|
1707
|
+
const request = await resolveRequest(
|
|
1708
|
+
name,
|
|
1709
|
+
options,
|
|
1710
|
+
parse3,
|
|
1711
|
+
dependencies.readInput,
|
|
1712
|
+
controller.signal
|
|
1713
|
+
);
|
|
1714
|
+
local = await dependencies.createLocalCoordinates({
|
|
1715
|
+
directory: options.runtimeDir,
|
|
1716
|
+
requiredReleaseId: options.release,
|
|
1717
|
+
allowDevelopment: options.development,
|
|
1718
|
+
signal: controller.signal
|
|
1719
|
+
});
|
|
1720
|
+
const response = await local[name](request, { signal: controller.signal });
|
|
1721
|
+
await local.close();
|
|
1722
|
+
local = void 0;
|
|
1723
|
+
printDocument(response);
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
printFailure(error, name);
|
|
1726
|
+
} finally {
|
|
1727
|
+
try {
|
|
1728
|
+
await local?.close();
|
|
1729
|
+
} catch {
|
|
1730
|
+
} finally {
|
|
1731
|
+
controller.close();
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
function configureCommand(command2) {
|
|
1737
|
+
return command2.allowUnknownOption(true).allowExcessArguments(true).helpOption(false).option("-h, --help", "display help");
|
|
1738
|
+
}
|
|
1739
|
+
async function resolveRequest(command2, options, parse3, readInput = readCoordinatesInput, signal) {
|
|
1740
|
+
const rawRequest = options.request !== void 0 || options.input !== void 0;
|
|
1741
|
+
if (options.request !== void 0 && options.input !== void 0 || rawRequest && hasConvenienceOptions(command2, options)) {
|
|
1742
|
+
throw invalidRequest(command2, "INVALID_VALUE", { path: ["request"] });
|
|
1743
|
+
}
|
|
1744
|
+
if (options.request !== void 0) return parseCoordinatesJsonRequest(command2, options.request);
|
|
1745
|
+
if (options.input !== void 0) {
|
|
1746
|
+
try {
|
|
1747
|
+
const input = await readInput(options.input, signal ?? new AbortController().signal);
|
|
1748
|
+
if (signal?.aborted) throw cancelledRequest(command2);
|
|
1749
|
+
return parseCoordinatesJsonRequest(command2, input);
|
|
1750
|
+
} catch (error) {
|
|
1751
|
+
if (signal?.aborted) throw cancelledRequest(command2);
|
|
1752
|
+
if (error instanceof CoordinatesInputError) throw invalidRequest(command2, error.reason);
|
|
1753
|
+
throw error;
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
return parse3(options);
|
|
1757
|
+
}
|
|
1758
|
+
function hasConvenienceOptions(command2, options) {
|
|
1759
|
+
if (command2 === "search") return options.query !== void 0;
|
|
1760
|
+
if (command2 === "describe") return options.id !== void 0;
|
|
1761
|
+
if (command2 === "operations") {
|
|
1762
|
+
const pair = options;
|
|
1763
|
+
return pair.from !== void 0 || pair.to !== void 0;
|
|
1764
|
+
}
|
|
1765
|
+
const transform = options;
|
|
1766
|
+
return transform.from !== void 0 || transform.to !== void 0 || transform.positions !== void 0;
|
|
1767
|
+
}
|
|
1768
|
+
function parseRequest(command2, options, request) {
|
|
1769
|
+
return parseCoordinatesRequest(command2, request);
|
|
1770
|
+
}
|
|
1771
|
+
function parseTransformRequest(options) {
|
|
1772
|
+
let positions;
|
|
1773
|
+
try {
|
|
1774
|
+
positions = options.positions === void 0 ? void 0 : JSON.parse(options.positions);
|
|
1775
|
+
} catch {
|
|
1776
|
+
throw invalidRequest("transform", "INVALID_JSON");
|
|
1777
|
+
}
|
|
1778
|
+
return parseCoordinatesRequest("transform", { from: options.from, to: options.to, positions });
|
|
1779
|
+
}
|
|
1780
|
+
async function readCoordinatesInput(input, signal) {
|
|
1781
|
+
if (input === "-") return readStandardInput(signal);
|
|
1782
|
+
assertNotAborted(signal);
|
|
1783
|
+
let info;
|
|
1784
|
+
try {
|
|
1785
|
+
info = await lstat2(input);
|
|
1786
|
+
} catch {
|
|
1787
|
+
throw new CoordinatesInputError("INVALID_VALUE");
|
|
1788
|
+
}
|
|
1789
|
+
if (!info.isFile() || info.isSymbolicLink()) throw new CoordinatesInputError("INVALID_VALUE");
|
|
1790
|
+
if (info.size > coordinatesLimits.maximumRequestBytes) {
|
|
1791
|
+
throw new CoordinatesInputError("REQUEST_TOO_LARGE");
|
|
1792
|
+
}
|
|
1793
|
+
const handle = await open3(input, "r");
|
|
1794
|
+
try {
|
|
1795
|
+
let length = 0;
|
|
1796
|
+
const bytes = Buffer.alloc(coordinatesLimits.maximumRequestBytes + 1);
|
|
1797
|
+
while (length < bytes.length) {
|
|
1798
|
+
assertNotAborted(signal);
|
|
1799
|
+
const { bytesRead } = await handle.read(bytes, length, bytes.length - length, length);
|
|
1800
|
+
if (bytesRead === 0) break;
|
|
1801
|
+
length += bytesRead;
|
|
1802
|
+
}
|
|
1803
|
+
assertNotAborted(signal);
|
|
1804
|
+
if (length > coordinatesLimits.maximumRequestBytes) {
|
|
1805
|
+
throw new CoordinatesInputError("REQUEST_TOO_LARGE");
|
|
1806
|
+
}
|
|
1807
|
+
return decodeInput(bytes.subarray(0, length));
|
|
1808
|
+
} finally {
|
|
1809
|
+
await handle.close();
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
async function readStandardInput(signal) {
|
|
1813
|
+
const chunks = [];
|
|
1814
|
+
let length = 0;
|
|
1815
|
+
return new Promise((resolve8, reject) => {
|
|
1816
|
+
const finish = (result) => {
|
|
1817
|
+
process.stdin.removeListener("data", onData);
|
|
1818
|
+
process.stdin.removeListener("end", onEnd);
|
|
1819
|
+
process.stdin.removeListener("error", onError);
|
|
1820
|
+
signal.removeEventListener("abort", onAbort);
|
|
1821
|
+
result();
|
|
1822
|
+
};
|
|
1823
|
+
const onAbort = () => {
|
|
1824
|
+
process.stdin.pause();
|
|
1825
|
+
finish(() => reject(new CoordinatesInputError("INVALID_VALUE")));
|
|
1826
|
+
};
|
|
1827
|
+
const onData = (chunk) => {
|
|
1828
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1829
|
+
length += bytes.length;
|
|
1830
|
+
if (length > coordinatesLimits.maximumRequestBytes) {
|
|
1831
|
+
process.stdin.pause();
|
|
1832
|
+
finish(() => reject(new CoordinatesInputError("REQUEST_TOO_LARGE")));
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
chunks.push(bytes);
|
|
1836
|
+
};
|
|
1837
|
+
const onEnd = () => finish(() => resolve8(decodeInput(Buffer.concat(chunks))));
|
|
1838
|
+
const onError = () => finish(() => reject(new CoordinatesInputError("INVALID_VALUE")));
|
|
1839
|
+
if (signal.aborted) {
|
|
1840
|
+
onAbort();
|
|
1841
|
+
return;
|
|
1842
|
+
}
|
|
1843
|
+
process.stdin.on("data", onData);
|
|
1844
|
+
process.stdin.once("end", onEnd);
|
|
1845
|
+
process.stdin.once("error", onError);
|
|
1846
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1847
|
+
process.stdin.resume();
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
function invalidRequest(command2, reason, details = {}) {
|
|
1851
|
+
return new CoordinatesContractError({
|
|
1852
|
+
schemaVersion: 1,
|
|
1853
|
+
ok: false,
|
|
1854
|
+
command: command2,
|
|
1855
|
+
releaseId: null,
|
|
1856
|
+
provenance: null,
|
|
1857
|
+
warnings: [],
|
|
1858
|
+
usage: null,
|
|
1859
|
+
error: { code: "COORDINATES_INVALID_REQUEST", reason, details, phase: "input" }
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
function cancelledRequest(command2) {
|
|
1863
|
+
return new CoordinatesContractError({
|
|
1864
|
+
schemaVersion: 1,
|
|
1865
|
+
ok: false,
|
|
1866
|
+
command: command2,
|
|
1867
|
+
releaseId: null,
|
|
1868
|
+
provenance: null,
|
|
1869
|
+
warnings: [],
|
|
1870
|
+
usage: null,
|
|
1871
|
+
error: { code: "COORDINATES_CANCELLED", reason: "CANCELLED", details: {}, phase: "input" }
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
function printDocument(document) {
|
|
1875
|
+
process.stdout.write(`${JSON.stringify(document)}
|
|
1876
|
+
`);
|
|
1877
|
+
}
|
|
1878
|
+
function printFailure(error, command2) {
|
|
1879
|
+
const document = serializeCoordinatesFailure(error, command2) ?? (command2 ? invalidRequest(command2, "INVALID_VALUE").toJSON() : setupFailureDocument());
|
|
1880
|
+
process.stderr.write(`${JSON.stringify(document)}
|
|
1881
|
+
`);
|
|
1882
|
+
process.exitCode = 1;
|
|
1883
|
+
}
|
|
1884
|
+
function printSetupFailure(error) {
|
|
1885
|
+
process.stderr.write(
|
|
1886
|
+
`${JSON.stringify(serializeSetupFailure(error) ?? setupFailureDocument())}
|
|
1887
|
+
`
|
|
1888
|
+
);
|
|
1889
|
+
process.exitCode = 1;
|
|
1890
|
+
}
|
|
1891
|
+
function serializeCoordinatesFailure(error, command2) {
|
|
1892
|
+
if (!(error instanceof CoordinatesContractError)) return void 0;
|
|
1893
|
+
const parsed = coordinatesFailureSchema.safeParse(error.toJSON());
|
|
1894
|
+
if (!parsed.success) return void 0;
|
|
1895
|
+
const failure = parsed.data;
|
|
1896
|
+
return new CoordinatesContractError({
|
|
1897
|
+
...failure,
|
|
1898
|
+
command: failure.command ?? command2 ?? null
|
|
1899
|
+
}).toJSON();
|
|
1900
|
+
}
|
|
1901
|
+
function serializeSetupFailure(error) {
|
|
1902
|
+
if (!(error instanceof CoordinatesSetupError)) return void 0;
|
|
1903
|
+
const codes = /* @__PURE__ */ new Set([
|
|
1904
|
+
"COORDINATES_SETUP_INVALID_REQUEST",
|
|
1905
|
+
"COORDINATES_SETUP_RELEASE_UNAVAILABLE",
|
|
1906
|
+
"COORDINATES_SETUP_MANIFEST_INVALID",
|
|
1907
|
+
"COORDINATES_SETUP_ARTIFACT_UNAVAILABLE",
|
|
1908
|
+
"COORDINATES_SETUP_INTEGRITY_FAILED",
|
|
1909
|
+
"COORDINATES_SETUP_INSTALLATION_FAILED",
|
|
1910
|
+
"COORDINATES_SETUP_CANCELLED",
|
|
1911
|
+
"COORDINATES_SETUP_TIMEOUT"
|
|
1912
|
+
]);
|
|
1913
|
+
if (!codes.has(error.code)) return void 0;
|
|
1914
|
+
return new CoordinatesSetupError(error.code, error.releaseId, error.assetId).toJSON();
|
|
1915
|
+
}
|
|
1916
|
+
function setupFailureDocument() {
|
|
1917
|
+
return new CoordinatesSetupError("COORDINATES_SETUP_INVALID_REQUEST").toJSON();
|
|
1918
|
+
}
|
|
1919
|
+
function printHelp(command2, json, printJson) {
|
|
1920
|
+
if (json) {
|
|
1921
|
+
printJson();
|
|
1922
|
+
return;
|
|
1923
|
+
}
|
|
1924
|
+
command2.outputHelp();
|
|
1925
|
+
}
|
|
1926
|
+
function isRemoteLocation(input) {
|
|
1927
|
+
return /^[A-Za-z][A-Za-z0-9+.-]*:\/\//u.test(input);
|
|
1928
|
+
}
|
|
1929
|
+
function assertNotAborted(signal) {
|
|
1930
|
+
if (signal.aborted) throw new CoordinatesInputError("INVALID_VALUE");
|
|
1931
|
+
}
|
|
1932
|
+
function decodeInput(bytes) {
|
|
1933
|
+
try {
|
|
1934
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
1935
|
+
} catch {
|
|
1936
|
+
throw new CoordinatesInputError("INVALID_VALUE");
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1592
1940
|
// src/deploy-source.ts
|
|
1593
1941
|
var overrideFields = [
|
|
1594
1942
|
["TILEFLOW_DEPLOY_REPOSITORY", "repository", 255],
|
|
@@ -3752,7 +4100,7 @@ import { z as z6 } from "zod";
|
|
|
3752
4100
|
|
|
3753
4101
|
// src/tileset-upload.ts
|
|
3754
4102
|
import { createHash } from "crypto";
|
|
3755
|
-
import { open as
|
|
4103
|
+
import { open as open4, stat } from "fs/promises";
|
|
3756
4104
|
import { z as z5 } from "zod";
|
|
3757
4105
|
import { serializeCanonicalJson as serializeCanonicalJson2 } from "@tileflow/core";
|
|
3758
4106
|
var teamTilesetPartSize = 16777216;
|
|
@@ -3816,7 +4164,7 @@ async function inspectNodeTeamTilesetArchive(path) {
|
|
|
3816
4164
|
return checkedIdentity(value.dev, value.ino, value.mtimeNs, value.size);
|
|
3817
4165
|
}
|
|
3818
4166
|
async function openNodeTeamTilesetArchive(path, expectedIdentity) {
|
|
3819
|
-
const handle = await
|
|
4167
|
+
const handle = await open4(path, "r");
|
|
3820
4168
|
const identity = async () => {
|
|
3821
4169
|
let pathStat;
|
|
3822
4170
|
let handleStat;
|
|
@@ -4831,7 +5179,7 @@ var tilesetPurgeResponseSchema = z6.object({
|
|
|
4831
5179
|
}).strict();
|
|
4832
5180
|
|
|
4833
5181
|
// src/visual-command.ts
|
|
4834
|
-
import { lstat as
|
|
5182
|
+
import { lstat as lstat4, readFile as readFile6 } from "fs/promises";
|
|
4835
5183
|
import { dirname as dirname9, isAbsolute as isAbsolute3, parse as parse2, relative as relative4, resolve as resolve6, sep as sep4 } from "path";
|
|
4836
5184
|
import {
|
|
4837
5185
|
analyzeTileflowCaptureReference,
|
|
@@ -4850,7 +5198,7 @@ import { compareCodeUnits as compareCodeUnits8 } from "@tileflow/core";
|
|
|
4850
5198
|
|
|
4851
5199
|
// src/visual-compare-command.ts
|
|
4852
5200
|
import { createHash as createHash3 } from "crypto";
|
|
4853
|
-
import { lstat as
|
|
5201
|
+
import { lstat as lstat3, readFile as readFile5, realpath } from "fs/promises";
|
|
4854
5202
|
import { basename as basename3, dirname as dirname8, extname, isAbsolute as isAbsolute2, parse, relative as relative3, resolve as resolve5, sep as sep3 } from "path";
|
|
4855
5203
|
import {
|
|
4856
5204
|
compareTileflowCapturesForReview,
|
|
@@ -5800,7 +6148,7 @@ async function readVisualCompareInventory(assetDirectory, inventoryPath, boundar
|
|
|
5800
6148
|
await assertNoSymlinkComponents(dirname8(inventoryPath), boundary);
|
|
5801
6149
|
let info;
|
|
5802
6150
|
try {
|
|
5803
|
-
info = await
|
|
6151
|
+
info = await lstat3(inventoryPath);
|
|
5804
6152
|
} catch (error) {
|
|
5805
6153
|
if (isMissingFile4(error)) return [];
|
|
5806
6154
|
throw error;
|
|
@@ -5824,7 +6172,7 @@ async function readVisualCompareInventory(assetDirectory, inventoryPath, boundar
|
|
|
5824
6172
|
await assertNoSymlinkComponents(dirname8(path), boundary);
|
|
5825
6173
|
let assetInfo;
|
|
5826
6174
|
try {
|
|
5827
|
-
assetInfo = await
|
|
6175
|
+
assetInfo = await lstat3(path);
|
|
5828
6176
|
} catch (error) {
|
|
5829
6177
|
if (isMissingFile4(error)) continue;
|
|
5830
6178
|
throw error;
|
|
@@ -5986,7 +6334,7 @@ function pathsOverlap(left, right) {
|
|
|
5986
6334
|
}
|
|
5987
6335
|
async function assertDirectoryIfPresent(path) {
|
|
5988
6336
|
try {
|
|
5989
|
-
const info = await
|
|
6337
|
+
const info = await lstat3(path);
|
|
5990
6338
|
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
5991
6339
|
throw new Error("Visual compare asset path must be a non-symlink directory.");
|
|
5992
6340
|
}
|
|
@@ -5996,7 +6344,7 @@ async function assertDirectoryIfPresent(path) {
|
|
|
5996
6344
|
}
|
|
5997
6345
|
async function pathExists(path) {
|
|
5998
6346
|
try {
|
|
5999
|
-
await
|
|
6347
|
+
await lstat3(path);
|
|
6000
6348
|
return true;
|
|
6001
6349
|
} catch (error) {
|
|
6002
6350
|
if (isMissingFile4(error)) return false;
|
|
@@ -6350,7 +6698,7 @@ async function readOptionalArtifact(path, boundary, maximumBytes) {
|
|
|
6350
6698
|
await assertNoSymlinkComponents(dirname9(path), boundary);
|
|
6351
6699
|
let info;
|
|
6352
6700
|
try {
|
|
6353
|
-
info = await
|
|
6701
|
+
info = await lstat4(path);
|
|
6354
6702
|
} catch (error) {
|
|
6355
6703
|
if (isMissingFile5(error)) return void 0;
|
|
6356
6704
|
throw error;
|
|
@@ -6370,7 +6718,7 @@ async function readOptionalArtifact(path, boundary, maximumBytes) {
|
|
|
6370
6718
|
async function readVisualReference(path) {
|
|
6371
6719
|
let info;
|
|
6372
6720
|
try {
|
|
6373
|
-
info = await
|
|
6721
|
+
info = await lstat4(path);
|
|
6374
6722
|
} catch (error) {
|
|
6375
6723
|
throw new TileflowCaptureError2("BASELINE_INVALID", "The visual reference PNG cannot be read.", {
|
|
6376
6724
|
cause: error
|
|
@@ -6406,7 +6754,7 @@ async function resolveVisualDirectory(cwd, value, kind) {
|
|
|
6406
6754
|
const boundary = isInside2(cwd, path) ? cwd : path;
|
|
6407
6755
|
await assertNoSymlinkComponents(path, boundary);
|
|
6408
6756
|
try {
|
|
6409
|
-
const info = await
|
|
6757
|
+
const info = await lstat4(path);
|
|
6410
6758
|
if (info.isSymbolicLink() || !info.isDirectory()) {
|
|
6411
6759
|
throw new Error(`Visual ${kind} path must be a non-symlink directory.`);
|
|
6412
6760
|
}
|
|
@@ -7348,6 +7696,7 @@ registerConfigInspectCommand(inspectCommand, { defaultConfigPath });
|
|
|
7348
7696
|
registerFeatureInspectCommand(inspectCommand, { defaultConfigPath });
|
|
7349
7697
|
registerAiCommands(program, { defaultApiUrl, defaultConfigPath });
|
|
7350
7698
|
registerCaptureCommands(program, { defaultConfigPath });
|
|
7699
|
+
registerCoordinatesCommands(program, { createLocalCoordinates, setupCoordinates });
|
|
7351
7700
|
registerVisualCommands(program, {
|
|
7352
7701
|
defaultConfigPath,
|
|
7353
7702
|
openReport: (path) => openBrowser(path, true)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileflow",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "CLI-only tools for Tileflow config, capture, visual testing, and deploy.",
|
|
6
6
|
"type": "module",
|
|
@@ -25,10 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
-
"LICENSE"
|
|
29
|
-
"NOTICE",
|
|
30
|
-
"GENERATED_OUTPUT_LICENSE.md",
|
|
31
|
-
"TRADEMARKS.md"
|
|
28
|
+
"LICENSE"
|
|
32
29
|
],
|
|
33
30
|
"bin": {
|
|
34
31
|
"tileflow": "./dist/index.js"
|
|
@@ -38,12 +35,14 @@
|
|
|
38
35
|
},
|
|
39
36
|
"dependencies": {
|
|
40
37
|
"@hono/node-server": "2.0.10",
|
|
41
|
-
"@tileflow/capture": ">=0.1.0-alpha.
|
|
42
|
-
"@tileflow/
|
|
43
|
-
"@tileflow/
|
|
44
|
-
"@tileflow/
|
|
45
|
-
"
|
|
38
|
+
"@tileflow/capture": ">=0.1.0-alpha.21 <0.1.0-beta.0",
|
|
39
|
+
"@tileflow/coordinates": ">=0.1.0-alpha.0 <0.1.0-beta.0",
|
|
40
|
+
"@tileflow/coordinates-runtime": ">=0.1.0-alpha.0 <0.1.0-beta.0",
|
|
41
|
+
"@tileflow/core": ">=0.1.0-alpha.24 <0.1.0-beta.0",
|
|
42
|
+
"@tileflow/dev": ">=0.1.0-alpha.22 <0.1.0-beta.0",
|
|
43
|
+
"@tileflow/maps": ">=0.1.0-alpha.2 <0.1.0-beta.0",
|
|
46
44
|
"commander": "^15.0.0",
|
|
45
|
+
"hono": "4.13.5",
|
|
47
46
|
"picocolors": "^1.1.1",
|
|
48
47
|
"zod": "^4.4.3"
|
|
49
48
|
},
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Tileflow generated-output grant
|
|
2
|
-
|
|
3
|
-
In addition to the rights granted by the Apache License, Version 2.0, Tileflow.dev contributors
|
|
4
|
-
grant recipients a perpetual, worldwide, non-exclusive, no-charge, royalty-free right to use,
|
|
5
|
-
reproduce, modify, display, perform, distribute, sublicense, and commercialize the Tileflow-owned
|
|
6
|
-
parts of output generated by this SDK.
|
|
7
|
-
|
|
8
|
-
Covered output includes compiled map styles, manifests, receipts, sprites, glyph artifacts, static
|
|
9
|
-
render descriptions, and other build artifacts produced from Tileflow maps or application maps.
|
|
10
|
-
Original Tileflow map definitions, icons, and patterns distributed by `@tileflow/maps` may likewise
|
|
11
|
-
be used, modified, embedded, deployed, and redistributed as part of personal or commercial maps and
|
|
12
|
-
applications.
|
|
13
|
-
|
|
14
|
-
This grant does not relicense third-party software, fonts, icons, map data, datasets, imagery, or
|
|
15
|
-
other input material. Their licenses, attribution requirements, notices, and use restrictions
|
|
16
|
-
continue to apply to the relevant source and generated output. You are responsible for having the
|
|
17
|
-
rights necessary to process and distribute your own inputs.
|
|
18
|
-
|
|
19
|
-
This grant does not provide access to Tileflow hosted services or grant rights in Tileflow names,
|
|
20
|
-
logos, or marks. The SDK and generated output are provided without warranties or conditions beyond
|
|
21
|
-
those required by applicable law.
|
package/NOTICE
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
Tileflow SDK
|
|
2
|
-
Copyright 2026 Tileflow.dev contributors
|
|
3
|
-
|
|
4
|
-
This product includes software and original map artwork developed by Tileflow.dev contributors.
|
|
5
|
-
|
|
6
|
-
Third-party materials distributed with a package remain subject to their own license and notice
|
|
7
|
-
files. See THIRD_PARTY_NOTICES.md and asset-adjacent license files where present.
|
|
8
|
-
|
|
9
|
-
The Tileflow names and marks are not licensed under the Apache License 2.0. See TRADEMARKS.md.
|
package/TRADEMARKS.md
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# Tileflow trademarks
|
|
2
|
-
|
|
3
|
-
The Apache License, Version 2.0, and the Tileflow generated-output grant do not grant permission to
|
|
4
|
-
use the Tileflow name, `tileflow.dev`, logos, service marks, product names, or other Tileflow brand
|
|
5
|
-
features except for reasonable and customary use that truthfully describes the origin of the SDK or
|
|
6
|
-
compatibility with Tileflow, and for reproducing required notices.
|
|
7
|
-
|
|
8
|
-
You may not use Tileflow brand features in a way that suggests sponsorship, endorsement, or an
|
|
9
|
-
official Tileflow product when none exists. Third-party names and marks remain the property of their
|
|
10
|
-
respective owners.
|