{"_id":"@amritk/lynx-location","_rev":"4-2b77adf8112f2fe92607be44303e7fcd","name":"@amritk/lynx-location","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@amritk/lynx-location","version":"0.1.0","keywords":["lynx","location","geolocation","gps","native-module","typescript","mjst"],"author":{"name":"amritk"},"license":"MIT","_id":"@amritk/lynx-location@0.1.0","maintainers":[{"name":"amritk","email":"amrit+spam@hockey-community.com"}],"homepage":"https://github.com/amritk/mini/tree/main/packages/lynx-location#readme","bugs":{"url":"https://github.com/amritk/mini/issues"},"dist":{"shasum":"12c9aaa305ca86e2ca6ac7b6d7c6a08de16fc464","tarball":"https://registry.npmjs.org/@amritk/lynx-location/-/lynx-location-0.1.0.tgz","fileCount":35,"integrity":"sha512-yZ0WGtNZvC3kRrr7XSzuuKBf+wCqJsg9e9Is1snwCrM/vjL1sgRwQYFwRJgE+TAG63eTiuHoj7sVFosZsTZmaQ==","signatures":[{"sig":"MEYCIQCiMShOF/57q7+Y/NZE1ZUT6y/uMmBNKVGtb5hk8g5XhQIhAN5uwdWMCuwnU18D89YP8QxOqjjaHBhd3DFAFDK+sRMJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":151046},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","development":"./src/index.ts"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","default":"./dist/testing/index.js","development":"./src/testing/index.ts"},"./package.json":"./package.json","./lynx.lib.json":"./lynx.lib.json"},"gitHead":"aea9072d4a679858c41a7d4eaf1f90f0d153798f","scripts":{"test":"NODE_ENV=production vitest run --root ../.. packages/lynx-location/","build":"tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f && node ../../scripts/strip-comments.mjs","types:check":"tsgo -p . --noEmit"},"_npmUser":{"name":"amritk","email":"amrit+spam@hockey-community.com"},"repository":{"url":"git+https://github.com/amritk/mini.git","type":"git","directory":"packages/lynx-location"},"_npmVersion":"11.16.0","description":"Device location for Lynx: an Android and iOS native module, and a promise-shaped facade that reaches it from the main thread.","directories":{},"sideEffects":false,"_nodeVersion":"26.3.0","dependencies":{"@amritk/mini-lynx-native":"workspace:*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5"},"peerDependencies":{"typescript":"^5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/lynx-location_0.1.0_1785895773947_0.8001650881169764","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@amritk/lynx-location","version":"0.2.0","keywords":["lynx","location","geolocation","gps","native-module","typescript","mjst"],"author":{"name":"amritk"},"license":"MIT","_id":"@amritk/lynx-location@0.2.0","maintainers":[{"name":"amritk","email":"amrit+spam@hockey-community.com"}],"homepage":"https://github.com/amritk/mini/tree/main/packages/lynx-location#readme","bugs":{"url":"https://github.com/amritk/mini/issues"},"dist":{"shasum":"4cd940b299d5736db90a512d0db65aee48e59e06","tarball":"https://registry.npmjs.org/@amritk/lynx-location/-/lynx-location-0.2.0.tgz","fileCount":62,"integrity":"sha512-EYBQX1Mu4ZK+HIsp1Xox5LUMAUx6eryo2nxRIM8bouIRxsViUrvy60vq2UlYhlaXUohrkajBSRzPT9OIUwCVIA==","signatures":[{"sig":"MEYCIQC/HA7ngIEOZhQNwnqK/Sarzpm4KZNN5bbeLuVGe0RGvQIhAMIMp6HPi3vOrJBrsC0GngSZwdFotNDecF8VJTTpa4xR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amritk%2flynx-location@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":199011},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","default":"./dist/testing/index.js"},"./package.json":"./package.json","./lynx.lib.json":"./lynx.lib.json"},"gitHead":"9c6b6bc96beba6a5f106f5e1bf5d7d0ab3b762c1","scripts":{"test":"NODE_ENV=production vitest run --root ../.. packages/lynx-location/","build":"tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f && node ../../scripts/strip-comments.mjs","types:check":"tsgo -p . --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:63e14da9-5646-4b14-bdd9-6bd842f07d36"}},"repository":{"url":"git+https://github.com/amritk/mini.git","type":"git","directory":"packages/lynx-location"},"_npmVersion":"12.0.2","description":"Device location for Lynx: an Android and iOS native module, and a promise-shaped facade that reaches it from the main thread.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"@amritk/mini-lynx-native":"0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5"},"peerDependencies":{"typescript":"^5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/lynx-location_0.2.0_1785905545908_0.2416813392071473","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@amritk/lynx-location","version":"0.2.1","keywords":["lynx","location","geolocation","gps","native-module","typescript","mjst"],"author":{"name":"amritk"},"license":"MIT","_id":"@amritk/lynx-location@0.2.1","maintainers":[{"name":"amritk","email":"amrit+spam@hockey-community.com"}],"homepage":"https://github.com/amritk/mini/tree/main/packages/lynx-location#readme","bugs":{"url":"https://github.com/amritk/mini/issues"},"dist":{"shasum":"82c4690af679808c0939c793a7e8c33d9e92aa20","tarball":"https://registry.npmjs.org/@amritk/lynx-location/-/lynx-location-0.2.1.tgz","fileCount":62,"integrity":"sha512-wWnDC9A9+6Z/+7Gh/qhhEcB/VGeWbGJEOdfAr3BiZTg9WtRuvN8UtB8YjetMN2WJyHsYbYW44Ciem1rRCicCDA==","signatures":[{"sig":"MEQCIEPhCYa6YxLfv0rS/c36NBQ1aGeLbsiTsVQje9csHtxMAiB6IztOIGAopAIV8FVWHfucxFiV00qY9Ub+9Okx5O9m8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amritk%2flynx-location@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":199077},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","default":"./dist/testing/index.js"},"./package.json":"./package.json","./lynx.lib.json":"./lynx.lib.json"},"gitHead":"9c78706160a9e76fc5a6e31ef33a1b7c5fdfeb03","scripts":{"test":"NODE_ENV=production vitest run --root ../.. packages/lynx-location/","build":"tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f && node ../../scripts/strip-comments.mjs","types:check":"tsgo -p . --noEmit","prepublishOnly":"node ../../scripts/check-publishable.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:63e14da9-5646-4b14-bdd9-6bd842f07d36"}},"repository":{"url":"git+https://github.com/amritk/mini.git","type":"git","directory":"packages/lynx-location"},"_npmVersion":"12.0.2","description":"Device location for Lynx: an Android and iOS native module, and a promise-shaped facade that reaches it from the main thread.","directories":{},"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{"@amritk/mini-lynx-native":"0.2.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5"},"peerDependencies":{"typescript":"^5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/lynx-location_0.2.1_1785949012005_0.18062564809291182","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@amritk/lynx-location","version":"0.2.2","description":"Device location for Lynx: an Android and iOS native module, and a promise-shaped facade that reaches it from the main thread.","type":"module","license":"MIT","author":{"name":"amritk"},"sideEffects":false,"keywords":["lynx","location","geolocation","gps","native-module","typescript","mjst"],"repository":{"type":"git","url":"git+https://github.com/amritk/mini.git","directory":"packages/lynx-location"},"homepage":"https://github.com/amritk/mini/tree/main/packages/lynx-location#readme","bugs":{"url":"https://github.com/amritk/mini/issues"},"publishConfig":{"access":"public"},"scripts":{"build":"tsgo -p tsconfig.build.json && tsc-alias -p tsconfig.build.json -f && node ../../scripts/strip-comments.mjs","prepublishOnly":"node ../../scripts/check-publishable.mjs","types:check":"tsgo -p . --noEmit","test":"NODE_ENV=production vitest run --root ../.. packages/lynx-location/"},"exports":{"./package.json":"./package.json","./lynx.lib.json":"./lynx.lib.json",".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing/index.js","default":"./dist/testing/index.js"}},"dependencies":{"@amritk/mini-lynx-native":"0.2.2"},"peerDependencies":{"typescript":"^5"},"peerDependenciesMeta":{"typescript":{"optional":true}},"devDependencies":{"typescript":"^5"},"gitHead":"c2516a9f0a935e9e8e1eda316d651ac48e0ccc71","_id":"@amritk/lynx-location@0.2.2","_nodeVersion":"24.19.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-/Og5NEC0iR0tom8hw78xp94GQeg+hVJVsxZvDAHkw7UtKgl1TYp/juovXm2mGSguJ4gAGBm/UJTvcDXpHntKEA==","shasum":"120be534a20d2b26daeb5f07d3143f100cf7502b","tarball":"https://registry.npmjs.org/@amritk/lynx-location/-/lynx-location-0.2.2.tgz","fileCount":62,"unpackedSize":199077,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amritk%2flynx-location@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCGgN9SIMXANeCEWWIgYrTUOmUf6QzX7HFgRyxHiyeTjwIhAJ6E+WZYGiVUSSxju2Atb+uI1HsRj829EScHRbloerNP"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:63e14da9-5646-4b14-bdd9-6bd842f07d36"}},"directories":{},"maintainers":[{"name":"amritk","email":"amrit+spam@hockey-community.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/lynx-location_0.2.2_1787351375552_0.755486446227035"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T02:09:33.759Z","modified":"2026-08-21T22:29:36.094Z","0.1.0":"2026-08-05T02:09:34.118Z","0.2.0":"2026-08-05T04:52:26.061Z","0.2.1":"2026-08-05T16:56:52.173Z","0.2.2":"2026-08-21T22:29:35.699Z"},"bugs":{"url":"https://github.com/amritk/mini/issues"},"author":{"name":"amritk"},"license":"MIT","homepage":"https://github.com/amritk/mini/tree/main/packages/lynx-location#readme","keywords":["lynx","location","geolocation","gps","native-module","typescript","mjst"],"repository":{"type":"git","url":"git+https://github.com/amritk/mini.git","directory":"packages/lynx-location"},"description":"Device location for Lynx: an Android and iOS native module, and a promise-shaped facade that reaches it from the main thread.","maintainers":[{"name":"amritk","email":"amrit+spam@hockey-community.com"}],"readme":"# @amritk/lynx-location\n\n**Device location for Lynx.** An Android native module, an iOS native module,\nand a promise-shaped facade that reaches them from a main-thread\n[`@amritk/mini-lynx`](../mini-lynx) tree.\n\n```ts\nimport { getCurrentPosition, getPermissionStatus, requestPermission } from '@amritk/lynx-location'\n\nif ((await getPermissionStatus()) === 'undetermined') await requestPermission()\n\nconst result = await getCurrentPosition({ accuracy: 'high', maximumAge: 30_000 })\nif (result.ok) console.log(result.position.latitude, result.position.longitude)\n```\n\n## Why this exists\n\nLynx ships no location module. Neither does\n[Sparkling](https://github.com/tiktok/Sparkling) — its built-ins are navigation,\nstorage and media, and anything else is a Sparkling Method you write yourself.\nThere is one published community package,\n[`@sigx/lynx-location`](https://www.npmjs.com/package/@sigx/lynx-location), and\nits JavaScript half calls `NativeModules` directly, which is background-thread\nonly — so a `mini-lynx` component importing it gets `undefined` with no error to\nread. Lynx's official answer is \"write native code and send it into your Lynx\ncode\", so that is what this is.\n\n## Install\n\n```sh\nbun add @amritk/lynx-location\n```\n\n`@amritk/mini-lynx-native` comes with it — it is the wire every call travels.\n\n## JavaScript setup\n\nOne line, in your **background** chunk:\n\n```ts\nimport { installNativeBridge } from '@amritk/mini-lynx-native/background'\n\ninstallNativeBridge()\n```\n\nWithout it every call queues forever and nothing says why. `NativeModules` is a\nbackground-thread global and `@amritk/mini-lynx` renders on the main thread, so\nthis package cannot reach the platform without a chunk it does not own\ninstalling the other half. See\n[`@amritk/mini-lynx-native`](../mini-lynx-native) for the reasoning.\n\nThen, anywhere on the main thread:\n\n```tsx\nimport { onCleanup, signal } from '@amritk/mini-lynx'\nimport { type LocationFix, getCurrentPosition, watchPosition } from '@amritk/lynx-location'\n\nconst Map = () => {\n  const position = signal<LocationFix | null>(null)\n\n  getCurrentPosition({ maximumAge: 60_000 }).then((result) => {\n    if (result.ok) position(result.position)\n  })\n\n  onCleanup(\n    watchPosition((update) => {\n      if (update.ok) position(update.position)\n    }, { distanceFilter: 10 }),\n  )\n\n  return <text>{() => (position() ? `${position()?.latitude}, ${position()?.longitude}` : 'locating…')}</text>\n}\n```\n\n## Host-app setup\n\n`lynx.lib.json` declares both native sources, so Lynx's autolinking picks them\nup. What autolinking cannot supply is the strings and entitlements that belong\nto your app.\n\n### Android\n\nThe two permissions are declared in this library's manifest and reach your app\nthrough manifest merging — you do not add them yourself:\n\n```xml\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n```\n\n**Know that this happens.** They appear in your merged manifest, on your Play\nStore listing, and in your data safety form. That is the cost of shipping a\nlocation library, and there is no version of it that avoids the declaration.\n\n`ACCESS_BACKGROUND_LOCATION` is deliberately **not** declared. It is a second\nprompt and a Play Store review conversation, and nothing here can use it.\n\nIf your build does not run Lynx's annotation processor, register the module by\nhand:\n\n```kotlin\nLynxEnv.inst().registerModule(\"MiniLynxLocationModule\", MiniLynxLocationModule::class.java)\n```\n\n### iOS\n\nAdd the usage description to your `Info.plist`. **This one is not optional** —\niOS terminates the app the moment it asks for location without it, and the crash\nlog does say why, but only if you look:\n\n```xml\n<key>NSLocationWhenInUseUsageDescription</key>\n<string>Shows nearby results and centres the map on you.</string>\n```\n\nWrite a real sentence there. It is the text in the system prompt, and it is the\nwhole of what the user has to decide on.\n\nRegister the module where you build your Lynx config:\n\n```objc\n#import <MiniLynxLocation/MiniLynxLocationModule.h>\n\n[config registerModule:MiniLynxLocationModule.class];\n```\n\nThere is nothing to forward from your app delegate — unlike notifications,\nCoreLocation answers the object that asked.\n\n## API\n\n```ts\ngetPermissionStatus(): Promise<LocationPermissionStatus>  // 'undetermined' | 'denied' | 'granted' | 'restricted'\nrequestPermission(request?: LocationPermissionRequest): Promise<LocationPermissionStatus>\n\ngetCurrentPosition(options?: PositionOptions): Promise<LocationResult>\ngetLastKnownPosition(): Promise<LocationFix | null>\n\nisLocationEnabled(): Promise<boolean>    // device-wide switch, NOT permission\nisLocationAvailable(): Promise<boolean>  // is the native module linked at all\n\nwatchPosition(listener: (update: WatchUpdate) => void, options?: WatchOptions): () => void\n\nreverseGeocode(coordinates: Coordinates, options?: ReverseGeocodeOptions): Promise<GeocodeResult>\n```\n\n`LocationResult`, `WatchUpdate` and `GeocodeResult` are discriminated unions —\n`{ ok: true, … }` or `{ ok: false, error, message }` — rather than rejections.\nLynx has no error convention for bridge callbacks, so a failure has to travel as\na value anyway, and \"the user has not granted location\" is an ordinary branch in\na UI rather than an exceptional condition.\n\n### Reverse geocoding\n\n`reverseGeocode` turns coordinates into a postal address. It is the one function\nhere that **never reads the device's own location**, so it needs no permission\nand will never prompt — an app can label a saved venue or a map centre without\nasking the user for anything.\n\n```ts\nconst result = await reverseGeocode({ latitude: 45.5017, longitude: -73.5673 })\nif (result.ok) console.log(result.addresses[0]?.formattedAddress)\n```\n\nA `LocationFix` satisfies `Coordinates`, so the two calls compose without a\nmapping step:\n\n```ts\nconst position = await getCurrentPosition()\nif (position.ok) await reverseGeocode(position.position)\n```\n\nEvery field of a `GeocodeAddress` is nullable and most are usually null — a\ngeocoder answers from whatever its map data holds. `formattedAddress` is built\nby the OS (`getAddressLine` on Android, `CNPostalAddressFormatter` on iOS), so it\nputs each country's postcode where that country puts it; a string assembled from\nthe other fields by hand will not. `isoCountryCode` is the only field stable\nacross locales, which makes it the only one worth storing or branching on.\n\n## The things that actually bite\n\n- **Permission and the device switch are different questions.** A perfectly\n  granted app on a device with Location Services off gets nothing, and sending\n  that user to your app's permission screen shows them a setting that already\n  looks correct. Check `isLocationEnabled()` first; it is why it exists.\n- **You get one prompt, ever.** iOS shows it once per install; Android stops\n  after two dismissals. A second request displays nothing and reports the\n  standing answer. Spend it when the user has just asked for something that\n  needs their location — not on first launch.\n- **`denied` is final, `restricted` is worse.** The route back from `denied` is\n  the system settings app. There is no route back from `restricted`: it is off\n  by parental controls or an MDM profile, and offering a settings link is\n  offering a dead end.\n- **`getCurrentPosition` can take seconds.** A cold radio indoors at `high`\n  accuracy is the worst case and it is not rare, which is why `timeout` defaults\n  to something finite. Set `maximumAge` when an approximate answer will do — it\n  turns a three-second wait into an immediate one.\n- **A watch holds a provider open.** That is a battery cost the user can see in\n  their settings app. Hand the returned function to `onCleanup`.\n- **`heading` is course over ground, not compass heading.** It is derived from\n  consecutive fixes, so a stationary device reports null no matter which way it\n  is pointing.\n- **Foreground only.** Both platforms stop delivering to a backgrounded app.\n  That is the platform working as designed, not a gap to work around.\n- **`WatchOptions.interval` is Android-only.** CoreLocation has no equivalent\n  and decides its own cadence. Pace with `distanceFilter`, which both honour.\n- **Apple rate-limits reverse geocoding, and does not publish the limit.** Their\n  guidance is at most one request per user action. An app that geocodes every\n  row of a list as it scrolls starts getting `network` errors for reasons that\n  have nothing to do with the network. Geocode on demand, cache the answer, and\n  key the cache on rounded coordinates rather than on the address.\n- **`Geocoder.isPresent()` is false on plenty of Android devices.** Anything\n  built without Google's services has no geocoding backend, for the life of the\n  device. That is `unavailable`, and retrying will never help — fall back to\n  showing the coordinates.\n\n## Testing\n\n`@amritk/lynx-location/testing` ships the native module's contract as an\nin-memory fake, which is what this package's own suite runs against:\n\n```ts\nimport { installNativeBridge } from '@amritk/mini-lynx-native/background'\nimport { createFakeContexts, createFakeEmitter } from '@amritk/mini-lynx-native/testing'\nimport { MODULE } from '@amritk/lynx-location'\nimport { createFakeLocation } from '@amritk/lynx-location/testing'\n\nconst contexts = createFakeContexts()\nconst emitter = createFakeEmitter()\nconst location = createFakeLocation(emitter)\n\nsetPeerContext(contexts.mainThread)\ninstallNativeBridge({ peer: contexts.background, emitter, modules: { [MODULE]: location.module } })\n\nlocation.setPermissionStatus('granted')\nlocation.setNextFix({ latitude: 51.5072, longitude: -0.1276, accuracy: 12, /* … */ })\n```\n\nIt reproduces the platforms rather than smoothing them over: a request after a\nrefusal returns the refusal, a device with location switched off fails as\n`locationDisabled` even when permission is granted, and a device with no fix to\ngive times out. A fake friendlier than a device would hide the bugs worth\ncatching.\n\n## Status, and what is actually verified\n\n**Pre-alpha, and nothing here has run on a device.** Three checks of decreasing\nreach stand behind it, and it is worth knowing which one a green run came from:\n\n| Check | Command | Strength |\n| --- | --- | --- |\n| Facade behaviour | `bun run test` | real code, fake platform |\n| Cross-language signatures | `src/native-contract.test.ts` | parses Kotlin + Objective-C, compares to TypeScript |\n| Kotlin compiles + packages | `bun run check:android` | real Lynx AAR, real Android SDK |\n| Objective-C compiles | `pod lib lint` (manual, macOS — not in CI) | real Lynx pod, real iOS SDK |\n\nNone of that is a device. Permission flows, provider selection, what a fix\nactually contains outdoors, whether a watch survives a backgrounding, and\nwhether Lynx's annotation processor registers the module without the generated\nSpec its own template extends are all unverified. See\n[`AGENTS.md`](./AGENTS.md).\n\n## Licence\n\nMIT\n","readmeFilename":"README.md"}