@tileflow/react-native 0.1.0-alpha.6 → 0.1.0-alpha.8
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 +72 -14
- package/android/src/main/java/dev/tileflow/reactnative/AdmissionBootstrap.kt +7 -3
- package/android/src/main/java/dev/tileflow/reactnative/AdmissionBootstrapOkHttpNetwork.kt +3 -1
- package/android/src/main/java/dev/tileflow/reactnative/AdmissionEngine.kt +4 -2
- package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeAdmissionModule.kt +1 -1
- package/dist/{contract-By3URNxS.d.ts → contract-BWT1jxqg.d.ts} +44 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +503 -55
- package/dist/internal/camera.d.ts +1 -1
- package/dist/internal/initial-view.d.ts +1 -1
- package/dist/internal/native-admission-bridge.js +8 -3
- package/dist/internal/native-admission.d.ts +15 -1
- package/dist/internal/native-admission.js +208 -21
- package/dist/internal/native-appearance.d.ts +1 -1
- package/dist/internal/session.d.ts +9 -2
- package/dist/internal/session.js +178 -21
- package/dist/internal/source-state.d.ts +1 -1
- package/ios/TFAdmissionBootstrap.mm +12 -6
- package/ios/TFAdmissionEngine.mm +4 -2
- package/package.json +3 -4
- package/docs/native-admission.md +0 -108
- package/docs/native-configuration.md +0 -210
- package/docs/native-interactions.md +0 -161
- package/docs/native-location.md +0 -148
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
# Native application configuration
|
|
2
|
-
|
|
3
|
-
This guide describes the private application-configuration reader used by the mounted Tileflow
|
|
4
|
-
`Map` in `@tileflow/react-native`. Its root exports the mounted `Map` and public types; the
|
|
5
|
-
configuration reader remains private. Mobile credentials remain application
|
|
6
|
-
configuration: there is no credential prop, JavaScript setter, provider, public configuration
|
|
7
|
-
object or public configuration subpath.
|
|
8
|
-
|
|
9
|
-
Importing `@tileflow/react-native` does not read configuration, install networking, start a session,
|
|
10
|
-
acquire admission or create a native Map. Configuration is read lazily only when a mounted source
|
|
11
|
-
resolves to Hosted session delivery. Follow the [package setup](../README.md) and the
|
|
12
|
-
[native admission guide](native-admission.md) for the exact native dependencies and installation
|
|
13
|
-
order. No Expo config plugin is supplied.
|
|
14
|
-
|
|
15
|
-
## Prerequisites and identity
|
|
16
|
-
|
|
17
|
-
Hosted native production requires a claimed Tileflow account/project, a Hosted Map and its scoped,
|
|
18
|
-
revocable, publishable mobile application credential. The credential authenticates the distributed
|
|
19
|
-
application, not an end user. There is no Tileflow end-user login, account provider or authentication
|
|
20
|
-
hook in this integration. Web deployment with allowed-domain authorization is a different mechanism.
|
|
21
|
-
A compatible SDK/API pair is required; this document is not a publication or availability claim.
|
|
22
|
-
|
|
23
|
-
Use only the publishable mobile credential, whose exact grammar is `tf_public_` followed by
|
|
24
|
-
48 lowercase hexadecimal characters, for a total of 58 ASCII characters. A CLI, deployment,
|
|
25
|
-
administration or other privileged credential must never enter application configuration.
|
|
26
|
-
|
|
27
|
-
The two logical fields are `apiOrigin` and `credential`. `apiOrigin` is the API origin approved by
|
|
28
|
-
the application operator, not a value copied automatically from a remote manifest. The native
|
|
29
|
-
session contract has no implicit origin. The examples below use `api.example.test` and an
|
|
30
|
-
intentionally invalid credential placeholder; replace both in the application build.
|
|
31
|
-
|
|
32
|
-
## Configure iOS
|
|
33
|
-
|
|
34
|
-
In the **application target's Info.plist**, add one `TileflowMobileConfiguration` key of type Array.
|
|
35
|
-
Its two String elements are `apiOrigin=...` and `credential=...`:
|
|
36
|
-
|
|
37
|
-
```xml
|
|
38
|
-
<key>TileflowMobileConfiguration</key>
|
|
39
|
-
<array>
|
|
40
|
-
<string>apiOrigin=https://api.example.test</string>
|
|
41
|
-
<string>credential=YOUR_PUBLISHABLE_MOBILE_CREDENTIAL</string>
|
|
42
|
-
</array>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Place this in the final application plist, not in a pod, framework, MapLibre configuration or
|
|
46
|
-
`InfoPlist.strings`. When Xcode generates the plist, ensure the resulting application target still
|
|
47
|
-
contains one literal array. Application-owned build substitution may supply each string, but
|
|
48
|
-
unresolved placeholders fail validation.
|
|
49
|
-
|
|
50
|
-
The autolinked `TileflowNativeConfiguration` module reads only `NSBundle.mainBundle` when its
|
|
51
|
-
private asynchronous reader is requested. It exports no constants or events. Constructing the
|
|
52
|
-
module, importing the package and mounting a non-session Map do not perform that read.
|
|
53
|
-
|
|
54
|
-
## Configure Android
|
|
55
|
-
|
|
56
|
-
In the application's `android/app/src/main/res/values/tileflow.xml`, add one literal String Array:
|
|
57
|
-
|
|
58
|
-
```xml
|
|
59
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
60
|
-
<resources>
|
|
61
|
-
<string-array name="tileflow_mobile_configuration" translatable="false">
|
|
62
|
-
<item>apiOrigin=https://api.example.test</item>
|
|
63
|
-
<item>credential=YOUR_PUBLISHABLE_MOBILE_CREDENTIAL</item>
|
|
64
|
-
</string-array>
|
|
65
|
-
</resources>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
The array belongs to the application package. Do not use AndroidManifest metadata, BuildConfig,
|
|
69
|
-
a system property, an alias or a second runtime input. Both entries must be literal strings;
|
|
70
|
-
references such as `@string/...`, `@array/...`, theme attributes and styled strings are rejected.
|
|
71
|
-
Build flavors may deliberately provide their own single final application configuration, but each
|
|
72
|
-
resulting application must be checked independently.
|
|
73
|
-
|
|
74
|
-
`TileflowNativeAdmissionPackage` autolinks the configuration reader alongside the private admission
|
|
75
|
-
and surface modules. Constructing those modules does not read configuration or install networking.
|
|
76
|
-
The library includes a resource-shrinker keep declaration for the dynamically located array; the
|
|
77
|
-
application's optimized release build must retain it. The library ships no default configuration
|
|
78
|
-
array or embedded credential.
|
|
79
|
-
|
|
80
|
-
## Array and origin contract
|
|
81
|
-
|
|
82
|
-
Both platforms use the same bounded list of exactly two `key=value` strings. Order is irrelevant;
|
|
83
|
-
keys are case-sensitive. Split only at the first equals sign. Missing, empty, additional,
|
|
84
|
-
wrong-typed or duplicate entries fail closed. Each complete entry is limited to 2,080 UTF-16 code
|
|
85
|
-
units.
|
|
86
|
-
|
|
87
|
-
The application-owned `apiOrigin` is at most 2,048 UTF-16 code units. Normalization is deliberately
|
|
88
|
-
limited to the HTTPS scheme and ASCII hostname, omission of port 443 and removal of one optional
|
|
89
|
-
root slash. For example, application configuration `HTTPS://API.Example.test:443/` becomes
|
|
90
|
-
`https://api.example.test`. Port 8443 remains distinct. The grammar permits ASCII DNS labels or
|
|
91
|
-
canonical dotted-decimal IPv4; IPv6 literals are outside this application-configuration grammar.
|
|
92
|
-
|
|
93
|
-
Ports are decimal 1–65535 without leading zeroes. HTTP, user-info, non-root paths, query strings,
|
|
94
|
-
fragments, whitespace, backslashes, percent escapes, wildcards, trailing host dots, Unicode hostname
|
|
95
|
-
conversion and shortened/octal/hexadecimal/integer IPv4 forms are rejected.
|
|
96
|
-
|
|
97
|
-
The **remote manifest is not normalized into trust**. Its declared `apiUrl` must already be the exact
|
|
98
|
-
canonical string stored in the application snapshot. A trailing slash, explicit default port or
|
|
99
|
-
case variation in the remote declaration is rejected, even if normalizing it would produce the same
|
|
100
|
-
origin. Equality includes scheme, host and non-default port; there is no suffix or subdomain match.
|
|
101
|
-
If both root and map-level API declarations are present, they must agree exactly.
|
|
102
|
-
|
|
103
|
-
## Source-to-session boundary
|
|
104
|
-
|
|
105
|
-
Use the public Native manifest URL returned by an explicit compatible
|
|
106
|
-
[`deploy --with-native`](../../cli/docs/native-artifacts.md#publish-web-and-native-together):
|
|
107
|
-
|
|
108
|
-
```text
|
|
109
|
-
https://api.example.test/maps/map_0123456789abcdef/native/manifest.json
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
The `Map` source remains `{map, manifestUrl}`. `map` is the authored map name, not the managed Map ID.
|
|
113
|
-
The initial document is bounded, one-map, version-1 public metadata. It contains theme names,
|
|
114
|
-
identity, revisions and references, not Style JSON or authority. It receives no credential or grant.
|
|
115
|
-
|
|
116
|
-
The private binding resolver consumes the current resolved Core source, not an executable config or
|
|
117
|
-
a renderer style. Only `map.usageMode === 'session'` can request application configuration. It
|
|
118
|
-
requires the declared Hosted `mapId`, exact `apiUrl`, agreement between the resolved logical map
|
|
119
|
-
name and selected source, and both the original requested URL and final response URL equal to the
|
|
120
|
-
canonical Hosted route for that managed Map. A redirect to another origin, Map, CDN route or query
|
|
121
|
-
alias is rejected. URL identity is a selector checked against the document, not authority.
|
|
122
|
-
|
|
123
|
-
A missing `usageMode` produces the existing direct binding without evaluating configuration only for
|
|
124
|
-
a non-Hosted source. A document obtained from the reserved Hosted Native route cannot omit that mode
|
|
125
|
-
to downgrade into direct delivery. Local, self-hosted and other non-session sources otherwise keep
|
|
126
|
-
their existing account-free behavior. Unknown modes, malformed session metadata, origin mismatches
|
|
127
|
-
or conflicting Map identity fail before a Hosted binding is delivered.
|
|
128
|
-
|
|
129
|
-
The publishable credential is sent **only** to the application's configured API origin at
|
|
130
|
-
`POST /v1/sessions/start`. The existing bootstrap transport does not follow redirects. Neither a
|
|
131
|
-
manifest URL nor a manifest-declared `apiUrl` can select a different credential destination. Styles,
|
|
132
|
-
TileJSON, tiles, sprites, glyphs and fonts use the existing resource grant, never that credential.
|
|
133
|
-
|
|
134
|
-
The resolver itself has no renderer or resource-admission authority. The mounted Map passes the
|
|
135
|
-
acknowledged binding into its private admission/session owner only after source resolution. Creating
|
|
136
|
-
a resolver does not call `acquire()`, and importing the package does not construct a resolver.
|
|
137
|
-
|
|
138
|
-
## Deployment revisions and stale discovery
|
|
139
|
-
|
|
140
|
-
Hosted themes carry mandatory revision hashes and versioned protected style URLs of the form
|
|
141
|
-
`/maps/<mapId>/native/v<deploymentVersion>/<theme>.json`. Every theme in one manifest belongs to the
|
|
142
|
-
same deployment version. The server checks current deployment ownership and verifies stored style
|
|
143
|
-
bytes against the revision. The mounted owner checks the returned style URL and its
|
|
144
|
-
Map/theme/deployment/revision metadata before projecting resources or creating a renderer.
|
|
145
|
-
|
|
146
|
-
If the root protected style cannot be read or fails this correspondence, the owner may discard its
|
|
147
|
-
cached discovery document and reload the canonical manifest **once per explicit source/theme
|
|
148
|
-
selection**. This recovery retains the same session and admission context. A refresh cannot switch
|
|
149
|
-
Map, origin or delivery mode, or move backwards to an older deployment. Child-resource failures do
|
|
150
|
-
not replenish that retry budget. A second failure uses the existing safe error or theme-rollback
|
|
151
|
-
path. It never composes a new active style with stale public metadata silently.
|
|
152
|
-
|
|
153
|
-
A public manifest GET, session start or Map render is not itself a commercial completion event.
|
|
154
|
-
Server completion remains conditional on an eligible protected GET returning 200/206 under the
|
|
155
|
-
existing admission contract. Disabled mobile delivery fails closed even for valid public references.
|
|
156
|
-
|
|
157
|
-
## Mounted ownership, caching and cancellation
|
|
158
|
-
|
|
159
|
-
The native reader caches one immutable application snapshot, or one safe failure, for the
|
|
160
|
-
application process. It does not retain a React context. JavaScript coalesces native reads and copies
|
|
161
|
-
the result into a frozen private value. Each mounted Map still owns an independent pending binding,
|
|
162
|
-
session controller, admission context, callbacks and renderer lifetime. Shared immutable application
|
|
163
|
-
configuration never implies shared grants, counters or source ownership.
|
|
164
|
-
|
|
165
|
-
Source replacement and Map disposal invalidate that owner's in-flight binding immediately. A late
|
|
166
|
-
configuration success or failure cannot deliver authority to a retired owner. Retiring one Map does
|
|
167
|
-
not cancel another Map's access to the process-level immutable configuration snapshot. Configuration
|
|
168
|
-
is not hot-reloaded; restart the application process after changing native values.
|
|
169
|
-
|
|
170
|
-
The configuration reader installs no timeout, timer, background poller or service. One unresolved
|
|
171
|
-
native read can remain pending, but every Map resolver remains independently disposable. Camera,
|
|
172
|
-
resource projection and rendered-readiness logic are owned elsewhere in the mounted Map runtime;
|
|
173
|
-
they are not configuration-reader responsibilities.
|
|
174
|
-
|
|
175
|
-
## Public credential threat model and rotation
|
|
176
|
-
|
|
177
|
-
A credential distributed inside a mobile application is extractable. Native configuration is not a
|
|
178
|
-
secret vault, proof of installation authenticity or end-user authentication. This version does not
|
|
179
|
-
authenticate with bundle ID, package name, signing identity or attestation. Origin binding prevents
|
|
180
|
-
the SDK from forwarding its configured credential to an origin selected by an untrusted manifest;
|
|
181
|
-
it does not stop a party that has copied the publishable credential from making its own requests.
|
|
182
|
-
Scope, revocation and server-side authorization remain necessary.
|
|
183
|
-
|
|
184
|
-
The credential crosses only the private reader/binding/bootstrap path. It is not a native grant and
|
|
185
|
-
is not a resource URL, cache key, public ref field, source state, renderer event or diagnostic.
|
|
186
|
-
Errors use fixed internal codes/messages rather than configured values or native causes. Do not log
|
|
187
|
-
native module responses, credentials, bootstrap bodies or grant material.
|
|
188
|
-
|
|
189
|
-
For rotation, issue a new credential with the intended Map scope, update the same native entries,
|
|
190
|
-
rebuild and distribute the application, then retire the old credential according to the rollout
|
|
191
|
-
policy. Revoking an old credential may stop installed versions that still contain it. Do not repair
|
|
192
|
-
that failure with a JavaScript override or a second credential source.
|
|
193
|
-
|
|
194
|
-
A future Expo plugin, if introduced, would write these same native values rather than create another
|
|
195
|
-
runtime configuration channel. No plugin or end-user login is part of this integration. Selection
|
|
196
|
-
presentation and foreground-location policy remain application-owned; this contract adds neither UI
|
|
197
|
-
nor a location API.
|
|
198
|
-
|
|
199
|
-
## Validation boundary
|
|
200
|
-
|
|
201
|
-
The authored source tests cover grammar, exact origin matching, source/final URL identity, lazy reads,
|
|
202
|
-
safe failures, stale results, bounded discovery recovery, independent resolvers and the absence of a
|
|
203
|
-
public credential surface. Native tests cover parser boundaries, versioned style ownership,
|
|
204
|
-
duplicate/wrong-typed configuration, resource literals, caching and reentrancy. Package tests protect
|
|
205
|
-
autolinking, exact peers, private configuration declarations and archive contents.
|
|
206
|
-
|
|
207
|
-
Those sources are not execution evidence. Local qualification must additionally exercise the final
|
|
208
|
-
iOS Info.plist and Android resource extraction, resource shrinking, bridge registration, cold starts,
|
|
209
|
-
concurrent mounted Maps, direct versus session sources, replacement/disposal, stale public metadata
|
|
210
|
-
and corrected/revoked credentials in the pinned native host.
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Native interaction contract
|
|
2
|
-
|
|
3
|
-
The React Native `Map` accepts portable annotations, semantic interaction bindings, activation
|
|
4
|
-
callbacks and an optional marker renderer. It exposes normalized targets and bounded data. The
|
|
5
|
-
application owns persistent selection and its presentation. Tileflow does not render a popup,
|
|
6
|
-
callout, tooltip, sheet, panel or modal.
|
|
7
|
-
|
|
8
|
-
The mounted implementation uses a private renderer-neutral foundation. It reuses schemas, target
|
|
9
|
-
types and diagnostics from the ordinary `@tileflow/interactions` root without
|
|
10
|
-
importing its browser adapter, DOM implementation or `maplibre-gl`. Native map handles, style
|
|
11
|
-
proofs, query ports and owners are not exported by `@tileflow/react-native`.
|
|
12
|
-
|
|
13
|
-
## Public Map inputs
|
|
14
|
-
|
|
15
|
-
`Map` is generic over the supplied annotation type, so application data remains typed in
|
|
16
|
-
`renderMarker` and `onInteractionEvent`. `annotations` and `interactions` are complete portable
|
|
17
|
-
documents, not patches. The shared annotation and binding validators still accept web presentation
|
|
18
|
-
metadata, but mobile does not use `popup` or `tooltip` fields.
|
|
19
|
-
|
|
20
|
-
`renderMarker` composes marker content only. Tileflow retains the native marker host, coordinate,
|
|
21
|
-
stable key, activation and authoritative accessibility wrapper. Without a renderer, Tileflow shows
|
|
22
|
-
a bounded default marker. Each marker has the annotation label, a 44-by-44-point minimum touch
|
|
23
|
-
target, button semantics and disabled accessibility state. Custom marker content does
|
|
24
|
-
not create another accessible target.
|
|
25
|
-
|
|
26
|
-
`onInteractionEvent` receives `target:activate` events for annotations and semantic POIs.
|
|
27
|
-
`onInteractionDiagnostic` receives fixed structured diagnostics. There is no mobile selection-state
|
|
28
|
-
prop, state callback or popup event. The application can retain the selected target in its own
|
|
29
|
-
state and choose what, if anything, to render.
|
|
30
|
-
|
|
31
|
-
## Input ownership and validation
|
|
32
|
-
|
|
33
|
-
One owner receives complete annotation and interaction-binding inputs. Omitted collections mean
|
|
34
|
-
empty collections, not partial document patches.
|
|
35
|
-
|
|
36
|
-
The owner uses the portable validators before planning any annotation changes. Invalid annotation
|
|
37
|
-
or binding replacements preserve the entire previous valid collection. The initial fallback is an
|
|
38
|
-
empty collection.
|
|
39
|
-
|
|
40
|
-
Inputs are copied and frozen before they become committed values. The portable JSON perimeter
|
|
41
|
-
rejects accessors, unsupported prototypes, non-finite numbers, unsafe keys, cycles, shared object
|
|
42
|
-
references and oversized documents. The native foundation uses the same portable bounds: at most
|
|
43
|
-
1,000 annotations, 100 bindings, 256,000 JSON bytes, depth 64, 20,000 nodes and 50,000 properties per
|
|
44
|
-
document. It does not expand large feature sets into annotation hosts.
|
|
45
|
-
|
|
46
|
-
Diagnostics retain the portable code, level and a fixed bounded message. They do not include raw
|
|
47
|
-
validator paths, input values, physical layer identifiers, style JSON, URLs or native error causes.
|
|
48
|
-
Replacing callbacks alone does not change snapshots or annotation identities.
|
|
49
|
-
|
|
50
|
-
## Annotation reconciliation
|
|
51
|
-
|
|
52
|
-
The private annotation plan contains `create`, `update`, `retain`, `remove` and final `order`.
|
|
53
|
-
Planning uses stable validated annotation IDs. An existing marker ID retains its future host when
|
|
54
|
-
coordinates, data or declarative surfaces change. Its update entry contains the old and new
|
|
55
|
-
validated definitions. New IDs create entries; absent IDs produce removals in previous order.
|
|
56
|
-
Unchanged IDs are retained, and final order follows the new document.
|
|
57
|
-
|
|
58
|
-
An invalid replacement produces no partial creates, updates or removals. The mounted adapter uses
|
|
59
|
-
the annotation ID as the React and native marker identity, so updates and reordering retain the
|
|
60
|
-
compatible host while removal retires it.
|
|
61
|
-
|
|
62
|
-
## Activation without selection ownership
|
|
63
|
-
|
|
64
|
-
A valid annotation activation emits one normalized `target:activate` event with annotation data,
|
|
65
|
-
coordinate and optional binding ID. A semantic POI activation emits the same event type with a
|
|
66
|
-
bounded POI target. No event changes or clears application selection. The application decides how
|
|
67
|
-
to handle removed entities, style changes and dismissal.
|
|
68
|
-
|
|
69
|
-
A syntactically invalid annotation or binding replacement retains the last valid collection. New
|
|
70
|
-
touches, source/style replacement, backgrounding and unmount discard pending semantic queries, so
|
|
71
|
-
late results cannot activate a target from a retired map or style.
|
|
72
|
-
|
|
73
|
-
## Finalized-style query port
|
|
74
|
-
|
|
75
|
-
The semantic adapter receives a private lease for exactly one finalized style on one native Map.
|
|
76
|
-
The lease supplies its style description, an ownership check and a cancelable asynchronous query
|
|
77
|
-
operation. Its ownership check must establish the exact current native style and map, not merely
|
|
78
|
-
compare style JSON. Style replacement must invalidate the old lease before another query can use
|
|
79
|
-
it.
|
|
80
|
-
|
|
81
|
-
Each query receives an immutable request containing the touch point, the relevant declared layer
|
|
82
|
-
IDs and a result limit. A result envelope must echo the identical private request object. The
|
|
83
|
-
platform adapter may construct that envelope only after rechecking native map/style ownership.
|
|
84
|
-
Native handles never cross this neutral boundary. The adapter rejects a response associated with
|
|
85
|
-
another request or Map even when the physical URLs or layer names happen to match.
|
|
86
|
-
|
|
87
|
-
The mounted adapter uses the existing public query on the pinned MapLibre React Native Map. Because
|
|
88
|
-
its iOS and Android serializers omit physical provenance, Tileflow queries one verified semantic
|
|
89
|
-
layer at a time in finalized topmost order. The exact single-layer filter supplies the physical
|
|
90
|
-
layer, source and source-layer identity that the neutral adapter verifies again. Results preserve
|
|
91
|
-
their within-layer order and share one global 512-feature bound. This adds no Swift, Kotlin or
|
|
92
|
-
public query API.
|
|
93
|
-
|
|
94
|
-
A lease becomes current only after the private Tileflow native-surface owner accepts the matching
|
|
95
|
-
style token. A JavaScript style-loaded callback or equal style JSON is insufficient. A newer touch
|
|
96
|
-
rotates the query lease; style or source replacement, backgrounding and unmount permanently retire
|
|
97
|
-
the old proof. Upstream queries have no abort handle, so cancellation is logical: Tileflow settles
|
|
98
|
-
the old operation as stale immediately, stops issuing further layer queries and ignores late
|
|
99
|
-
results.
|
|
100
|
-
|
|
101
|
-
## Semantic POI rules
|
|
102
|
-
|
|
103
|
-
Only finalized `tileflow:interaction-manifest` metadata with exact version 2 is accepted. The
|
|
104
|
-
adapter checks the POI identity convention, deduplication tuple, representation-priority list,
|
|
105
|
-
field mapping, category vocabulary, rendered-topmost ordering and pointer-coordinate anchors.
|
|
106
|
-
The artifact's `animation-frame` frequency field is its existing version-2 vocabulary; it does not
|
|
107
|
-
introduce hover or JavaScript-frame scheduling into the native adapter.
|
|
108
|
-
|
|
109
|
-
Every declared semantic layer must exist exactly once in that same style and match its declared
|
|
110
|
-
source and source-layer. The source must exist. All declared POI representations share one
|
|
111
|
-
source/source-layer feature-ID namespace. The adapter bounds the physical style inventory at 4,096
|
|
112
|
-
layers and the semantic inventory at 256 declared layers. Missing or inconsistent metadata fails
|
|
113
|
-
closed with `SEMANTIC_MANIFEST_MISMATCH`.
|
|
114
|
-
|
|
115
|
-
Queries include only declared layers relevant to the current POI bindings and category filters.
|
|
116
|
-
The port must supply rendered-topmost results. Duplicate representations of one stable feature ID
|
|
117
|
-
use the manifest's representation priority, then layer priority, while retaining the earliest
|
|
118
|
-
rendered position of that identity. Numeric and string IDs are distinct. Features from undeclared
|
|
119
|
-
layers are excluded; an owned feature with a mismatched source or source-layer invalidates the
|
|
120
|
-
query rather than being relabeled.
|
|
121
|
-
|
|
122
|
-
A query processes at most 512 returned features. The port must report overflow rather than silently
|
|
123
|
-
truncate a result whose omitted features could change representation selection. The native
|
|
124
|
-
boundary emits only the existing semantic POI target shape, without physical layer identities.
|
|
125
|
-
Properties are restricted to category, filter rank, size rank, icon, name and type. Category and
|
|
126
|
-
rank ranges follow the portable contract; icon/type use bounded snake-case values and text uses the
|
|
127
|
-
portable 4,096-character limit. Unknown fields and unsafe property accessors are not forwarded.
|
|
128
|
-
|
|
129
|
-
Touch is the only activation modality in this adapter. There is no inferred hover, tooltip,
|
|
130
|
-
long-press or keyboard behavior. An activation without a stable feature ID can still emit a target
|
|
131
|
-
event. When present, feature IDs are safe integers or nonempty strings of at most 128 characters;
|
|
132
|
-
no property-based fallback ID is invented.
|
|
133
|
-
|
|
134
|
-
## Retirement and observation
|
|
135
|
-
|
|
136
|
-
Each mounted Map has independent inputs, annotation plans, style proofs,
|
|
137
|
-
query tickets and subscribers. No authority, Map identity or asynchronous operation is shared
|
|
138
|
-
between Maps. Marker and map delivery for one touch share one claim, so a marker activation cannot
|
|
139
|
-
also activate a semantic feature underneath it.
|
|
140
|
-
|
|
141
|
-
Ownership is checked again after asynchronous results and before event publication. Late results
|
|
142
|
-
from disposed owners or retired styles are inert. Reentrant cancellation, observer replacement,
|
|
143
|
-
exceptions and rejected observer promises cannot transfer ownership to another Map. Disposal is
|
|
144
|
-
idempotent and exposes a final safe empty snapshot plus the annotation removal plan.
|
|
145
|
-
|
|
146
|
-
Selection presentation remains outside this contract. The application owns its layout, focus,
|
|
147
|
-
dismissal and accessibility behavior. Device location is also separate and requires an explicit
|
|
148
|
-
application-owned permission and provider flow.
|
|
149
|
-
|
|
150
|
-
## Location composes as an ordinary application annotation
|
|
151
|
-
|
|
152
|
-
Foreground device location does not extend the interaction owner or semantic query port. An
|
|
153
|
-
application that chooses to display its latest validated fix can provide one stable-ID annotation
|
|
154
|
-
through the existing `annotations` input, and remove that annotation when permission is revoked or
|
|
155
|
-
the provider becomes unavailable. Tileflow does not request permission, start observation or
|
|
156
|
-
recenter the camera when that annotation changes.
|
|
157
|
-
|
|
158
|
-
See [Application-owned foreground location](./native-location.md) for the source-checkout recipe.
|
|
159
|
-
The application remains responsible for provider lifetime, privacy policy, recenter controls and
|
|
160
|
-
status/error UI, and the recipe does not alter the rule that all selection presentation remains
|
|
161
|
-
application-owned.
|
package/docs/native-location.md
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# Application-owned foreground location
|
|
2
|
-
|
|
3
|
-
`@tileflow/react-native` does not own device location. A Tileflow `Map` renders normally without a
|
|
4
|
-
location permission, provider, hook or native location module. The application decides whether to
|
|
5
|
-
request foreground permission, which provider to use, when observation starts and stops, what fix is
|
|
6
|
-
displayed, whether recentering is offered, and what status or error UI is appropriate.
|
|
7
|
-
|
|
8
|
-
This guide describes a source-checkout recipe built only from the existing public `Map`, controlled
|
|
9
|
-
camera and annotation contracts. It is not a new Tileflow runtime API and it does not add a location
|
|
10
|
-
provider to the package.
|
|
11
|
-
|
|
12
|
-
## Boundary
|
|
13
|
-
|
|
14
|
-
The package deliberately does not provide any of the following:
|
|
15
|
-
|
|
16
|
-
- a Tileflow location component, hook, provider or permission API;
|
|
17
|
-
- an iOS or Android location permission declaration;
|
|
18
|
-
- a dependency on Expo Location, a geolocation package or another location provider;
|
|
19
|
-
- a background task, background permission or location-history store;
|
|
20
|
-
- a credential/session field for device location;
|
|
21
|
-
- a location analytics event or precise-coordinate telemetry path;
|
|
22
|
-
- a GeoIP fallback for device location;
|
|
23
|
-
- implicit permission requests or tracking when `Map` mounts.
|
|
24
|
-
|
|
25
|
-
The application must configure any native permission strings, manifest entries and provider setup
|
|
26
|
-
required by the provider it chooses. Those application settings are separate from Tileflow's native
|
|
27
|
-
Hosted credential configuration.
|
|
28
|
-
|
|
29
|
-
## Source-checkout recipe
|
|
30
|
-
|
|
31
|
-
`../harness/ForegroundLocationExample.tsx` is a compile-only example owned by this package. Its
|
|
32
|
-
provider boundary is injected:
|
|
33
|
-
|
|
34
|
-
```ts
|
|
35
|
-
export type ApplicationForegroundLocationAdapter = Readonly<{
|
|
36
|
-
requestPermission(): Promise<
|
|
37
|
-
'granted-precise' | 'granted-approximate' | 'denied' | 'unavailable'
|
|
38
|
-
>;
|
|
39
|
-
observe(listener: (update: ApplicationLocationObservation) => void): () => void;
|
|
40
|
-
}>;
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
No concrete provider is imported. The adapter is application code: it translates the provider's
|
|
44
|
-
permission and foreground observation APIs into this small recipe-specific shape. The example and
|
|
45
|
-
its state helper live under `harness/`, are absent from package exports, and are excluded from
|
|
46
|
-
packed runtime files.
|
|
47
|
-
|
|
48
|
-
## Explicit application state
|
|
49
|
-
|
|
50
|
-
The recipe models these states without unmounting the Map:
|
|
51
|
-
|
|
52
|
-
| State | Meaning | Location annotation |
|
|
53
|
-
| --------------------- | ------------------------------------------------------------ | ---------------------------- |
|
|
54
|
-
| `idle` | The application has not requested permission. | none |
|
|
55
|
-
| `requesting` | An explicit application action started a permission request. | none |
|
|
56
|
-
| `granted-precise` | Foreground policy allows precise observation. | one marker after a valid fix |
|
|
57
|
-
| `granted-approximate` | Foreground policy allows approximate observation. | one marker after a valid fix |
|
|
58
|
-
| `denied` | The permission request was denied. | none |
|
|
59
|
-
| `unavailable` | Permission/provider setup failed or emitted invalid data. | none |
|
|
60
|
-
| `revoked` | A previously granted observation reported revocation. | removed immediately |
|
|
61
|
-
|
|
62
|
-
Construction is inert: it neither requests permission nor starts observation. The example's **Use
|
|
63
|
-
my location** control is the only permission-request trigger. A rejected provider promise is reduced
|
|
64
|
-
to the application-level `unavailable` state; raw provider exceptions are not forwarded into Map
|
|
65
|
-
props or Tileflow callbacks.
|
|
66
|
-
|
|
67
|
-
## Validate before Map props
|
|
68
|
-
|
|
69
|
-
The adapter output is treated as untrusted runtime data even though the TypeScript adapter is typed.
|
|
70
|
-
The recipe accepts only a plain record with exactly `longitude`, `latitude` and `accuracy` data
|
|
71
|
-
properties. Longitude must be finite and within `[-180, 180]`, latitude finite and within
|
|
72
|
-
`[-90, 90]`, and accuracy finite and nonnegative. Accessors, extra provider fields, invalid
|
|
73
|
-
prototypes and non-finite values fail closed.
|
|
74
|
-
|
|
75
|
-
Only a validated fix is converted to an annotation:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
{
|
|
79
|
-
id: 'application-foreground-location',
|
|
80
|
-
kind: 'marker',
|
|
81
|
-
ariaLabel: 'Current location',
|
|
82
|
-
coordinate: [longitude, latitude],
|
|
83
|
-
data: {accuracyMeters: accuracy, precision: 'precise'},
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Approximate permission uses the same stable ID and an `Approximate current location` label. The
|
|
88
|
-
stable ID lets the existing annotation reconciler update one marker host instead of recreating a
|
|
89
|
-
new marker for every fix. Revocation, denial or provider failure removes the annotation by returning
|
|
90
|
-
an empty annotation collection.
|
|
91
|
-
|
|
92
|
-
The marker uses the existing accessible Tileflow annotation wrapper. This recipe does not add a
|
|
93
|
-
location-specific native marker component.
|
|
94
|
-
|
|
95
|
-
## Foreground observation lifetime
|
|
96
|
-
|
|
97
|
-
Observation starts only when both conditions are true:
|
|
98
|
-
|
|
99
|
-
1. the application is in the foreground; and
|
|
100
|
-
2. its current permission state is `granted-precise` or `granted-approximate`.
|
|
101
|
-
|
|
102
|
-
`AppState` is application-side orchestration in the example. Moving to background synchronously
|
|
103
|
-
retires the current observation token and calls the provider cleanup. Returning to foreground
|
|
104
|
-
starts a new observation only if the last application permission policy still allows it. Denied,
|
|
105
|
-
revoked and unavailable states do not restart observation automatically.
|
|
106
|
-
|
|
107
|
-
The React effect owns a replayable `mount()` epoch. Its cleanup immediately retires the current
|
|
108
|
-
observation and any pending permission/provider callback without terminally disposing the
|
|
109
|
-
controller. A StrictMode setup replay may therefore mount the same controller again; if the retained
|
|
110
|
-
settled permission state is granted and the application is foregrounded, observation restarts
|
|
111
|
-
without another permission prompt. If cleanup interrupted an in-flight permission request, that
|
|
112
|
-
request is retired and the last settled application state is restored instead of accepting its late
|
|
113
|
-
result. A real unmount or adapter replacement uses the same cleanup boundary, so late callbacks are
|
|
114
|
-
inert even though no timing heuristic distinguishes them from a replay. The recipe does not persist
|
|
115
|
-
fixes or observation history.
|
|
116
|
-
|
|
117
|
-
`dispose()` remains a separate terminal operation for an owner that will never mount again. The
|
|
118
|
-
React example does not use terminal disposal for ordinary effect cleanup.
|
|
119
|
-
|
|
120
|
-
## Recenter is explicit
|
|
121
|
-
|
|
122
|
-
A new fix changes only the application-owned annotation. It does **not** change camera state.
|
|
123
|
-
|
|
124
|
-
The example keeps the existing complete controlled `Map` view. An explicit **Recenter** action copies
|
|
125
|
-
the latest validated coordinate into that controlled view while preserving zoom, bearing and pitch.
|
|
126
|
-
The recipe uses no camera animation API or duration, so it introduces no animated movement for
|
|
127
|
-
reduced-motion users. Applications that later add their own animated camera affordance must apply
|
|
128
|
-
their own reduced-motion policy before doing so.
|
|
129
|
-
|
|
130
|
-
Gestures continue to update the same controlled view through `onViewChange`; receiving another
|
|
131
|
-
location fix never overwrites that user-driven camera state.
|
|
132
|
-
|
|
133
|
-
## Privacy and product scope
|
|
134
|
-
|
|
135
|
-
The sample keeps only the latest in-memory fix needed for its marker. It does not store history,
|
|
136
|
-
send coordinates to analytics, derive a device fix from GeoIP, start background tracking or attach
|
|
137
|
-
location to Tileflow sessions/admission. Status and error presentation are application UI.
|
|
138
|
-
|
|
139
|
-
Location also does not change the interaction presentation boundary. Tileflow annotations and
|
|
140
|
-
semantic targets remain primitives and data; the application still owns any popup, callout,
|
|
141
|
-
tooltip, sheet, panel, modal or other selection presentation.
|
|
142
|
-
|
|
143
|
-
## Qualification
|
|
144
|
-
|
|
145
|
-
The source files describe the intended application contract; they are not evidence that a provider,
|
|
146
|
-
permission prompt, simulator/device scenario, native build, package publication or Hosted service
|
|
147
|
-
was executed. Typecheck the source-checkout harness and qualify the chosen provider in the
|
|
148
|
-
application that owns its permission and privacy policy.
|