@tileflow/react-native 0.1.0-alpha.7 → 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 +11 -16
- package/dist/{contract-BaK24QZD.d.ts → contract-BWT1jxqg.d.ts} +10 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +57 -24
- package/dist/internal/camera.d.ts +1 -1
- package/dist/internal/initial-view.d.ts +1 -1
- package/dist/internal/native-admission.d.ts +1 -0
- package/dist/internal/native-admission.js +47 -21
- package/dist/internal/native-appearance.d.ts +1 -1
- package/dist/internal/session.d.ts +4 -1
- package/dist/internal/session.js +46 -20
- package/dist/internal/source-state.d.ts +1 -1
- package/package.json +3 -4
- package/docs/native-admission.md +0 -124
- package/docs/native-configuration.md +0 -210
- package/docs/native-interactions.md +0 -161
- package/docs/native-location.md +0 -148
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tileflow/react-native
|
|
2
2
|
|
|
3
|
-
`@tileflow/react-native` provides a Tileflow `Map` backed by MapLibre Native on iOS and Android. It is pre-release.
|
|
3
|
+
`@tileflow/react-native` provides a Tileflow `Map` backed by MapLibre Native on iOS and Android. It is pre-release. Publication requires the repository’s protected release workflow.
|
|
4
4
|
|
|
5
5
|
The package targets exactly React 19.2.0, React Native 0.83.10 and `@maplibre/maplibre-react-native` 11.5.0, with MapLibre Native Android 13.6.1 and iOS 6.31.0 through the pinned integration below. Expo consumers use Expo 55.0.31 with a native development build; Expo Go does not contain the required native modules.
|
|
6
6
|
|
|
@@ -99,7 +99,7 @@ Theme and `timeOfDay` changes cross-fade over 450 ms by default: a snapshot of t
|
|
|
99
99
|
<Map source={source} themeBlend={{themes: ['night', 'dusk', 'day'], position}} style={{flex: 1}} />
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
The first blend of a set of themes prepares every theme's style and replaces the native style once; moving `position` later changes the map without loading. Removing `themeBlend` returns to `theme`. Both keep the same native Map, context and session, and `ready` events wait for the fade. The device's reduce-motion setting changes at once. See [theme transitions and blends](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/
|
|
102
|
+
The first blend of a set of themes prepares every theme's style and replaces the native style once; moving `position` later changes the map without loading. Removing `themeBlend` returns to `theme`. Both keep the same native Map, context and session, and `ready` events wait for the fade. The device's reduce-motion setting changes at once. See [theme transitions and blends](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for what follows the position on native maps.
|
|
103
103
|
|
|
104
104
|
## Boundary choropleths
|
|
105
105
|
|
|
@@ -132,8 +132,7 @@ export function UnemploymentMap({
|
|
|
132
132
|
|
|
133
133
|
Values survive theme changes: they are set again once the new style has loaded. `values: null`
|
|
134
134
|
removes them. Rows keyed by codes the polygons do not carry are joined before they reach the app,
|
|
135
|
-
on a server or at build time
|
|
136
|
-
[boundary areas and choropleths](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/boundary-areas-and-choropleths.md#join-by-codes-the-polygons-do-not-carry).
|
|
135
|
+
on a server or at build time.
|
|
137
136
|
|
|
138
137
|
## Camera
|
|
139
138
|
|
|
@@ -178,16 +177,12 @@ Relative URLs are resolved with Core's native URL policy. Protected resources ar
|
|
|
178
177
|
|
|
179
178
|
Glyph templates use a finite set of exact font-stack expansions. A later theme may extend that same template only through an acknowledged append-only finite union; it cannot change the resource scope, origin or identity.
|
|
180
179
|
|
|
181
|
-
See [Private native resource admission](./docs/native-admission.md) for the transport and security boundaries.
|
|
182
|
-
|
|
183
180
|
## Hosted mobile application configuration
|
|
184
181
|
|
|
185
182
|
Hosted native session delivery uses a scoped, revocable, publishable **mobile application credential** configured once in the native application. It authenticates the distributed application, not its end user. The manifest supplies `mapId`, `apiUrl` and `usageMode`; Tileflow requires the manifest API origin to exactly match the configured canonical HTTPS origin before bootstrap.
|
|
186
183
|
|
|
187
184
|
There is intentionally no credential prop, JS setter, Provider, client object, package-name/bundle-ID authentication or attestation path in this version.
|
|
188
185
|
|
|
189
|
-
See [Native application configuration](./docs/native-configuration.md) for the exact Android resource and iOS Info.plist keys, credential grammar, origin normalization, rotation/revocation guidance and threat model.
|
|
190
|
-
|
|
191
186
|
## Map options and presentation
|
|
192
187
|
|
|
193
188
|
The public `mapOptions` object remains a positive allowlist. It includes the currently supported gesture/control options only. Style inputs, request transformation, headers and upstream lifecycle callbacks remain owned by Tileflow. Runtime validation rejects forged extra keys without reflecting their values.
|
|
@@ -208,7 +203,7 @@ The public lifecycle surface remains:
|
|
|
208
203
|
|
|
209
204
|
`getSourceState()` returns only the last safe projected source snapshot. Errors use existing bounded codes/fields/kinds. No URL, response body, native event, credential, grant, session object, native handle or raw cause enters public callbacks, refs or serializable state.
|
|
210
205
|
|
|
211
|
-
`onError` reports `source-error`, `renderer-error` and, for Hosted session delivery, `session-error`. A `session-error` means Tileflow refused the session: the mobile credential was rejected (`NATIVE_SESSION_CREDENTIAL_REJECTED`), it does not authorize the Map (`NATIVE_SESSION_MAP_MISMATCH`), the Map was not found (`NATIVE_SESSION_MAP_NOT_FOUND`)
|
|
206
|
+
`onError` reports `source-error`, `renderer-error` and, for Hosted session delivery, `session-error`. A `session-error` means Tileflow refused the session: the mobile credential was rejected (`NATIVE_SESSION_CREDENTIAL_REJECTED`), it does not authorize the Map (`NATIVE_SESSION_MAP_MISMATCH`), the Map was not found (`NATIVE_SESSION_MAP_NOT_FOUND`), its view or spending limit was reached (`NATIVE_SESSION_QUOTA_EXCEEDED`), or the service refused the session for another reason that trying again cannot change (`NATIVE_SESSION_REJECTED`), such as a Map that does not use session delivery. For `NATIVE_SESSION_REJECTED`, `event.error.reason` is the service's code when it sent one, for example `MOBILE_SESSION_MODE_REQUIRED`; it is a bounded identifier, never a message or response body. A `session-error` can arrive after the first load, when a renewal is refused. The map keeps what it has drawn but loads nothing new until you call `ref.retry()` or change the source:
|
|
212
207
|
|
|
213
208
|
```tsx
|
|
214
209
|
import {Map, type MapRef} from '@tileflow/react-native';
|
|
@@ -226,6 +221,11 @@ export function StoreMap() {
|
|
|
226
221
|
event.error.code === 'NATIVE_SESSION_QUOTA_EXCEEDED'
|
|
227
222
|
) {
|
|
228
223
|
// Show your own notice; call map.current?.retry() once the limit is raised.
|
|
224
|
+
} else if (
|
|
225
|
+
event.type === 'session-error' &&
|
|
226
|
+
event.error.code === 'NATIVE_SESSION_REJECTED'
|
|
227
|
+
) {
|
|
228
|
+
// event.error.reason, such as 'MOBILE_SESSION_MODE_REQUIRED', names the cause.
|
|
229
229
|
}
|
|
230
230
|
}}
|
|
231
231
|
style={{flex: 1}}
|
|
@@ -247,7 +247,7 @@ $MLRN.post_install(installer)
|
|
|
247
247
|
tileflow_native_admission_post_install(installer)
|
|
248
248
|
```
|
|
249
249
|
|
|
250
|
-
Do not add a second MapLibre Native CocoaPod.
|
|
250
|
+
Do not add a second MapLibre Native CocoaPod.
|
|
251
251
|
|
|
252
252
|
## Source-checkout harness
|
|
253
253
|
|
|
@@ -276,8 +276,7 @@ remain in native vector or GeoJSON layers and are selected through semantic rend
|
|
|
276
276
|
queries rather than thousands of React marker views.
|
|
277
277
|
|
|
278
278
|
The application owns persistent selection and its presentation. The SDK emits normalized
|
|
279
|
-
annotation or POI targets but no popup, callout, tooltip, sheet, panel or modal renderer.
|
|
280
|
-
[Native interaction contract](./docs/native-interactions.md).
|
|
279
|
+
annotation or POI targets but no popup, callout, tooltip, sheet, panel or modal renderer.
|
|
281
280
|
|
|
282
281
|
## Current boundary
|
|
283
282
|
|
|
@@ -297,7 +296,3 @@ Source and tests describe contracts; they do not establish that a native build,
|
|
|
297
296
|
fix arrives. Applications can compose a validated foreground fix through the existing accessible
|
|
298
297
|
annotation and controlled-camera contracts while keeping permission, provider lifetime, privacy
|
|
299
298
|
policy, status UI and recenter controls outside Tileflow.
|
|
300
|
-
|
|
301
|
-
See [Application-owned foreground location](./docs/native-location.md) for the package-owned
|
|
302
|
-
source-checkout recipe. The recipe is excluded from package exports and packed runtime files and
|
|
303
|
-
imports no concrete location provider.
|
|
@@ -110,13 +110,19 @@ type MapSourceState = Readonly<{
|
|
|
110
110
|
error: MapSourceError;
|
|
111
111
|
}>;
|
|
112
112
|
/**
|
|
113
|
-
* The Hosted session stopped: its credential, Map or quota was rejected
|
|
114
|
-
*
|
|
115
|
-
*
|
|
113
|
+
* The Hosted session stopped: its credential, Map or quota was rejected, or Tileflow refused the
|
|
114
|
+
* session for another reason that trying again will not change (`NATIVE_SESSION_REJECTED`). The map
|
|
115
|
+
* keeps what it has drawn and loads nothing new until `ref.retry()` or another source. Service
|
|
116
|
+
* outages and rate limits retry on their own and are not reported.
|
|
116
117
|
*/
|
|
117
118
|
type MapSessionError = Readonly<{
|
|
118
|
-
code: 'NATIVE_SESSION_CREDENTIAL_REJECTED' | 'NATIVE_SESSION_MAP_MISMATCH' | 'NATIVE_SESSION_MAP_NOT_FOUND' | 'NATIVE_SESSION_QUOTA_EXCEEDED' | 'NATIVE_SESSION_INPUT_INVALID';
|
|
119
|
+
code: 'NATIVE_SESSION_CREDENTIAL_REJECTED' | 'NATIVE_SESSION_MAP_MISMATCH' | 'NATIVE_SESSION_MAP_NOT_FOUND' | 'NATIVE_SESSION_QUOTA_EXCEEDED' | 'NATIVE_SESSION_REJECTED' | 'NATIVE_SESSION_INPUT_INVALID';
|
|
119
120
|
kind: 'terminal';
|
|
121
|
+
/**
|
|
122
|
+
* For `NATIVE_SESSION_REJECTED`, the service's code when its answer carried one, such as
|
|
123
|
+
* `MOBILE_SESSION_MODE_REQUIRED`. A bounded identifier, never a message or response body.
|
|
124
|
+
*/
|
|
125
|
+
reason?: string;
|
|
120
126
|
}>;
|
|
121
127
|
type MapRef = Readonly<{
|
|
122
128
|
/** A synchronous read of the last source snapshot. Does not trigger loading or native commands. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { TileflowAnnotation } from '@tileflow/interactions';
|
|
3
3
|
export { TileflowAnnotation, TileflowInteractionBinding, TileflowInteractionCoordinate, TileflowInteractionDiagnostic, TileflowPoiCategory, TileflowResolvedAnnotationTarget, TileflowResolvedPoiFeatureTarget } from '@tileflow/interactions';
|
|
4
|
-
import { d as MapProps } from './contract-
|
|
5
|
-
export { e as MapBaseProps, f as MapBoundaryFeatureState, c as MapCameraProps, g as MapColorScheme, h as MapErrorEvent, i as MapEventHandlers, b as MapInitialViewInputs, j as MapInteractionEvent, k as MapInteractionProps, l as MapLoadEvent, m as MapMarkerRenderContext, n as MapMarkerRenderer, o as MapOptions, p as MapPresentationProps, q as MapReadinessChangeEvent, r as MapRef, s as MapSelection, t as MapSessionError, u as MapSource, v as MapSourceError, w as MapSourceProps, x as MapSourceState, y as MapTheme, z as MapThemeBlend, A as MapThemeChangeEvent, B as MapThemeSelection, C as MapThemeTransition, M as MapView, a as MapViewChangeEvent } from './contract-
|
|
4
|
+
import { d as MapProps } from './contract-BWT1jxqg.js';
|
|
5
|
+
export { e as MapBaseProps, f as MapBoundaryFeatureState, c as MapCameraProps, g as MapColorScheme, h as MapErrorEvent, i as MapEventHandlers, b as MapInitialViewInputs, j as MapInteractionEvent, k as MapInteractionProps, l as MapLoadEvent, m as MapMarkerRenderContext, n as MapMarkerRenderer, o as MapOptions, p as MapPresentationProps, q as MapReadinessChangeEvent, r as MapRef, s as MapSelection, t as MapSessionError, u as MapSource, v as MapSourceError, w as MapSourceProps, x as MapSourceState, y as MapTheme, z as MapThemeBlend, A as MapThemeChangeEvent, B as MapThemeSelection, C as MapThemeTransition, M as MapView, a as MapViewChangeEvent } from './contract-BWT1jxqg.js';
|
|
6
6
|
import '@maplibre/maplibre-react-native';
|
|
7
7
|
import 'react-native';
|
|
8
8
|
import '@tileflow/core/native';
|
package/dist/index.js
CHANGED
|
@@ -1965,6 +1965,8 @@ var RETRY_LIMIT_MS = 6e4;
|
|
|
1965
1965
|
var RETRY_AFTER_LIMIT_MS = 15 * 60 * 1e3;
|
|
1966
1966
|
var RETRY_AFTER_SECONDS = /^\d{1,10}$/u;
|
|
1967
1967
|
var QUOTA_CODES = /* @__PURE__ */ new Set(["COMMERCIAL_MAP_LIMIT_REACHED", "COMMERCIAL_SPENDING_LIMIT_REACHED"]);
|
|
1968
|
+
var SERVICE_CODE = /^[A-Z][A-Z0-9_]{0,63}$/u;
|
|
1969
|
+
var SERVICE_CODE_BODY_LIMIT = 4096;
|
|
1968
1970
|
var MOBILE_CREDENTIAL = /^tf_public_[0-9a-f]{48}$/u;
|
|
1969
1971
|
var MAP_ID = /^map_[A-Za-z0-9_-]{16}$/u;
|
|
1970
1972
|
var CREDENTIAL_ID = /^key_[A-Za-z0-9_-]{8,80}$/u;
|
|
@@ -2008,7 +2010,8 @@ var TERMINAL_CODES = /* @__PURE__ */ new Set([
|
|
|
2008
2010
|
"NATIVE_SESSION_CREDENTIAL_REJECTED",
|
|
2009
2011
|
"NATIVE_SESSION_MAP_MISMATCH",
|
|
2010
2012
|
"NATIVE_SESSION_MAP_NOT_FOUND",
|
|
2011
|
-
"NATIVE_SESSION_QUOTA_EXCEEDED"
|
|
2013
|
+
"NATIVE_SESSION_QUOTA_EXCEEDED",
|
|
2014
|
+
"NATIVE_SESSION_REJECTED"
|
|
2012
2015
|
]);
|
|
2013
2016
|
var ERROR_MESSAGES = {
|
|
2014
2017
|
NATIVE_SESSION_INPUT_INVALID: "Native session configuration is invalid.",
|
|
@@ -2027,13 +2030,16 @@ var ERROR_MESSAGES = {
|
|
|
2027
2030
|
NATIVE_SESSION_DISPOSED: "Native session controller is disposed."
|
|
2028
2031
|
};
|
|
2029
2032
|
var HostedNativeSessionError = class extends Error {
|
|
2030
|
-
constructor(code) {
|
|
2033
|
+
constructor(code, reason) {
|
|
2031
2034
|
super(ERROR_MESSAGES[code]);
|
|
2032
2035
|
__publicField(this, "code");
|
|
2033
2036
|
__publicField(this, "kind");
|
|
2034
2037
|
this.name = "HostedNativeSessionError";
|
|
2035
2038
|
this.code = code;
|
|
2036
2039
|
this.kind = errorKind(code);
|
|
2040
|
+
if (code === "NATIVE_SESSION_REJECTED" && typeof reason === "string" && SERVICE_CODE.test(reason)) {
|
|
2041
|
+
this.reason = reason;
|
|
2042
|
+
}
|
|
2037
2043
|
}
|
|
2038
2044
|
};
|
|
2039
2045
|
function createHostedNativeSessionController(input) {
|
|
@@ -2162,10 +2168,10 @@ function createHostedNativeSessionController(input) {
|
|
|
2162
2168
|
if (retryAt === null || at >= retryAt) failures = Math.min(failures + 1, 16);
|
|
2163
2169
|
const backoff = Math.min(RETRY_INITIAL_MS * 2 ** (failures - 1), RETRY_LIMIT_MS);
|
|
2164
2170
|
retryAt = Math.max(retryAt ?? at, at + Math.max(backoff, retryAfterDelays.get(error) ?? 0));
|
|
2165
|
-
retryError =
|
|
2171
|
+
retryError = safeError(error);
|
|
2166
2172
|
}
|
|
2167
2173
|
function rotateIfRequired(at) {
|
|
2168
|
-
if (terminal) throw
|
|
2174
|
+
if (terminal) throw errorFrom(terminal);
|
|
2169
2175
|
if (!activeSession || binding.kind !== "hosted") return;
|
|
2170
2176
|
if (at - activeSession.startedAt < ROTATION_AGE_MS && activeSession.requestCount < ROTATION_REQUEST_LIMIT) {
|
|
2171
2177
|
return;
|
|
@@ -2199,7 +2205,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2199
2205
|
return current;
|
|
2200
2206
|
}
|
|
2201
2207
|
async function ensureAuthority(session, at) {
|
|
2202
|
-
if (terminal) throw
|
|
2208
|
+
if (terminal) throw errorFrom(terminal);
|
|
2203
2209
|
if (session.authority && session.authority.clockEpoch === clock.epoch && session.authority.validUntil - at > REFRESH_MARGIN_MS) {
|
|
2204
2210
|
return { authority: session.authority, session };
|
|
2205
2211
|
}
|
|
@@ -2211,7 +2217,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2211
2217
|
if (session.authority && session.authority.clockEpoch === clock.epoch && session.authority.validUntil > at) {
|
|
2212
2218
|
return { authority: session.authority, session };
|
|
2213
2219
|
}
|
|
2214
|
-
throw
|
|
2220
|
+
throw errorFrom(retryError);
|
|
2215
2221
|
}
|
|
2216
2222
|
const operationBinding = binding;
|
|
2217
2223
|
const abort = new SessionAbortController();
|
|
@@ -2238,14 +2244,16 @@ function createHostedNativeSessionController(input) {
|
|
|
2238
2244
|
const normalized = abort.signal.aborted ? abort.error() : normalizeError(error);
|
|
2239
2245
|
const target = latestSession(session);
|
|
2240
2246
|
if (normalized.kind === "terminal" && binding === operationBinding && !terminal) {
|
|
2241
|
-
const failure3 =
|
|
2247
|
+
const failure3 = safeError(normalized);
|
|
2242
2248
|
terminal = failure3;
|
|
2243
2249
|
const rejectedSession = activeSession;
|
|
2244
2250
|
if (rejectedSession) {
|
|
2245
2251
|
rejectedSession.authority = null;
|
|
2246
2252
|
rejectedSession.error = failure3;
|
|
2247
2253
|
}
|
|
2248
|
-
for (const pending of [...operations])
|
|
2254
|
+
for (const pending of [...operations]) {
|
|
2255
|
+
pending.abort(failure3.code, failure3.reason);
|
|
2256
|
+
}
|
|
2249
2257
|
if (binding === operationBinding && rejectedSession) {
|
|
2250
2258
|
publishSession(rejectedSession, "error", failure3);
|
|
2251
2259
|
}
|
|
@@ -2254,7 +2262,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2254
2262
|
delayRetry(normalized);
|
|
2255
2263
|
}
|
|
2256
2264
|
if (normalized.code !== "NATIVE_SESSION_REPLACED" && normalized.code !== "NATIVE_SESSION_DISPOSED") {
|
|
2257
|
-
target.error =
|
|
2265
|
+
target.error = safeError(normalized);
|
|
2258
2266
|
publishSession(target, "error", target.error);
|
|
2259
2267
|
}
|
|
2260
2268
|
throw normalized;
|
|
@@ -2280,7 +2288,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2280
2288
|
if (abort.signal.aborted) throw abort.error();
|
|
2281
2289
|
const expectedSurfaceId = session.authority?.public.surfaceId ?? session.requestedSurfaceId;
|
|
2282
2290
|
const response = await fetchResponse(hostedBinding, session, expectedSurfaceId, abort);
|
|
2283
|
-
const source = await readBoundedResponse(response, abort);
|
|
2291
|
+
const { source, size } = await readBoundedResponse(response, abort);
|
|
2284
2292
|
let body;
|
|
2285
2293
|
try {
|
|
2286
2294
|
body = source.length ? JSON.parse(source) : null;
|
|
@@ -2290,14 +2298,15 @@ function createHostedNativeSessionController(input) {
|
|
|
2290
2298
|
}
|
|
2291
2299
|
body = null;
|
|
2292
2300
|
}
|
|
2293
|
-
if (response.status === 409 &&
|
|
2301
|
+
if (response.status === 409 && isExactRestart(body, session.sessionId)) {
|
|
2302
|
+
if (!allowRestart) throw new HostedNativeSessionError("NATIVE_SESSION_UNAVAILABLE");
|
|
2294
2303
|
assertCurrentSession(session, hostedBinding);
|
|
2295
2304
|
const replacement = redirectSession(session, readClock());
|
|
2296
2305
|
if (abort.signal.aborted) throw abort.error();
|
|
2297
2306
|
return bootstrap(replacement, hostedBinding, abort, false, false);
|
|
2298
2307
|
}
|
|
2299
2308
|
if (response.status !== 201) {
|
|
2300
|
-
const failure3 = statusError(response.status, body);
|
|
2309
|
+
const failure3 = statusError(response.status, body, size);
|
|
2301
2310
|
const delay = retryAfterMs(response.headers, now);
|
|
2302
2311
|
if (delay !== null) retryAfterDelays.set(failure3, delay);
|
|
2303
2312
|
throw failure3;
|
|
@@ -2435,7 +2444,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2435
2444
|
if (bindingGeneration !== expectedGeneration) {
|
|
2436
2445
|
throw new HostedNativeSessionError("NATIVE_SESSION_REPLACED");
|
|
2437
2446
|
}
|
|
2438
|
-
if (terminal) throw
|
|
2447
|
+
if (terminal) throw errorFrom(terminal);
|
|
2439
2448
|
checkedAt = readClock();
|
|
2440
2449
|
if (resolved.authority.clockEpoch === clock.epoch && resolved.authority.validUntil > checkedAt) {
|
|
2441
2450
|
admittedAuthorities.set(resolved.authority.public, resolved.authority);
|
|
@@ -2510,7 +2519,7 @@ function createHostedNativeSessionController(input) {
|
|
|
2510
2519
|
if (disposed) throw new HostedNativeSessionError("NATIVE_SESSION_DISPOSED");
|
|
2511
2520
|
lifecycle = "foreground";
|
|
2512
2521
|
if (terminal) {
|
|
2513
|
-
const error =
|
|
2522
|
+
const error = errorFrom(terminal);
|
|
2514
2523
|
publish(currentSnapshot());
|
|
2515
2524
|
throw error;
|
|
2516
2525
|
}
|
|
@@ -2783,7 +2792,7 @@ async function readBoundedResponse(response, abort) {
|
|
|
2783
2792
|
bytes.set(chunk, offset);
|
|
2784
2793
|
offset += chunk.byteLength;
|
|
2785
2794
|
}
|
|
2786
|
-
return decodeUtf8(bytes);
|
|
2795
|
+
return { source: decodeUtf8(bytes), size };
|
|
2787
2796
|
}
|
|
2788
2797
|
function decodeUtf8(bytes) {
|
|
2789
2798
|
let result = "";
|
|
@@ -2831,7 +2840,7 @@ function decodeUtf8(bytes) {
|
|
|
2831
2840
|
function hasNoStore(value) {
|
|
2832
2841
|
return typeof value === "string" && value.split(",").some((part) => part.trim().toLowerCase() === "no-store");
|
|
2833
2842
|
}
|
|
2834
|
-
function statusError(status, body) {
|
|
2843
|
+
function statusError(status, body, size) {
|
|
2835
2844
|
if (status === 401) return new HostedNativeSessionError("NATIVE_SESSION_CREDENTIAL_REJECTED");
|
|
2836
2845
|
if (status === 403) return new HostedNativeSessionError("NATIVE_SESSION_MAP_MISMATCH");
|
|
2837
2846
|
if (status === 404) return new HostedNativeSessionError("NATIVE_SESSION_MAP_NOT_FOUND");
|
|
@@ -2843,7 +2852,21 @@ function statusError(status, body) {
|
|
|
2843
2852
|
if (status === 408 || status >= 500 && status <= 599) {
|
|
2844
2853
|
return new HostedNativeSessionError("NATIVE_SESSION_UNAVAILABLE");
|
|
2845
2854
|
}
|
|
2846
|
-
|
|
2855
|
+
if (status >= 400 && status <= 499) {
|
|
2856
|
+
return new HostedNativeSessionError(
|
|
2857
|
+
"NATIVE_SESSION_REJECTED",
|
|
2858
|
+
size <= SERVICE_CODE_BODY_LIMIT && isRecord(body) && typeof body.code === "string" ? body.code : void 0
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
2861
|
+
return new HostedNativeSessionError("NATIVE_SESSION_RESPONSE_INVALID");
|
|
2862
|
+
}
|
|
2863
|
+
function safeError(error) {
|
|
2864
|
+
return Object.freeze(
|
|
2865
|
+
error.reason === void 0 ? { code: error.code, kind: error.kind } : { code: error.code, kind: error.kind, reason: error.reason }
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
function errorFrom(error) {
|
|
2869
|
+
return new HostedNativeSessionError(error.code, error.reason);
|
|
2847
2870
|
}
|
|
2848
2871
|
var retryAfterDelays = /* @__PURE__ */ new WeakMap();
|
|
2849
2872
|
function retryAfterMs(headers, now) {
|
|
@@ -2893,12 +2916,13 @@ async function cancelResponse(response) {
|
|
|
2893
2916
|
} catch {
|
|
2894
2917
|
}
|
|
2895
2918
|
}
|
|
2896
|
-
var _aborted, _code, _listeners;
|
|
2919
|
+
var _aborted, _code, _reason, _listeners;
|
|
2897
2920
|
var SessionAbortController = class {
|
|
2898
2921
|
constructor() {
|
|
2899
2922
|
__publicField(this, "signal");
|
|
2900
2923
|
__privateAdd(this, _aborted, false);
|
|
2901
2924
|
__privateAdd(this, _code, "NATIVE_SESSION_REPLACED");
|
|
2925
|
+
__privateAdd(this, _reason);
|
|
2902
2926
|
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
2903
2927
|
const isAborted = () => __privateGet(this, _aborted);
|
|
2904
2928
|
this.signal = Object.freeze({
|
|
@@ -2913,9 +2937,10 @@ var SessionAbortController = class {
|
|
|
2913
2937
|
}
|
|
2914
2938
|
});
|
|
2915
2939
|
}
|
|
2916
|
-
abort(code) {
|
|
2940
|
+
abort(code, reason) {
|
|
2917
2941
|
if (__privateGet(this, _aborted)) return;
|
|
2918
2942
|
__privateSet(this, _code, code);
|
|
2943
|
+
__privateSet(this, _reason, reason);
|
|
2919
2944
|
__privateSet(this, _aborted, true);
|
|
2920
2945
|
for (const listener of [...__privateGet(this, _listeners)]) {
|
|
2921
2946
|
try {
|
|
@@ -2926,11 +2951,12 @@ var SessionAbortController = class {
|
|
|
2926
2951
|
__privateGet(this, _listeners).clear();
|
|
2927
2952
|
}
|
|
2928
2953
|
error() {
|
|
2929
|
-
return new HostedNativeSessionError(__privateGet(this, _code));
|
|
2954
|
+
return new HostedNativeSessionError(__privateGet(this, _code), __privateGet(this, _reason));
|
|
2930
2955
|
}
|
|
2931
2956
|
};
|
|
2932
2957
|
_aborted = new WeakMap();
|
|
2933
2958
|
_code = new WeakMap();
|
|
2959
|
+
_reason = new WeakMap();
|
|
2934
2960
|
_listeners = new WeakMap();
|
|
2935
2961
|
function raceWithAbort(promise, controller) {
|
|
2936
2962
|
if (controller.signal.aborted) return Promise.reject(controller.error());
|
|
@@ -3238,7 +3264,7 @@ function createNativeAdmissionOwner(options) {
|
|
|
3238
3264
|
reported = code;
|
|
3239
3265
|
if (state.status !== "error") return;
|
|
3240
3266
|
try {
|
|
3241
|
-
input.onSessionError?.(Object.freeze({
|
|
3267
|
+
input.onSessionError?.(Object.freeze({ ...state.error }));
|
|
3242
3268
|
} catch {
|
|
3243
3269
|
}
|
|
3244
3270
|
});
|
|
@@ -5824,8 +5850,10 @@ var sessionErrorCodes = /* @__PURE__ */ new Set([
|
|
|
5824
5850
|
"NATIVE_SESSION_MAP_MISMATCH",
|
|
5825
5851
|
"NATIVE_SESSION_MAP_NOT_FOUND",
|
|
5826
5852
|
"NATIVE_SESSION_QUOTA_EXCEEDED",
|
|
5853
|
+
"NATIVE_SESSION_REJECTED",
|
|
5827
5854
|
"NATIVE_SESSION_INPUT_INVALID"
|
|
5828
5855
|
]);
|
|
5856
|
+
var SERVICE_CODE2 = /^[A-Z][A-Z0-9_]{0,63}$/u;
|
|
5829
5857
|
function themeSource(source, name3) {
|
|
5830
5858
|
const theme = Object.hasOwn(source.map.themes, name3) ? source.map.themes[name3] : void 0;
|
|
5831
5859
|
if (!theme) throw new NativePreparationError();
|
|
@@ -6085,9 +6113,14 @@ function createMountedMapOwner(ports2) {
|
|
|
6085
6113
|
reopenings += 1;
|
|
6086
6114
|
restart(epoch);
|
|
6087
6115
|
}
|
|
6088
|
-
function sessionError(epoch, code) {
|
|
6116
|
+
function sessionError(epoch, code, reason) {
|
|
6089
6117
|
if (disposed || current !== epoch || !epoch.live || !sessionErrorCodes.has(code)) return;
|
|
6090
|
-
const
|
|
6118
|
+
const detail = code === "NATIVE_SESSION_REJECTED" && typeof reason === "string" && SERVICE_CODE2.test(reason) ? { reason } : {};
|
|
6119
|
+
const error = Object.freeze({
|
|
6120
|
+
code,
|
|
6121
|
+
kind: "terminal",
|
|
6122
|
+
...detail
|
|
6123
|
+
});
|
|
6091
6124
|
emit({ type: "session-error", generation: generation(), error });
|
|
6092
6125
|
}
|
|
6093
6126
|
function createEpoch(developmentOrigin) {
|
|
@@ -6125,7 +6158,7 @@ function createMountedMapOwner(ports2) {
|
|
|
6125
6158
|
onRetired: () => void Promise.resolve().then(() => reopen(epoch)),
|
|
6126
6159
|
onSessionError: (error) => {
|
|
6127
6160
|
if (error.kind !== "terminal") return;
|
|
6128
|
-
void Promise.resolve().then(() => sessionError(epoch, error.code));
|
|
6161
|
+
void Promise.resolve().then(() => sessionError(epoch, error.code, error.reason));
|
|
6129
6162
|
}
|
|
6130
6163
|
});
|
|
6131
6164
|
const map = await epoch.lease.ready;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as MapView, a as MapViewChangeEvent, b as MapInitialViewInputs, c as MapCameraProps } from '../contract-
|
|
1
|
+
import { M as MapView, a as MapViewChangeEvent, b as MapInitialViewInputs, c as MapCameraProps } from '../contract-BWT1jxqg.js';
|
|
2
2
|
import '@maplibre/maplibre-react-native';
|
|
3
3
|
import 'react';
|
|
4
4
|
import 'react-native';
|
|
@@ -11,6 +11,7 @@ type NativeMapAdmissionInput = Omit<SessionInput, 'fetch' | 'sessionIdFactory'>
|
|
|
11
11
|
onSessionError?: (error: Readonly<{
|
|
12
12
|
code: HostedNativeSessionErrorCode;
|
|
13
13
|
kind: HostedNativeSessionErrorKind;
|
|
14
|
+
reason?: string;
|
|
14
15
|
}>) => void;
|
|
15
16
|
}>;
|
|
16
17
|
type NativeMapAdmission = Readonly<{
|
|
@@ -343,6 +343,8 @@ var RETRY_LIMIT_MS = 6e4;
|
|
|
343
343
|
var RETRY_AFTER_LIMIT_MS = 15 * 60 * 1e3;
|
|
344
344
|
var RETRY_AFTER_SECONDS = /^\d{1,10}$/u;
|
|
345
345
|
var QUOTA_CODES = /* @__PURE__ */ new Set(["COMMERCIAL_MAP_LIMIT_REACHED", "COMMERCIAL_SPENDING_LIMIT_REACHED"]);
|
|
346
|
+
var SERVICE_CODE = /^[A-Z][A-Z0-9_]{0,63}$/u;
|
|
347
|
+
var SERVICE_CODE_BODY_LIMIT = 4096;
|
|
346
348
|
var MOBILE_CREDENTIAL = /^tf_public_[0-9a-f]{48}$/u;
|
|
347
349
|
var MAP_ID = /^map_[A-Za-z0-9_-]{16}$/u;
|
|
348
350
|
var CREDENTIAL_ID = /^key_[A-Za-z0-9_-]{8,80}$/u;
|
|
@@ -386,7 +388,8 @@ var TERMINAL_CODES = /* @__PURE__ */ new Set([
|
|
|
386
388
|
"NATIVE_SESSION_CREDENTIAL_REJECTED",
|
|
387
389
|
"NATIVE_SESSION_MAP_MISMATCH",
|
|
388
390
|
"NATIVE_SESSION_MAP_NOT_FOUND",
|
|
389
|
-
"NATIVE_SESSION_QUOTA_EXCEEDED"
|
|
391
|
+
"NATIVE_SESSION_QUOTA_EXCEEDED",
|
|
392
|
+
"NATIVE_SESSION_REJECTED"
|
|
390
393
|
]);
|
|
391
394
|
var ERROR_MESSAGES = {
|
|
392
395
|
NATIVE_SESSION_INPUT_INVALID: "Native session configuration is invalid.",
|
|
@@ -405,13 +408,16 @@ var ERROR_MESSAGES = {
|
|
|
405
408
|
NATIVE_SESSION_DISPOSED: "Native session controller is disposed."
|
|
406
409
|
};
|
|
407
410
|
var HostedNativeSessionError = class extends Error {
|
|
408
|
-
constructor(code) {
|
|
411
|
+
constructor(code, reason) {
|
|
409
412
|
super(ERROR_MESSAGES[code]);
|
|
410
413
|
__publicField(this, "code");
|
|
411
414
|
__publicField(this, "kind");
|
|
412
415
|
this.name = "HostedNativeSessionError";
|
|
413
416
|
this.code = code;
|
|
414
417
|
this.kind = errorKind(code);
|
|
418
|
+
if (code === "NATIVE_SESSION_REJECTED" && typeof reason === "string" && SERVICE_CODE.test(reason)) {
|
|
419
|
+
this.reason = reason;
|
|
420
|
+
}
|
|
415
421
|
}
|
|
416
422
|
};
|
|
417
423
|
function createHostedNativeSessionController(input) {
|
|
@@ -540,10 +546,10 @@ function createHostedNativeSessionController(input) {
|
|
|
540
546
|
if (retryAt === null || at >= retryAt) failures = Math.min(failures + 1, 16);
|
|
541
547
|
const backoff = Math.min(RETRY_INITIAL_MS * 2 ** (failures - 1), RETRY_LIMIT_MS);
|
|
542
548
|
retryAt = Math.max(retryAt ?? at, at + Math.max(backoff, retryAfterDelays.get(error) ?? 0));
|
|
543
|
-
retryError =
|
|
549
|
+
retryError = safeError(error);
|
|
544
550
|
}
|
|
545
551
|
function rotateIfRequired(at) {
|
|
546
|
-
if (terminal) throw
|
|
552
|
+
if (terminal) throw errorFrom(terminal);
|
|
547
553
|
if (!activeSession || binding.kind !== "hosted") return;
|
|
548
554
|
if (at - activeSession.startedAt < ROTATION_AGE_MS && activeSession.requestCount < ROTATION_REQUEST_LIMIT) {
|
|
549
555
|
return;
|
|
@@ -577,7 +583,7 @@ function createHostedNativeSessionController(input) {
|
|
|
577
583
|
return current;
|
|
578
584
|
}
|
|
579
585
|
async function ensureAuthority(session, at) {
|
|
580
|
-
if (terminal) throw
|
|
586
|
+
if (terminal) throw errorFrom(terminal);
|
|
581
587
|
if (session.authority && session.authority.clockEpoch === clock.epoch && session.authority.validUntil - at > REFRESH_MARGIN_MS) {
|
|
582
588
|
return { authority: session.authority, session };
|
|
583
589
|
}
|
|
@@ -589,7 +595,7 @@ function createHostedNativeSessionController(input) {
|
|
|
589
595
|
if (session.authority && session.authority.clockEpoch === clock.epoch && session.authority.validUntil > at) {
|
|
590
596
|
return { authority: session.authority, session };
|
|
591
597
|
}
|
|
592
|
-
throw
|
|
598
|
+
throw errorFrom(retryError);
|
|
593
599
|
}
|
|
594
600
|
const operationBinding = binding;
|
|
595
601
|
const abort = new SessionAbortController();
|
|
@@ -616,14 +622,16 @@ function createHostedNativeSessionController(input) {
|
|
|
616
622
|
const normalized = abort.signal.aborted ? abort.error() : normalizeError(error);
|
|
617
623
|
const target = latestSession(session);
|
|
618
624
|
if (normalized.kind === "terminal" && binding === operationBinding && !terminal) {
|
|
619
|
-
const failure =
|
|
625
|
+
const failure = safeError(normalized);
|
|
620
626
|
terminal = failure;
|
|
621
627
|
const rejectedSession = activeSession;
|
|
622
628
|
if (rejectedSession) {
|
|
623
629
|
rejectedSession.authority = null;
|
|
624
630
|
rejectedSession.error = failure;
|
|
625
631
|
}
|
|
626
|
-
for (const pending of [...operations])
|
|
632
|
+
for (const pending of [...operations]) {
|
|
633
|
+
pending.abort(failure.code, failure.reason);
|
|
634
|
+
}
|
|
627
635
|
if (binding === operationBinding && rejectedSession) {
|
|
628
636
|
publishSession(rejectedSession, "error", failure);
|
|
629
637
|
}
|
|
@@ -632,7 +640,7 @@ function createHostedNativeSessionController(input) {
|
|
|
632
640
|
delayRetry(normalized);
|
|
633
641
|
}
|
|
634
642
|
if (normalized.code !== "NATIVE_SESSION_REPLACED" && normalized.code !== "NATIVE_SESSION_DISPOSED") {
|
|
635
|
-
target.error =
|
|
643
|
+
target.error = safeError(normalized);
|
|
636
644
|
publishSession(target, "error", target.error);
|
|
637
645
|
}
|
|
638
646
|
throw normalized;
|
|
@@ -658,7 +666,7 @@ function createHostedNativeSessionController(input) {
|
|
|
658
666
|
if (abort.signal.aborted) throw abort.error();
|
|
659
667
|
const expectedSurfaceId = session.authority?.public.surfaceId ?? session.requestedSurfaceId;
|
|
660
668
|
const response = await fetchResponse(hostedBinding, session, expectedSurfaceId, abort);
|
|
661
|
-
const source = await readBoundedResponse(response, abort);
|
|
669
|
+
const { source, size } = await readBoundedResponse(response, abort);
|
|
662
670
|
let body;
|
|
663
671
|
try {
|
|
664
672
|
body = source.length ? JSON.parse(source) : null;
|
|
@@ -668,14 +676,15 @@ function createHostedNativeSessionController(input) {
|
|
|
668
676
|
}
|
|
669
677
|
body = null;
|
|
670
678
|
}
|
|
671
|
-
if (response.status === 409 &&
|
|
679
|
+
if (response.status === 409 && isExactRestart(body, session.sessionId)) {
|
|
680
|
+
if (!allowRestart) throw new HostedNativeSessionError("NATIVE_SESSION_UNAVAILABLE");
|
|
672
681
|
assertCurrentSession(session, hostedBinding);
|
|
673
682
|
const replacement = redirectSession(session, readClock());
|
|
674
683
|
if (abort.signal.aborted) throw abort.error();
|
|
675
684
|
return bootstrap(replacement, hostedBinding, abort, false, false);
|
|
676
685
|
}
|
|
677
686
|
if (response.status !== 201) {
|
|
678
|
-
const failure = statusError(response.status, body);
|
|
687
|
+
const failure = statusError(response.status, body, size);
|
|
679
688
|
const delay = retryAfterMs(response.headers, now);
|
|
680
689
|
if (delay !== null) retryAfterDelays.set(failure, delay);
|
|
681
690
|
throw failure;
|
|
@@ -813,7 +822,7 @@ function createHostedNativeSessionController(input) {
|
|
|
813
822
|
if (bindingGeneration !== expectedGeneration) {
|
|
814
823
|
throw new HostedNativeSessionError("NATIVE_SESSION_REPLACED");
|
|
815
824
|
}
|
|
816
|
-
if (terminal) throw
|
|
825
|
+
if (terminal) throw errorFrom(terminal);
|
|
817
826
|
checkedAt = readClock();
|
|
818
827
|
if (resolved.authority.clockEpoch === clock.epoch && resolved.authority.validUntil > checkedAt) {
|
|
819
828
|
admittedAuthorities.set(resolved.authority.public, resolved.authority);
|
|
@@ -888,7 +897,7 @@ function createHostedNativeSessionController(input) {
|
|
|
888
897
|
if (disposed) throw new HostedNativeSessionError("NATIVE_SESSION_DISPOSED");
|
|
889
898
|
lifecycle = "foreground";
|
|
890
899
|
if (terminal) {
|
|
891
|
-
const error =
|
|
900
|
+
const error = errorFrom(terminal);
|
|
892
901
|
publish(currentSnapshot());
|
|
893
902
|
throw error;
|
|
894
903
|
}
|
|
@@ -1161,7 +1170,7 @@ async function readBoundedResponse(response, abort) {
|
|
|
1161
1170
|
bytes.set(chunk, offset);
|
|
1162
1171
|
offset += chunk.byteLength;
|
|
1163
1172
|
}
|
|
1164
|
-
return decodeUtf8(bytes);
|
|
1173
|
+
return { source: decodeUtf8(bytes), size };
|
|
1165
1174
|
}
|
|
1166
1175
|
function decodeUtf8(bytes) {
|
|
1167
1176
|
let result = "";
|
|
@@ -1209,7 +1218,7 @@ function decodeUtf8(bytes) {
|
|
|
1209
1218
|
function hasNoStore(value) {
|
|
1210
1219
|
return typeof value === "string" && value.split(",").some((part) => part.trim().toLowerCase() === "no-store");
|
|
1211
1220
|
}
|
|
1212
|
-
function statusError(status, body) {
|
|
1221
|
+
function statusError(status, body, size) {
|
|
1213
1222
|
if (status === 401) return new HostedNativeSessionError("NATIVE_SESSION_CREDENTIAL_REJECTED");
|
|
1214
1223
|
if (status === 403) return new HostedNativeSessionError("NATIVE_SESSION_MAP_MISMATCH");
|
|
1215
1224
|
if (status === 404) return new HostedNativeSessionError("NATIVE_SESSION_MAP_NOT_FOUND");
|
|
@@ -1221,7 +1230,21 @@ function statusError(status, body) {
|
|
|
1221
1230
|
if (status === 408 || status >= 500 && status <= 599) {
|
|
1222
1231
|
return new HostedNativeSessionError("NATIVE_SESSION_UNAVAILABLE");
|
|
1223
1232
|
}
|
|
1224
|
-
|
|
1233
|
+
if (status >= 400 && status <= 499) {
|
|
1234
|
+
return new HostedNativeSessionError(
|
|
1235
|
+
"NATIVE_SESSION_REJECTED",
|
|
1236
|
+
size <= SERVICE_CODE_BODY_LIMIT && isRecord(body) && typeof body.code === "string" ? body.code : void 0
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
return new HostedNativeSessionError("NATIVE_SESSION_RESPONSE_INVALID");
|
|
1240
|
+
}
|
|
1241
|
+
function safeError(error) {
|
|
1242
|
+
return Object.freeze(
|
|
1243
|
+
error.reason === void 0 ? { code: error.code, kind: error.kind } : { code: error.code, kind: error.kind, reason: error.reason }
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
function errorFrom(error) {
|
|
1247
|
+
return new HostedNativeSessionError(error.code, error.reason);
|
|
1225
1248
|
}
|
|
1226
1249
|
var retryAfterDelays = /* @__PURE__ */ new WeakMap();
|
|
1227
1250
|
function retryAfterMs(headers, now) {
|
|
@@ -1271,12 +1294,13 @@ async function cancelResponse(response) {
|
|
|
1271
1294
|
} catch {
|
|
1272
1295
|
}
|
|
1273
1296
|
}
|
|
1274
|
-
var _aborted, _code, _listeners;
|
|
1297
|
+
var _aborted, _code, _reason, _listeners;
|
|
1275
1298
|
var SessionAbortController = class {
|
|
1276
1299
|
constructor() {
|
|
1277
1300
|
__publicField(this, "signal");
|
|
1278
1301
|
__privateAdd(this, _aborted, false);
|
|
1279
1302
|
__privateAdd(this, _code, "NATIVE_SESSION_REPLACED");
|
|
1303
|
+
__privateAdd(this, _reason);
|
|
1280
1304
|
__privateAdd(this, _listeners, /* @__PURE__ */ new Set());
|
|
1281
1305
|
const isAborted = () => __privateGet(this, _aborted);
|
|
1282
1306
|
this.signal = Object.freeze({
|
|
@@ -1291,9 +1315,10 @@ var SessionAbortController = class {
|
|
|
1291
1315
|
}
|
|
1292
1316
|
});
|
|
1293
1317
|
}
|
|
1294
|
-
abort(code) {
|
|
1318
|
+
abort(code, reason) {
|
|
1295
1319
|
if (__privateGet(this, _aborted)) return;
|
|
1296
1320
|
__privateSet(this, _code, code);
|
|
1321
|
+
__privateSet(this, _reason, reason);
|
|
1297
1322
|
__privateSet(this, _aborted, true);
|
|
1298
1323
|
for (const listener of [...__privateGet(this, _listeners)]) {
|
|
1299
1324
|
try {
|
|
@@ -1304,11 +1329,12 @@ var SessionAbortController = class {
|
|
|
1304
1329
|
__privateGet(this, _listeners).clear();
|
|
1305
1330
|
}
|
|
1306
1331
|
error() {
|
|
1307
|
-
return new HostedNativeSessionError(__privateGet(this, _code));
|
|
1332
|
+
return new HostedNativeSessionError(__privateGet(this, _code), __privateGet(this, _reason));
|
|
1308
1333
|
}
|
|
1309
1334
|
};
|
|
1310
1335
|
_aborted = new WeakMap();
|
|
1311
1336
|
_code = new WeakMap();
|
|
1337
|
+
_reason = new WeakMap();
|
|
1312
1338
|
_listeners = new WeakMap();
|
|
1313
1339
|
function raceWithAbort(promise, controller) {
|
|
1314
1340
|
if (controller.signal.aborted) return Promise.reject(controller.error());
|
|
@@ -1616,7 +1642,7 @@ function createNativeAdmissionOwner(options) {
|
|
|
1616
1642
|
reported = code;
|
|
1617
1643
|
if (state.status !== "error") return;
|
|
1618
1644
|
try {
|
|
1619
|
-
input.onSessionError?.(Object.freeze({
|
|
1645
|
+
input.onSessionError?.(Object.freeze({ ...state.error }));
|
|
1620
1646
|
} catch {
|
|
1621
1647
|
}
|
|
1622
1648
|
});
|