@tileflow/react-native 0.0.0-bootstrap.0 → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +216 -4
  2. package/TileflowNativeAdmission.podspec +34 -0
  3. package/android/build.gradle +43 -0
  4. package/android/src/main/AndroidManifest.xml +3 -0
  5. package/android/src/main/java/dev/tileflow/reactnative/AdmissionBootstrap.kt +144 -0
  6. package/android/src/main/java/dev/tileflow/reactnative/AdmissionBootstrapOkHttpNetwork.kt +89 -0
  7. package/android/src/main/java/dev/tileflow/reactnative/AdmissionCatalog.kt +137 -0
  8. package/android/src/main/java/dev/tileflow/reactnative/AdmissionDocumentScope.kt +22 -0
  9. package/android/src/main/java/dev/tileflow/reactnative/AdmissionEngine.kt +335 -0
  10. package/android/src/main/java/dev/tileflow/reactnative/AdmissionModuleProvider.kt +68 -0
  11. package/android/src/main/java/dev/tileflow/reactnative/AdmissionOkHttpNetwork.kt +86 -0
  12. package/android/src/main/java/dev/tileflow/reactnative/AdmissionProviderLease.kt +56 -0
  13. package/android/src/main/java/dev/tileflow/reactnative/AdmissionTypes.kt +85 -0
  14. package/android/src/main/java/dev/tileflow/reactnative/AdmissionUrl.kt +100 -0
  15. package/android/src/main/java/dev/tileflow/reactnative/HandlerAdmissionScheduler.kt +16 -0
  16. package/android/src/main/java/dev/tileflow/reactnative/MobileConfiguration.kt +95 -0
  17. package/android/src/main/java/dev/tileflow/reactnative/MobileConfigurationResources.kt +43 -0
  18. package/android/src/main/java/dev/tileflow/reactnative/NativeDocumentOkHttpNetwork.kt +101 -0
  19. package/android/src/main/java/dev/tileflow/reactnative/NativeDocumentRegistry.kt +136 -0
  20. package/android/src/main/java/dev/tileflow/reactnative/NativeSurfaceState.kt +115 -0
  21. package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeAdmissionModule.kt +236 -0
  22. package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeAdmissionPackage.kt +16 -0
  23. package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeConfigurationModule.kt +43 -0
  24. package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeDocumentsModule.kt +82 -0
  25. package/android/src/main/java/dev/tileflow/reactnative/TileflowNativeSurfaceModule.kt +277 -0
  26. package/android/src/main/res/raw/tileflow_configuration_keep.xml +3 -0
  27. package/dist/contract-DWs-lDPo.d.ts +144 -0
  28. package/dist/index.d.ts +13 -0
  29. package/dist/index.js +6989 -0
  30. package/dist/internal/camera.d.ts +65 -0
  31. package/dist/internal/camera.js +325 -0
  32. package/dist/internal/hosted-binding.d.ts +18 -0
  33. package/dist/internal/hosted-binding.js +277 -0
  34. package/dist/internal/initial-view.d.ts +11 -0
  35. package/dist/internal/initial-view.js +8 -0
  36. package/dist/internal/interactions.d.ts +76 -0
  37. package/dist/internal/interactions.js +794 -0
  38. package/dist/internal/native-admission-bridge.d.ts +29 -0
  39. package/dist/internal/native-admission-bridge.js +351 -0
  40. package/dist/internal/native-admission.d.ts +78 -0
  41. package/dist/internal/native-admission.js +1614 -0
  42. package/dist/internal/native-appearance.d.ts +21 -0
  43. package/dist/internal/native-appearance.js +110 -0
  44. package/dist/internal/native-configuration-bridge.d.ts +9 -0
  45. package/dist/internal/native-configuration-bridge.js +343 -0
  46. package/dist/internal/session.d.ts +125 -0
  47. package/dist/internal/session.js +887 -0
  48. package/dist/internal/source-state.d.ts +11 -0
  49. package/dist/internal/source-state.js +26 -0
  50. package/dist/native-admission-contract-k7LKE1vW.d.ts +89 -0
  51. package/docs/native-admission.md +108 -0
  52. package/docs/native-configuration.md +210 -0
  53. package/docs/native-interactions.md +161 -0
  54. package/docs/native-location.md +148 -0
  55. package/ios/TFAdmissionBootstrap.h +17 -0
  56. package/ios/TFAdmissionBootstrap.mm +168 -0
  57. package/ios/TFAdmissionCatalog.h +13 -0
  58. package/ios/TFAdmissionCatalog.mm +193 -0
  59. package/ios/TFAdmissionDocumentScope.h +7 -0
  60. package/ios/TFAdmissionDocumentScope.mm +45 -0
  61. package/ios/TFAdmissionEngine.h +57 -0
  62. package/ios/TFAdmissionEngine.mm +371 -0
  63. package/ios/TFAdmissionInstallation.h +27 -0
  64. package/ios/TFAdmissionInstallation.mm +117 -0
  65. package/ios/TFAdmissionNetwork.h +16 -0
  66. package/ios/TFAdmissionNetwork.mm +268 -0
  67. package/ios/TFAdmissionURL.mm +116 -0
  68. package/ios/TFDocumentBounds.h +9 -0
  69. package/ios/TFDocumentBounds.mm +19 -0
  70. package/ios/TFMobileConfiguration.h +23 -0
  71. package/ios/TFMobileConfiguration.mm +139 -0
  72. package/ios/TFNativeAdmissionURLProtocol.mm +69 -0
  73. package/ios/TFNativeDocumentRegistry.h +28 -0
  74. package/ios/TFNativeDocumentRegistry.mm +193 -0
  75. package/ios/TFNativeDocumentURL.h +6 -0
  76. package/ios/TFNativeSurfaceState.h +28 -0
  77. package/ios/TFNativeSurfaceState.mm +128 -0
  78. package/ios/TileflowNativeAdmission.h +9 -0
  79. package/ios/TileflowNativeAdmission.mm +184 -0
  80. package/ios/TileflowNativeConfiguration.mm +41 -0
  81. package/ios/TileflowNativeDocuments.h +12 -0
  82. package/ios/TileflowNativeDocuments.mm +105 -0
  83. package/ios/TileflowNativeSurface.mm +403 -0
  84. package/ios/tileflow_native_admission.rb +45 -0
  85. package/package.json +51 -7
  86. package/react-native.config.cjs +13 -0
@@ -0,0 +1,21 @@
1
+ import { y as MapThemeSelection, f as MapColorScheme } from '../contract-DWs-lDPo.js';
2
+ import '@maplibre/maplibre-react-native';
3
+ import 'react';
4
+ import 'react-native';
5
+ import '@tileflow/core/native';
6
+ import '@tileflow/interactions';
7
+
8
+ type AppearanceState = Readonly<{
9
+ status: 'available';
10
+ colorScheme: MapColorScheme;
11
+ }> | Readonly<{
12
+ status: 'unavailable';
13
+ }>;
14
+ type AppearanceSelection = Readonly<{
15
+ theme?: MapThemeSelection;
16
+ }>;
17
+
18
+ /** Internal native boundary. Package import is inert; only a mounted system theme subscribes. */
19
+ declare function observeNativeAppearance(selection: AppearanceSelection, listener: (state: AppearanceState) => void): () => void;
20
+
21
+ export { observeNativeAppearance };
@@ -0,0 +1,110 @@
1
+ // src/native-appearance.ts
2
+ import { Appearance } from "react-native";
3
+
4
+ // src/appearance.ts
5
+ var light = Object.freeze({ status: "available", colorScheme: "light" });
6
+ var dark = Object.freeze({ status: "available", colorScheme: "dark" });
7
+ var unavailable = Object.freeze({ status: "unavailable" });
8
+ function normalize(value) {
9
+ return value === "light" ? light : value === "dark" ? dark : unavailable;
10
+ }
11
+ function normalizeEvent(value) {
12
+ try {
13
+ if (!value || typeof value !== "object") return unavailable;
14
+ const property = Object.getOwnPropertyDescriptor(value, "colorScheme");
15
+ return property && "value" in property ? normalize(property.value) : unavailable;
16
+ } catch {
17
+ return unavailable;
18
+ }
19
+ }
20
+ function remove(subscription) {
21
+ try {
22
+ subscription?.remove();
23
+ } catch {
24
+ }
25
+ }
26
+ function createAppearanceObserver(port) {
27
+ const listeners = /* @__PURE__ */ new Set();
28
+ let connection;
29
+ const notify = (entry, state) => {
30
+ if (!listeners.has(entry) || entry.last === state) return;
31
+ entry.last = state;
32
+ try {
33
+ void Promise.resolve(entry.notify(state)).catch(() => void 0);
34
+ } catch {
35
+ }
36
+ };
37
+ const publish = (current, state) => {
38
+ if (connection !== current || current.closed || current.current === state) return;
39
+ current.current = state;
40
+ for (const entry of [...listeners]) {
41
+ if (connection !== current || current.closed || current.current !== state) break;
42
+ notify(entry, state);
43
+ }
44
+ };
45
+ const activate = () => {
46
+ const current = { closed: false, acceptEvents: true, revision: 0 };
47
+ connection = current;
48
+ let subscription;
49
+ try {
50
+ subscription = port.addChangeListener((event) => {
51
+ if (connection !== current || current.closed || !current.acceptEvents) return;
52
+ current.revision++;
53
+ publish(current, normalizeEvent(event));
54
+ });
55
+ } catch {
56
+ current.acceptEvents = false;
57
+ publish(current, unavailable);
58
+ return;
59
+ }
60
+ if (connection !== current || current.closed) {
61
+ remove(subscription);
62
+ return;
63
+ }
64
+ current.subscription = subscription;
65
+ let initial;
66
+ try {
67
+ initial = normalize(port.getColorScheme());
68
+ } catch {
69
+ initial = unavailable;
70
+ }
71
+ if (current.revision === 0) publish(current, initial);
72
+ };
73
+ return {
74
+ subscribe(selection, listener) {
75
+ if (selection.theme !== "system") return () => void 0;
76
+ if (typeof listener !== "function") throw new TypeError("Expected an appearance listener.");
77
+ const entry = { notify: listener };
78
+ listeners.add(entry);
79
+ if (!connection) activate();
80
+ if (connection?.current) notify(entry, connection.current);
81
+ let released = false;
82
+ return () => {
83
+ if (released) return;
84
+ released = true;
85
+ listeners.delete(entry);
86
+ if (listeners.size !== 0) return;
87
+ const previous = connection;
88
+ connection = void 0;
89
+ if (!previous) return;
90
+ previous.closed = true;
91
+ previous.acceptEvents = false;
92
+ const subscription = previous.subscription;
93
+ previous.subscription = void 0;
94
+ remove(subscription);
95
+ };
96
+ }
97
+ };
98
+ }
99
+
100
+ // src/native-appearance.ts
101
+ var observer = createAppearanceObserver({
102
+ getColorScheme: () => Appearance.getColorScheme(),
103
+ addChangeListener: (listener) => Appearance.addChangeListener(listener)
104
+ });
105
+ function observeNativeAppearance(selection, listener) {
106
+ return observer.subscribe(selection, listener);
107
+ }
108
+ export {
109
+ observeNativeAppearance
110
+ };
@@ -0,0 +1,9 @@
1
+ import { HostedNativeSessionBinding } from './session.js';
2
+ import * as _tileflow_core_native from '@tileflow/core/native';
3
+
4
+ declare function createReactNativeHostedBindingResolver(): Readonly<{
5
+ replace(source: _tileflow_core_native.TileflowNativeSourceState): Promise<HostedNativeSessionBinding>;
6
+ dispose(): void;
7
+ }>;
8
+
9
+ export { createReactNativeHostedBindingResolver };
@@ -0,0 +1,343 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/native-configuration-bridge.ts
6
+ import { NativeModules } from "react-native";
7
+
8
+ // src/mobile-configuration.ts
9
+ var messages = {
10
+ NATIVE_CONFIGURATION_INVALID: "Native application configuration is invalid.",
11
+ NATIVE_CONFIGURATION_UNAVAILABLE: "Native application configuration is unavailable.",
12
+ NATIVE_CONFIGURATION_SOURCE_INVALID: "Hosted source metadata is invalid.",
13
+ NATIVE_CONFIGURATION_ORIGIN_MISMATCH: "Hosted source origin is not approved by the application.",
14
+ NATIVE_CONFIGURATION_REPLACED: "Hosted binding resolution was replaced.",
15
+ NATIVE_CONFIGURATION_DISPOSED: "Hosted binding resolution is disposed."
16
+ };
17
+ var originPattern = /^([Hh][Tt][Tt][Pp][Ss]):\/\/([A-Za-z0-9.-]+)(?::([1-9][0-9]{0,4}))?\/?$/u;
18
+ var NativeConfigurationError = class extends Error {
19
+ constructor(code) {
20
+ super(messages[code]);
21
+ __publicField(this, "code");
22
+ this.name = "NativeConfigurationError";
23
+ this.code = code;
24
+ }
25
+ };
26
+ function invalid() {
27
+ throw new NativeConfigurationError("NATIVE_CONFIGURATION_INVALID");
28
+ }
29
+ function canonicalMobileApiOrigin(value) {
30
+ if (typeof value !== "string" || value.length === 0 || value.length > 2048) return invalid();
31
+ const match = originPattern.exec(value);
32
+ if (!match || match[0] !== value) return invalid();
33
+ const host = match[2].toLowerCase();
34
+ const labels = host.split(".");
35
+ if (host.length > 253 || labels.some((label) => !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/u.test(label))) {
36
+ return invalid();
37
+ }
38
+ const last = labels[labels.length - 1];
39
+ if (!/^[a-z]/u.test(last)) {
40
+ if (labels.length !== 4 || labels.some((label) => !/^(?:0|[1-9][0-9]{0,2})$/u.test(label) || Number(label) > 255)) {
41
+ return invalid();
42
+ }
43
+ }
44
+ const port = match[3] === void 0 ? 443 : Number(match[3]);
45
+ if (port > 65535) return invalid();
46
+ return `https://${host}${port === 443 ? "" : `:${port}`}`;
47
+ }
48
+ function configurationRecord(value) {
49
+ if (!value || typeof value !== "object" || Array.isArray(value)) return invalid();
50
+ const prototype = Object.getPrototypeOf(value);
51
+ if (prototype !== Object.prototype && prototype !== null) return invalid();
52
+ const keys = Reflect.ownKeys(value);
53
+ if (keys.length > 32) return invalid();
54
+ const result = /* @__PURE__ */ Object.create(null);
55
+ for (const key of keys) {
56
+ if (typeof key !== "string") return invalid();
57
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
58
+ if (!descriptor || !("value" in descriptor)) return invalid();
59
+ result[key] = descriptor.value;
60
+ }
61
+ return result;
62
+ }
63
+ function snapshotMobileConfiguration(value) {
64
+ try {
65
+ const data = configurationRecord(value);
66
+ if (Object.keys(data).length !== 2 || !Object.hasOwn(data, "apiOrigin") || !Object.hasOwn(data, "credential") || typeof data.credential !== "string" || data.credential.length !== 58 || !/^tf_public_[0-9a-f]{48}$/u.test(data.credential)) {
67
+ return invalid();
68
+ }
69
+ const apiOrigin = canonicalMobileApiOrigin(data.apiOrigin);
70
+ const snapshot = Object.defineProperties(
71
+ {},
72
+ {
73
+ apiOrigin: { value: apiOrigin },
74
+ credential: { value: data.credential }
75
+ }
76
+ );
77
+ return Object.freeze(snapshot);
78
+ } catch {
79
+ return invalid();
80
+ }
81
+ }
82
+
83
+ // src/hosted-manifest-identity.ts
84
+ var mapPattern = /^map_[A-Za-z0-9_-]{16}$/u;
85
+ var themePattern = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/u;
86
+ var revisionPattern = /^[a-f0-9]{64}$/u;
87
+ function record(value) {
88
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
89
+ const prototype = Object.getPrototypeOf(value);
90
+ if (prototype !== Object.prototype && prototype !== null) throw new Error();
91
+ return value;
92
+ }
93
+ function field(value, name) {
94
+ const descriptor = Object.getOwnPropertyDescriptor(record(value), name);
95
+ if (!descriptor) return void 0;
96
+ if (!descriptor.enumerable || !("value" in descriptor)) throw new Error();
97
+ return descriptor.value;
98
+ }
99
+ function names(value, maximum) {
100
+ const keys = Reflect.ownKeys(record(value));
101
+ if (!keys.length || keys.length > maximum || keys.some((key) => typeof key !== "string"))
102
+ throw new Error();
103
+ return keys;
104
+ }
105
+ function reservedManifest(value) {
106
+ if (typeof value !== "string" || value.length > 2048) throw new Error();
107
+ return /^https:\/\/[^/?#]+\/maps\/[^/?#]+\/native\//iu.test(decodeURIComponent(value));
108
+ }
109
+ function exactApiOrigin(value) {
110
+ if (typeof value !== "string" || canonicalMobileApiOrigin(value) !== value) throw new Error();
111
+ return value;
112
+ }
113
+ function styleVersion(url, origin, mapId, theme) {
114
+ if (typeof url !== "string" || url.length > 2048) throw new Error();
115
+ const prefix = `${origin}/maps/${mapId}/native/v`;
116
+ const suffix = `/${theme}.json`;
117
+ if (!url.startsWith(prefix) || !url.endsWith(suffix)) throw new Error();
118
+ const raw = url.slice(prefix.length, -suffix.length);
119
+ if (!/^[1-9][0-9]{0,15}$/u.test(raw)) throw new Error();
120
+ const version = Number(raw);
121
+ if (!Number.isSafeInteger(version)) throw new Error();
122
+ return version;
123
+ }
124
+ function snapshotHostedNativeManifestIdentity(source) {
125
+ try {
126
+ if (field(source, "status") !== "ready") throw new Error();
127
+ const map = field(source, "map");
128
+ const mode = field(map, "usageMode");
129
+ const input = field(source, "source");
130
+ const sourceUrl = field(input, "manifestUrl");
131
+ const finalUrl = field(source, "manifestUrl");
132
+ if (mode === void 0) {
133
+ if (reservedManifest(sourceUrl) || reservedManifest(finalUrl)) throw new Error();
134
+ return null;
135
+ }
136
+ if (mode !== "session") throw new Error();
137
+ const mapId = field(map, "mapId");
138
+ const name = field(map, "name");
139
+ if (typeof mapId !== "string" || !mapPattern.test(mapId) || typeof name !== "string" || !themePattern.test(name) || name !== field(input, "map"))
140
+ throw new Error();
141
+ const apiOrigin = exactApiOrigin(field(map, "apiUrl"));
142
+ const expected = `${apiOrigin}/maps/${mapId}/native/manifest.json`;
143
+ if (sourceUrl !== expected || finalUrl !== expected) throw new Error();
144
+ const manifest = field(source, "manifest");
145
+ const maps = field(manifest, "maps");
146
+ if (field(manifest, "version") !== 1 || names(maps, 1)[0] !== name) throw new Error();
147
+ const declared = field(maps, name);
148
+ if (field(declared, "mapId") !== mapId || field(declared, "usageMode") !== "session")
149
+ throw new Error();
150
+ const rootApi = field(manifest, "apiUrl");
151
+ const declaredApi = field(declared, "apiUrl") ?? rootApi;
152
+ if (declaredApi !== apiOrigin || rootApi !== void 0 && rootApi !== apiOrigin)
153
+ throw new Error();
154
+ const themes = field(map, "themes");
155
+ const declaredThemes = field(declared, "themes");
156
+ const themeNames = names(themes, 64).sort();
157
+ if (themeNames.join("\0") !== names(declaredThemes, 64).sort().join("\0") || field(map, "defaultTheme") !== field(declared, "defaultTheme"))
158
+ throw new Error();
159
+ let deploymentVersion;
160
+ for (const themeName of themeNames) {
161
+ if (!themePattern.test(themeName)) throw new Error();
162
+ const theme2 = field(themes, themeName);
163
+ const original = field(declaredThemes, themeName);
164
+ const revision = field(theme2, "revision");
165
+ const styleUrl = field(theme2, "styleUrl");
166
+ if (typeof revision !== "string" || !revisionPattern.test(revision) || revision !== field(original, "revision") || styleUrl !== field(original, "styleUrl") || field(theme2, "colorScheme") !== field(original, "colorScheme"))
167
+ throw new Error();
168
+ const version = styleVersion(styleUrl, apiOrigin, mapId, themeName);
169
+ if (deploymentVersion !== void 0 && deploymentVersion !== version) throw new Error();
170
+ deploymentVersion = version;
171
+ }
172
+ const selected = field(source, "theme");
173
+ const selectedName = field(selected, "name");
174
+ if (typeof selectedName !== "string" || !themeNames.includes(selectedName)) throw new Error();
175
+ const theme = field(themes, selectedName);
176
+ if (field(selected, "styleUrl") !== field(theme, "styleUrl") || field(selected, "revision") !== field(theme, "revision"))
177
+ throw new Error();
178
+ return Object.freeze({ mapId, apiOrigin, deploymentVersion });
179
+ } catch {
180
+ throw new NativeConfigurationError("NATIVE_CONFIGURATION_SOURCE_INVALID");
181
+ }
182
+ }
183
+
184
+ // src/hosted-binding.ts
185
+ function bind(metadata, configuration) {
186
+ const snapshot = snapshotMobileConfiguration(configuration);
187
+ if (snapshot.apiOrigin !== metadata.apiOrigin) {
188
+ throw new NativeConfigurationError("NATIVE_CONFIGURATION_ORIGIN_MISMATCH");
189
+ }
190
+ const binding = Object.defineProperties(
191
+ { kind: "hosted", mapId: metadata.mapId },
192
+ {
193
+ apiOrigin: { value: snapshot.apiOrigin },
194
+ credential: { value: snapshot.credential }
195
+ }
196
+ );
197
+ return Object.freeze(binding);
198
+ }
199
+ function createHostedNativeBindingResolver(readConfiguration) {
200
+ let disposed = false;
201
+ let generation = 0;
202
+ let active;
203
+ return Object.freeze({
204
+ replace(source) {
205
+ if (disposed) {
206
+ return Promise.reject(new NativeConfigurationError("NATIVE_CONFIGURATION_DISPOSED"));
207
+ }
208
+ if (generation >= Number.MAX_SAFE_INTEGER) {
209
+ return Promise.reject(new NativeConfigurationError("NATIVE_CONFIGURATION_SOURCE_INVALID"));
210
+ }
211
+ const sequence = ++generation;
212
+ let resolve;
213
+ let reject;
214
+ const result = new Promise((yes, no) => {
215
+ resolve = yes;
216
+ reject = no;
217
+ });
218
+ void result.catch(() => void 0);
219
+ const previous = active;
220
+ const own = { reject };
221
+ active = own;
222
+ const current = () => !disposed && generation === sequence && active === own;
223
+ previous?.reject(new NativeConfigurationError("NATIVE_CONFIGURATION_REPLACED"));
224
+ let metadata;
225
+ try {
226
+ metadata = snapshotHostedNativeManifestIdentity(source);
227
+ } catch {
228
+ if (current()) {
229
+ active = void 0;
230
+ reject(new NativeConfigurationError("NATIVE_CONFIGURATION_SOURCE_INVALID"));
231
+ }
232
+ return result;
233
+ }
234
+ if (!current()) return result;
235
+ if (!metadata) {
236
+ active = void 0;
237
+ resolve(Object.freeze({ kind: "direct" }));
238
+ return result;
239
+ }
240
+ const selected = metadata;
241
+ void Promise.resolve().then(() => {
242
+ if (!current()) return void 0;
243
+ return readConfiguration();
244
+ }).then((configuration) => {
245
+ if (!current()) return;
246
+ const binding = bind(selected, configuration);
247
+ if (!current()) return;
248
+ active = void 0;
249
+ resolve(binding);
250
+ }).catch((error) => {
251
+ if (!current()) return;
252
+ let code;
253
+ try {
254
+ if (error && typeof error === "object") {
255
+ code = Object.getOwnPropertyDescriptor(error, "code")?.value;
256
+ }
257
+ } catch {
258
+ }
259
+ if (!current()) return;
260
+ active = void 0;
261
+ reject(
262
+ new NativeConfigurationError(
263
+ code === "NATIVE_CONFIGURATION_INVALID" || code === "NATIVE_CONFIGURATION_ORIGIN_MISMATCH" ? code : "NATIVE_CONFIGURATION_UNAVAILABLE"
264
+ )
265
+ );
266
+ });
267
+ return result;
268
+ },
269
+ dispose() {
270
+ if (disposed) return;
271
+ disposed = true;
272
+ const previous = active;
273
+ active = void 0;
274
+ previous?.reject(new NativeConfigurationError("NATIVE_CONFIGURATION_DISPOSED"));
275
+ }
276
+ });
277
+ }
278
+
279
+ // src/native-configuration-reader.ts
280
+ function createNativeConfigurationReader(locate) {
281
+ let pending;
282
+ let owner;
283
+ let read;
284
+ let failure;
285
+ const checkOwner = () => {
286
+ try {
287
+ if (failure || !owner || locate() !== owner || owner.readConfiguration !== read) {
288
+ throw new Error();
289
+ }
290
+ } catch {
291
+ failure = "NATIVE_CONFIGURATION_UNAVAILABLE";
292
+ throw new NativeConfigurationError(failure);
293
+ }
294
+ };
295
+ return Object.freeze({
296
+ read() {
297
+ if (!pending) {
298
+ pending = Promise.resolve().then(() => {
299
+ const module = locate();
300
+ if (!module || typeof module !== "object") throw new Error();
301
+ const method = module.readConfiguration;
302
+ if (typeof method !== "function") throw new Error();
303
+ owner = module;
304
+ read = method;
305
+ return method.call(owner);
306
+ }).then((raw) => {
307
+ checkOwner();
308
+ return snapshotMobileConfiguration(raw);
309
+ }).catch((error) => {
310
+ let code;
311
+ try {
312
+ if (error && typeof error === "object") {
313
+ code = Object.getOwnPropertyDescriptor(error, "code")?.value;
314
+ }
315
+ } catch {
316
+ }
317
+ failure = code === "NATIVE_CONFIGURATION_INVALID" ? "NATIVE_CONFIGURATION_INVALID" : "NATIVE_CONFIGURATION_UNAVAILABLE";
318
+ throw new NativeConfigurationError(failure);
319
+ });
320
+ }
321
+ return pending.then(
322
+ (configuration) => {
323
+ checkOwner();
324
+ return configuration;
325
+ },
326
+ () => {
327
+ throw new NativeConfigurationError(failure ?? "NATIVE_CONFIGURATION_UNAVAILABLE");
328
+ }
329
+ );
330
+ }
331
+ });
332
+ }
333
+
334
+ // src/native-configuration-bridge.ts
335
+ var applicationConfiguration = createNativeConfigurationReader(
336
+ () => NativeModules.TileflowNativeConfiguration
337
+ );
338
+ function createReactNativeHostedBindingResolver() {
339
+ return createHostedNativeBindingResolver(applicationConfiguration.read);
340
+ }
341
+ export {
342
+ createReactNativeHostedBindingResolver
343
+ };
@@ -0,0 +1,125 @@
1
+ type NativeSessionResourceScope = 'style' | 'tilejson' | 'tile' | 'sprite' | 'glyph' | 'font';
2
+ type HostedNativeSessionBinding = Readonly<{
3
+ kind: 'hosted';
4
+ apiOrigin: string;
5
+ credential: string;
6
+ mapId: string;
7
+ surfaceId?: string;
8
+ }> | Readonly<{
9
+ kind: 'direct';
10
+ }>;
11
+ type HostedNativeSessionAbortSignal = Readonly<{
12
+ aborted: boolean;
13
+ addEventListener(type: 'abort', listener: () => void, options?: {
14
+ once?: boolean;
15
+ }): void;
16
+ removeEventListener(type: 'abort', listener: () => void): void;
17
+ }>;
18
+ type HostedNativeSessionFetchInit = Readonly<{
19
+ body: string;
20
+ credentials: 'omit';
21
+ headers: Readonly<Record<string, string>>;
22
+ method: 'POST';
23
+ signal: HostedNativeSessionAbortSignal;
24
+ }>;
25
+ type HostedNativeSessionBodyReader = Readonly<{
26
+ read(): Promise<{
27
+ done: true;
28
+ value?: undefined;
29
+ } | {
30
+ done: false;
31
+ value: Uint8Array;
32
+ }>;
33
+ cancel(): void | Promise<void>;
34
+ }>;
35
+ type HostedNativeSessionFetchResponse = Readonly<{
36
+ status: number;
37
+ headers: Readonly<{
38
+ get(name: string): string | null;
39
+ }>;
40
+ body: Readonly<{
41
+ getReader(): HostedNativeSessionBodyReader;
42
+ }> | null;
43
+ }>;
44
+ type HostedNativeSessionFetch = (url: string, init: HostedNativeSessionFetchInit) => Promise<HostedNativeSessionFetchResponse>;
45
+ type HostedNativeSessionErrorCode = 'NATIVE_SESSION_INPUT_INVALID' | 'NATIVE_SESSION_RESPONSE_TOO_LARGE' | 'NATIVE_SESSION_RESPONSE_UTF8_INVALID' | 'NATIVE_SESSION_RESPONSE_JSON_INVALID' | 'NATIVE_SESSION_RESPONSE_INVALID' | 'NATIVE_SESSION_CREDENTIAL_REJECTED' | 'NATIVE_SESSION_MAP_MISMATCH' | 'NATIVE_SESSION_MAP_NOT_FOUND' | 'NATIVE_SESSION_QUOTA_EXCEEDED' | 'NATIVE_SESSION_REJECTED' | 'NATIVE_SESSION_UNAVAILABLE' | 'NATIVE_SESSION_REPLACED' | 'NATIVE_SESSION_DISPOSED';
46
+ type HostedNativeSessionErrorKind = 'terminal' | 'recoverable' | 'cancelled';
47
+ declare class HostedNativeSessionError extends Error {
48
+ readonly code: HostedNativeSessionErrorCode;
49
+ readonly kind: HostedNativeSessionErrorKind;
50
+ constructor(code: HostedNativeSessionErrorCode);
51
+ }
52
+ type HostedNativeSessionAuthority = Readonly<{
53
+ grant: string;
54
+ mapId: string;
55
+ sessionId: string;
56
+ surfaceId: string;
57
+ credentialId: string;
58
+ credentialRevision: number;
59
+ deliveryPolicyRevision: number;
60
+ issuedAt: string;
61
+ serverTime: string;
62
+ expiresAt: string;
63
+ meterMode: 'disabled' | 'shadow' | 'enforced';
64
+ disposition: 'unmetered' | 'ordinary' | 'unbilled_fail_open';
65
+ resourceOrigins: readonly string[];
66
+ resourceScopes: readonly NativeSessionResourceScope[];
67
+ tilesetIds: readonly string[];
68
+ }>;
69
+ /** Private graph classification data; it cannot authorize a resource request. */
70
+ type HostedNativeResourcePolicy = Readonly<Pick<HostedNativeSessionAuthority, 'mapId' | 'resourceOrigins' | 'resourceScopes' | 'tilesetIds'>>;
71
+ type SafeError = Readonly<{
72
+ code: HostedNativeSessionErrorCode;
73
+ kind: HostedNativeSessionErrorKind;
74
+ }>;
75
+ type Lifecycle = 'foreground' | 'background';
76
+ type HostedNativeSessionState = Readonly<{
77
+ status: 'idle';
78
+ source: 'direct';
79
+ lifecycle: Lifecycle;
80
+ }> | Readonly<{
81
+ status: 'idle' | 'loading';
82
+ source: 'hosted';
83
+ lifecycle: Lifecycle;
84
+ mapId: string;
85
+ sessionId: string;
86
+ }> | Readonly<{
87
+ status: 'ready';
88
+ source: 'hosted';
89
+ lifecycle: Lifecycle;
90
+ mapId: string;
91
+ sessionId: string;
92
+ surfaceId: string;
93
+ credentialId: string;
94
+ credentialRevision: number;
95
+ deliveryPolicyRevision: number;
96
+ }> | Readonly<{
97
+ status: 'error';
98
+ source: 'hosted';
99
+ lifecycle: Lifecycle;
100
+ mapId: string;
101
+ sessionId: string;
102
+ error: SafeError;
103
+ }> | Readonly<{
104
+ status: 'disposed';
105
+ lifecycle: 'disposed';
106
+ }>;
107
+ type HostedNativeSessionController = Readonly<{
108
+ readonly state: HostedNativeSessionState;
109
+ acquire(): Promise<HostedNativeSessionAuthority | null>;
110
+ prepare?(): Promise<HostedNativeResourcePolicy | null>;
111
+ transportBudget(authority: HostedNativeSessionAuthority): number;
112
+ background(): void;
113
+ resume(): Promise<void>;
114
+ replaceBinding(binding: HostedNativeSessionBinding): void;
115
+ subscribe(listener: (state: HostedNativeSessionState) => void): () => void;
116
+ dispose(): void;
117
+ }>;
118
+ declare function createHostedNativeSessionController(input: {
119
+ binding: HostedNativeSessionBinding;
120
+ fetch: HostedNativeSessionFetch;
121
+ now: () => Date;
122
+ sessionIdFactory: () => string;
123
+ }): HostedNativeSessionController;
124
+
125
+ export { type HostedNativeResourcePolicy, type HostedNativeSessionAbortSignal, type HostedNativeSessionAuthority, type HostedNativeSessionBinding, type HostedNativeSessionBodyReader, type HostedNativeSessionController, HostedNativeSessionError, type HostedNativeSessionErrorCode, type HostedNativeSessionErrorKind, type HostedNativeSessionFetch, type HostedNativeSessionFetchInit, type HostedNativeSessionFetchResponse, type HostedNativeSessionState, type NativeSessionResourceScope, createHostedNativeSessionController };