one 2.7.2 → 2.7.4
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/android/src/main/AndroidManifest.xml +11 -0
- package/android/src/main/java/com/margelo/nitro/one/HybridOneLocation.kt +8 -3
- package/android/src/main/java/com/margelo/nitro/one/HybridOneNotifications.kt +56 -58
- package/android/src/main/java/dev/onejs/onenative/OneNativeNotificationTapActivity.kt +16 -0
- package/android/src/maps/java/dev/onejs/onenative/OneNativeUiMapView.kt +10 -9
- package/dist/cjs/vite/resolveResponse.cjs +15 -2
- package/dist/cjs/vite/resolveResponse.native.cjs +17 -2
- package/dist/cjs/vite/resolveResponse.native.js +17 -2
- package/dist/cjs/vite/resolveResponse.native.js.map +1 -1
- package/dist/esm/vite/resolveResponse.mjs +15 -2
- package/dist/esm/vite/resolveResponse.mjs.map +1 -1
- package/dist/esm/vite/resolveResponse.native.js +17 -2
- package/dist/esm/vite/resolveResponse.native.js.map +1 -1
- package/ios/Tests/ImageManipulator/README.md +3 -2
- package/ios/Tests/ImageManipulator/Sources/SDWebImageWebPCoder/SDImageWebPCoder.swift +1 -1
- package/ios/ZoomTransition/ZoomTransition.swift +52 -15
- package/package.json +15 -15
- package/src/createHandleRequest.test.ts +98 -0
- package/src/vite/resolveResponse.ts +17 -2
- package/types/vite/resolveResponse.d.ts.map +1 -1
|
@@ -53,5 +53,16 @@
|
|
|
53
53
|
android:configChanges="keyboardHidden|orientation|screenSize"
|
|
54
54
|
android:exported="false"
|
|
55
55
|
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />
|
|
56
|
+
<!-- a scheduled notification's tap records its response here before
|
|
57
|
+
the app opens; react native drops a tap that reaches an app activity
|
|
58
|
+
recreated after process death. never exported: only the notification's
|
|
59
|
+
pending intent launches it. -->
|
|
60
|
+
<activity
|
|
61
|
+
android:name="dev.onejs.onenative.OneNativeNotificationTapActivity"
|
|
62
|
+
android:excludeFromRecents="true"
|
|
63
|
+
android:exported="false"
|
|
64
|
+
android:noHistory="true"
|
|
65
|
+
android:taskAffinity=""
|
|
66
|
+
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
|
56
67
|
</application>
|
|
57
68
|
</manifest>
|
|
@@ -504,9 +504,14 @@ class HybridOneLocation :
|
|
|
504
504
|
)
|
|
505
505
|
return@post
|
|
506
506
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
507
|
+
// a live watch keeps the last fix current; without one it can be
|
|
508
|
+
// a fix the device has since moved from, so ask for a fresh one
|
|
509
|
+
// (the ios contract).
|
|
510
|
+
if (monitoring) {
|
|
511
|
+
recentPosition(manager)?.let {
|
|
512
|
+
promise.resolve(it)
|
|
513
|
+
return@post
|
|
514
|
+
}
|
|
510
515
|
}
|
|
511
516
|
if (!serviceEnabled(manager)) {
|
|
512
517
|
promise.reject(
|
|
@@ -24,6 +24,7 @@ import com.facebook.react.modules.core.PermissionListener
|
|
|
24
24
|
import com.margelo.nitro.NitroModules
|
|
25
25
|
import com.margelo.nitro.core.AnyMap
|
|
26
26
|
import com.margelo.nitro.core.Promise
|
|
27
|
+
import dev.onejs.onenative.OneNativeNotificationTapActivity
|
|
27
28
|
import dev.onejs.onenative.OneNativeNotificationsReceiver
|
|
28
29
|
import dev.onejs.onenative.OneNativePush
|
|
29
30
|
import org.json.JSONArray
|
|
@@ -601,21 +602,7 @@ class HybridOneNotifications :
|
|
|
601
602
|
if (intent == null || !intent.getBooleanExtra(EXTRA_TAP, false)) return
|
|
602
603
|
// consumed at once: onNewIntent and onHostResume both report a tap.
|
|
603
604
|
intent.removeExtra(EXTRA_TAP)
|
|
604
|
-
val response =
|
|
605
|
-
TapResponse(
|
|
606
|
-
intent.getStringExtra(EXTRA_IDENTIFIER) ?: return,
|
|
607
|
-
intent.getStringExtra(EXTRA_TITLE),
|
|
608
|
-
intent.getStringExtra(EXTRA_SUBTITLE),
|
|
609
|
-
intent.getStringExtra(EXTRA_BODY),
|
|
610
|
-
intent.getStringExtra(EXTRA_DATA) ?: "{}",
|
|
611
|
-
intent.getBooleanExtra(EXTRA_SOUND, false),
|
|
612
|
-
if (intent.hasExtra(EXTRA_BADGE)) intent.getIntExtra(EXTRA_BADGE, 0) else null,
|
|
613
|
-
intent.getStringExtra(EXTRA_TRIGGER) ?: IMMEDIATE_TRIGGER_JSON,
|
|
614
|
-
System.currentTimeMillis(),
|
|
615
|
-
intent.getStringExtra(EXTRA_ACTION) ?: DEFAULT_ACTION_IDENTIFIER,
|
|
616
|
-
intent.getStringExtra(EXTRA_USER_TEXT),
|
|
617
|
-
intent.getStringExtra(EXTRA_CATEGORY)
|
|
618
|
-
)
|
|
605
|
+
val response = tapResponse(intent, intent.getStringExtra(EXTRA_USER_TEXT)) ?: return
|
|
619
606
|
lastResponse = response
|
|
620
607
|
currentListeners()?.onResponse?.invoke(responsePayload(response))
|
|
621
608
|
}
|
|
@@ -626,21 +613,11 @@ class HybridOneNotifications :
|
|
|
626
613
|
fun handleAction(context: Context, intent: Intent) {
|
|
627
614
|
val results = androidx.core.app.RemoteInput.getResultsFromIntent(intent)
|
|
628
615
|
val response =
|
|
629
|
-
|
|
630
|
-
intent
|
|
631
|
-
intent.getStringExtra(EXTRA_TITLE),
|
|
632
|
-
intent.getStringExtra(EXTRA_SUBTITLE),
|
|
633
|
-
intent.getStringExtra(EXTRA_BODY),
|
|
634
|
-
intent.getStringExtra(EXTRA_DATA) ?: "{}",
|
|
635
|
-
intent.getBooleanExtra(EXTRA_SOUND, false),
|
|
636
|
-
if (intent.hasExtra(EXTRA_BADGE)) intent.getIntExtra(EXTRA_BADGE, 0) else null,
|
|
637
|
-
intent.getStringExtra(EXTRA_TRIGGER) ?: IMMEDIATE_TRIGGER_JSON,
|
|
638
|
-
System.currentTimeMillis(),
|
|
639
|
-
intent.getStringExtra(EXTRA_ACTION) ?: DEFAULT_ACTION_IDENTIFIER,
|
|
616
|
+
tapResponse(
|
|
617
|
+
intent,
|
|
640
618
|
results?.getCharSequence(EXTRA_USER_TEXT)?.toString()
|
|
641
|
-
?: intent.getStringExtra(EXTRA_USER_TEXT)
|
|
642
|
-
|
|
643
|
-
)
|
|
619
|
+
?: intent.getStringExtra(EXTRA_USER_TEXT)
|
|
620
|
+
) ?: return
|
|
644
621
|
lastResponse = response
|
|
645
622
|
currentListeners()?.onResponse?.invoke(responsePayload(response))
|
|
646
623
|
if (intent.getBooleanExtra(EXTRA_FOREGROUND, true)) {
|
|
@@ -708,7 +685,6 @@ class HybridOneNotifications :
|
|
|
708
685
|
private const val E_CATEGORY = "E_NOTIFICATIONS_CATEGORY"
|
|
709
686
|
private const val DEFAULT_CHANNEL_ID = "default"
|
|
710
687
|
private const val DEFAULT_ACTION_IDENTIFIER = "expo.modules.notifications.actions.DEFAULT"
|
|
711
|
-
private const val ACTION_TAP = "dev.onejs.onenative.NOTIFICATION_TAP"
|
|
712
688
|
private const val EXTRA_TAP = "dev.onejs.onenative.EXTRA_TAP"
|
|
713
689
|
private const val EXTRA_TITLE = "dev.onejs.onenative.EXTRA_TITLE"
|
|
714
690
|
private const val EXTRA_SUBTITLE = "dev.onejs.onenative.EXTRA_SUBTITLE"
|
|
@@ -1095,15 +1071,9 @@ class HybridOneNotifications :
|
|
|
1095
1071
|
if (highPriority) NotificationCompat.PRIORITY_HIGH
|
|
1096
1072
|
else NotificationCompat.PRIORITY_DEFAULT
|
|
1097
1073
|
)
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
target.component = component
|
|
1102
|
-
target.flags =
|
|
1103
|
-
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
1104
|
-
Intent.FLAG_ACTIVITY_CLEAR_TOP or
|
|
1105
|
-
Intent.FLAG_ACTIVITY_SINGLE_TOP
|
|
1106
|
-
target.putExtra(EXTRA_TAP, true)
|
|
1074
|
+
if (launch?.component != null) {
|
|
1075
|
+
val target = Intent(context, OneNativeNotificationTapActivity::class.java)
|
|
1076
|
+
target.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
1107
1077
|
target.putExtra(EXTRA_IDENTIFIER, schedule.identifier)
|
|
1108
1078
|
target.putExtra(EXTRA_TITLE, schedule.title)
|
|
1109
1079
|
target.putExtra(EXTRA_SUBTITLE, schedule.subtitle)
|
|
@@ -1177,7 +1147,11 @@ class HybridOneNotifications :
|
|
|
1177
1147
|
context,
|
|
1178
1148
|
(schedule.identifier + ":" + action.identifier).hashCode(),
|
|
1179
1149
|
target,
|
|
1180
|
-
|
|
1150
|
+
// the system writes a typed reply into the intent, so a
|
|
1151
|
+
// text-input action needs a mutable one (refused otherwise).
|
|
1152
|
+
PendingIntent.FLAG_UPDATE_CURRENT or
|
|
1153
|
+
if (action.textInputPlaceholder != null) PendingIntent.FLAG_MUTABLE
|
|
1154
|
+
else PendingIntent.FLAG_IMMUTABLE
|
|
1181
1155
|
)
|
|
1182
1156
|
val builder =
|
|
1183
1157
|
androidx.core.app.NotificationCompat.Action.Builder(0, action.buttonTitle, pending)
|
|
@@ -1194,6 +1168,46 @@ class HybridOneNotifications :
|
|
|
1194
1168
|
return builder.build()
|
|
1195
1169
|
}
|
|
1196
1170
|
|
|
1171
|
+
// a notification tap or action, from the extras every tap intent carries.
|
|
1172
|
+
private fun tapResponse(intent: Intent, userText: String?): TapResponse? {
|
|
1173
|
+
val identifier = intent.getStringExtra(EXTRA_IDENTIFIER) ?: return null
|
|
1174
|
+
return TapResponse(
|
|
1175
|
+
identifier,
|
|
1176
|
+
intent.getStringExtra(EXTRA_TITLE),
|
|
1177
|
+
intent.getStringExtra(EXTRA_SUBTITLE),
|
|
1178
|
+
intent.getStringExtra(EXTRA_BODY),
|
|
1179
|
+
intent.getStringExtra(EXTRA_DATA) ?: "{}",
|
|
1180
|
+
intent.getBooleanExtra(EXTRA_SOUND, false),
|
|
1181
|
+
if (intent.hasExtra(EXTRA_BADGE)) intent.getIntExtra(EXTRA_BADGE, 0) else null,
|
|
1182
|
+
intent.getStringExtra(EXTRA_TRIGGER) ?: IMMEDIATE_TRIGGER_JSON,
|
|
1183
|
+
System.currentTimeMillis(),
|
|
1184
|
+
intent.getStringExtra(EXTRA_ACTION) ?: DEFAULT_ACTION_IDENTIFIER,
|
|
1185
|
+
userText,
|
|
1186
|
+
intent.getStringExtra(EXTRA_CATEGORY)
|
|
1187
|
+
)
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// a notification body tap, from OneNativeNotificationTapActivity before
|
|
1191
|
+
// the app opens. react native drops an onNewIntent that arrives before
|
|
1192
|
+
// its context is ready, which is how android hands the tap to an app
|
|
1193
|
+
// activity it recreates after the process died, so the response is
|
|
1194
|
+
// recorded on the process here and the app opens without it.
|
|
1195
|
+
fun handleTap(context: Context, intent: Intent) {
|
|
1196
|
+
val response = tapResponse(intent, null) ?: return
|
|
1197
|
+
lastResponse = response
|
|
1198
|
+
instance?.let { live ->
|
|
1199
|
+
live.currentListeners()?.onResponse?.invoke(live.responsePayload(response))
|
|
1200
|
+
}
|
|
1201
|
+
val launch =
|
|
1202
|
+
context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return
|
|
1203
|
+
launch.addFlags(
|
|
1204
|
+
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
1205
|
+
Intent.FLAG_ACTIVITY_CLEAR_TOP or
|
|
1206
|
+
Intent.FLAG_ACTIVITY_SINGLE_TOP
|
|
1207
|
+
)
|
|
1208
|
+
context.startActivity(launch)
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1197
1211
|
// action-tap entry: through the live hybrid when js is up, or
|
|
1198
1212
|
// recorded statically with a response-carrying launch when the
|
|
1199
1213
|
// process started for this broadcast. the activity harvest reads
|
|
@@ -1206,24 +1220,8 @@ class HybridOneNotifications :
|
|
|
1206
1220
|
}
|
|
1207
1221
|
val results = androidx.core.app.RemoteInput.getResultsFromIntent(intent)
|
|
1208
1222
|
val response =
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
intent.getStringExtra(EXTRA_TITLE),
|
|
1212
|
-
intent.getStringExtra(EXTRA_SUBTITLE),
|
|
1213
|
-
intent.getStringExtra(EXTRA_BODY),
|
|
1214
|
-
intent.getStringExtra(EXTRA_DATA) ?: "{}",
|
|
1215
|
-
intent.getBooleanExtra(EXTRA_SOUND, false),
|
|
1216
|
-
if (intent.hasExtra(EXTRA_BADGE)) {
|
|
1217
|
-
intent.getIntExtra(EXTRA_BADGE, 0)
|
|
1218
|
-
} else {
|
|
1219
|
-
null
|
|
1220
|
-
},
|
|
1221
|
-
intent.getStringExtra(EXTRA_TRIGGER) ?: IMMEDIATE_TRIGGER_JSON,
|
|
1222
|
-
System.currentTimeMillis(),
|
|
1223
|
-
intent.getStringExtra(EXTRA_ACTION) ?: DEFAULT_ACTION_IDENTIFIER,
|
|
1224
|
-
results?.getCharSequence(EXTRA_USER_TEXT)?.toString(),
|
|
1225
|
-
intent.getStringExtra(EXTRA_CATEGORY)
|
|
1226
|
-
)
|
|
1223
|
+
tapResponse(intent, results?.getCharSequence(EXTRA_USER_TEXT)?.toString())
|
|
1224
|
+
?: return
|
|
1227
1225
|
lastResponse = response
|
|
1228
1226
|
if (intent.getBooleanExtra(EXTRA_FOREGROUND, true)) {
|
|
1229
1227
|
foregroundWithResponse(context, response, results)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package dev.onejs.onenative
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.os.Bundle
|
|
5
|
+
import com.margelo.nitro.one.HybridOneNotifications
|
|
6
|
+
|
|
7
|
+
// a scheduled notification's body tap opens this invisible activity first: it
|
|
8
|
+
// records the response before any app activity sees the tap, then opens the
|
|
9
|
+
// app. never exported, so only the notification's own pending intent reaches it.
|
|
10
|
+
class OneNativeNotificationTapActivity : Activity() {
|
|
11
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
12
|
+
super.onCreate(savedInstanceState)
|
|
13
|
+
HybridOneNotifications.handleTap(this, intent)
|
|
14
|
+
finish()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -8,7 +8,6 @@ import androidx.compose.runtime.LaunchedEffect
|
|
|
8
8
|
import androidx.compose.runtime.getValue
|
|
9
9
|
import androidx.compose.runtime.key
|
|
10
10
|
import androidx.compose.runtime.mutableStateOf
|
|
11
|
-
import androidx.compose.runtime.remember
|
|
12
11
|
import androidx.compose.runtime.setValue
|
|
13
12
|
import androidx.compose.runtime.snapshotFlow
|
|
14
13
|
import androidx.compose.ui.Modifier
|
|
@@ -16,7 +15,8 @@ import androidx.compose.ui.graphics.Color
|
|
|
16
15
|
import androidx.compose.ui.platform.ComposeView
|
|
17
16
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
|
18
17
|
import androidx.lifecycle.LifecycleOwner
|
|
19
|
-
import androidx.lifecycle.
|
|
18
|
+
import androidx.lifecycle.findViewTreeLifecycleOwner
|
|
19
|
+
import androidx.lifecycle.setViewTreeLifecycleOwner
|
|
20
20
|
import com.facebook.react.bridge.ReadableArray
|
|
21
21
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
22
22
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
@@ -237,10 +237,14 @@ class OneNativeUiMapView(context: Context) : FrameLayout(context) {
|
|
|
237
237
|
cameraPositionState.position =
|
|
238
238
|
CameraPosition.fromLatLngZoom(LatLng(latitude, longitude), zoom.toFloat())
|
|
239
239
|
}
|
|
240
|
-
var gestureMove by remember { mutableStateOf(false) }
|
|
241
240
|
LaunchedEffect(cameraPositionState) {
|
|
241
|
+
var gestureMove = false
|
|
242
242
|
snapshotFlow { cameraPositionState.isMoving }.collect { moving ->
|
|
243
|
-
if (
|
|
243
|
+
if (moving) {
|
|
244
|
+
gestureMove =
|
|
245
|
+
cameraPositionState.cameraMoveStartedReason ==
|
|
246
|
+
CameraMoveStartedReason.GESTURE
|
|
247
|
+
} else if (gestureMove) {
|
|
244
248
|
gestureMove = false
|
|
245
249
|
val position = cameraPositionState.position
|
|
246
250
|
handleCameraMove(
|
|
@@ -255,9 +259,6 @@ class OneNativeUiMapView(context: Context) : FrameLayout(context) {
|
|
|
255
259
|
modifier = Modifier.fillMaxSize(),
|
|
256
260
|
cameraPositionState = cameraPositionState,
|
|
257
261
|
onMapClick = { point -> handleMapClick(point.latitude, point.longitude) },
|
|
258
|
-
onCameraMoveStarted = { reason ->
|
|
259
|
-
gestureMove = reason == CameraMoveStartedReason.GESTURE
|
|
260
|
-
},
|
|
261
262
|
) {
|
|
262
263
|
markers.forEach { marker ->
|
|
263
264
|
key(marker.id, marker.latitude, marker.longitude, marker.title, marker.tint) {
|
|
@@ -314,9 +315,9 @@ class OneNativeUiMapView(context: Context) : FrameLayout(context) {
|
|
|
314
315
|
// published here instead. retried on attach: the activity can be null
|
|
315
316
|
// while the view is constructed.
|
|
316
317
|
private fun ensureLifecycleOwner() {
|
|
317
|
-
if (
|
|
318
|
+
if (findViewTreeLifecycleOwner() != null) return
|
|
318
319
|
val activity = (context as? ThemedReactContext)?.currentActivity as? LifecycleOwner ?: return
|
|
319
|
-
|
|
320
|
+
setViewTreeLifecycleOwner(activity)
|
|
320
321
|
}
|
|
321
322
|
|
|
322
323
|
internal fun setLatitude(latitude: Double) {
|
|
@@ -76,8 +76,21 @@ function resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {
|
|
|
76
76
|
const requestType = request.method || "GET";
|
|
77
77
|
const handler = imported[requestType] || imported.default;
|
|
78
78
|
if (!handler) {
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
const allowedMethods = [
|
|
80
|
+
"GET",
|
|
81
|
+
"HEAD",
|
|
82
|
+
"POST",
|
|
83
|
+
"PUT",
|
|
84
|
+
"DELETE",
|
|
85
|
+
"CONNECT",
|
|
86
|
+
"OPTIONS",
|
|
87
|
+
"TRACE",
|
|
88
|
+
"PATCH"
|
|
89
|
+
].filter((method) => typeof imported[method] === "function").join(", ");
|
|
90
|
+
return new Response(null, {
|
|
91
|
+
status: 405,
|
|
92
|
+
headers: { Allow: allowedMethods }
|
|
93
|
+
});
|
|
81
94
|
}
|
|
82
95
|
const worker = env !== void 0 || executionCtx !== void 0 ? {
|
|
83
96
|
env,
|
|
@@ -78,8 +78,23 @@ function resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {
|
|
|
78
78
|
var requestType = request.method || "GET";
|
|
79
79
|
var handler = imported[requestType] || imported.default;
|
|
80
80
|
if (!handler) {
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
var allowedMethods = [
|
|
82
|
+
"GET",
|
|
83
|
+
"HEAD",
|
|
84
|
+
"POST",
|
|
85
|
+
"PUT",
|
|
86
|
+
"DELETE",
|
|
87
|
+
"CONNECT",
|
|
88
|
+
"OPTIONS",
|
|
89
|
+
"TRACE",
|
|
90
|
+
"PATCH"
|
|
91
|
+
].filter(function(method) {
|
|
92
|
+
return typeof imported[method] === "function";
|
|
93
|
+
}).join(", ");
|
|
94
|
+
return new Response(null, {
|
|
95
|
+
status: 405,
|
|
96
|
+
headers: { Allow: allowedMethods }
|
|
97
|
+
});
|
|
83
98
|
}
|
|
84
99
|
var worker = env !== void 0 || executionCtx !== void 0 ? {
|
|
85
100
|
env,
|
|
@@ -78,8 +78,23 @@ function resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {
|
|
|
78
78
|
var requestType = request.method || "GET";
|
|
79
79
|
var handler = imported[requestType] || imported.default;
|
|
80
80
|
if (!handler) {
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
var allowedMethods = [
|
|
82
|
+
"GET",
|
|
83
|
+
"HEAD",
|
|
84
|
+
"POST",
|
|
85
|
+
"PUT",
|
|
86
|
+
"DELETE",
|
|
87
|
+
"CONNECT",
|
|
88
|
+
"OPTIONS",
|
|
89
|
+
"TRACE",
|
|
90
|
+
"PATCH"
|
|
91
|
+
].filter(function(method) {
|
|
92
|
+
return typeof imported[method] === "function";
|
|
93
|
+
}).join(", ");
|
|
94
|
+
return new Response(null, {
|
|
95
|
+
status: 405,
|
|
96
|
+
headers: { Allow: allowedMethods }
|
|
97
|
+
});
|
|
83
98
|
}
|
|
84
99
|
var worker = env !== void 0 || executionCtx !== void 0 ? {
|
|
85
100
|
env,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveResponse.native.js","names":[],"sources":["cjs/vite/resolveResponse.native.js"],"sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\nvar resolveResponse_exports = {};\n__export(resolveResponse_exports, {\n resolveAPIEndpoint: () => resolveAPIEndpoint,\n resolveResponse: () => resolveResponse,\n withRequestContext: () => withRequestContext\n});\nmodule.exports = __toCommonJS(resolveResponse_exports);\nvar import_isResponse = require(\"../utils/isResponse\");\nvar import_one_server_only = require(\"./one-server-only\");\nvar _nextId = 1;\nfunction createId() {\n return {\n _id: _nextId++\n };\n}\nasync function resolveResponse(getResponse) {\n var store = import_one_server_only.requestAsyncLocalStore !== null && import_one_server_only.requestAsyncLocalStore !== void 0 ? import_one_server_only.requestAsyncLocalStore : globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n var id = createId();\n var response;\n await store.run(id, async function() {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if ((0, import_isResponse.isResponse)(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return (0, import_one_server_only.runWithAsyncLocalContext)(async function(id2) {\n try {\n var response2 = await getResponse();\n return await getResponseWithAddedHeaders(response2, id2);\n } catch (err) {\n if ((0, import_isResponse.isResponse)(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n var store = import_one_server_only.requestAsyncLocalStore;\n if (store) {\n var id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async function() {\n var imported = await runEndpoint();\n var requestType = request.method || \"GET\";\n var handler = imported[requestType] || imported.default;\n if (!handler) {\n
|
|
1
|
+
{"version":3,"file":"resolveResponse.native.js","names":[],"sources":["cjs/vite/resolveResponse.native.js"],"sourcesContent":["\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\nvar resolveResponse_exports = {};\n__export(resolveResponse_exports, {\n resolveAPIEndpoint: () => resolveAPIEndpoint,\n resolveResponse: () => resolveResponse,\n withRequestContext: () => withRequestContext\n});\nmodule.exports = __toCommonJS(resolveResponse_exports);\nvar import_isResponse = require(\"../utils/isResponse\");\nvar import_one_server_only = require(\"./one-server-only\");\nvar _nextId = 1;\nfunction createId() {\n return {\n _id: _nextId++\n };\n}\nasync function resolveResponse(getResponse) {\n var store = import_one_server_only.requestAsyncLocalStore !== null && import_one_server_only.requestAsyncLocalStore !== void 0 ? import_one_server_only.requestAsyncLocalStore : globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n var id = createId();\n var response;\n await store.run(id, async function() {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if ((0, import_isResponse.isResponse)(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return (0, import_one_server_only.runWithAsyncLocalContext)(async function(id2) {\n try {\n var response2 = await getResponse();\n return await getResponseWithAddedHeaders(response2, id2);\n } catch (err) {\n if ((0, import_isResponse.isResponse)(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n var store = import_one_server_only.requestAsyncLocalStore;\n if (store) {\n var id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async function() {\n var imported = await runEndpoint();\n var requestType = request.method || \"GET\";\n var handler = imported[requestType] || imported.default;\n if (!handler) {\n var allowedMethods = [\n \"GET\",\n \"HEAD\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"CONNECT\",\n \"OPTIONS\",\n \"TRACE\",\n \"PATCH\"\n ].filter(function(method) {\n return typeof imported[method] === \"function\";\n }).join(\", \");\n return new Response(null, {\n status: 405,\n headers: {\n Allow: allowedMethods\n }\n });\n }\n var worker = env !== void 0 || executionCtx !== void 0 ? {\n env,\n executionCtx\n } : void 0;\n return await handler(request, {\n params,\n worker\n });\n });\n}\nasync function getResponseWithAddedHeaders(response, id) {\n var _globalThis___vxrnasyncHeadersCache;\n var cache = (_globalThis___vxrnasyncHeadersCache = globalThis[\"__vxrnasyncHeadersCache\"]) !== null && _globalThis___vxrnasyncHeadersCache !== void 0 ? _globalThis___vxrnasyncHeadersCache : import_one_server_only.asyncHeadersCache;\n var asyncHeaders = cache.get(id);\n if (asyncHeaders) {\n try {\n if (response instanceof Response) {\n var cloned = response.clone();\n var headers = new Headers();\n (0, import_one_server_only.mergeHeaders)(headers, cloned.headers);\n (0, import_one_server_only.mergeHeaders)(headers, asyncHeaders);\n response = new Response(cloned.body, {\n status: cloned.status,\n statusText: cloned.statusText,\n headers\n });\n } else {\n if (response && typeof response === \"object\") {\n response = Response.json(response, {\n headers: asyncHeaders\n });\n } else {\n var headers1 = new Headers(asyncHeaders);\n if (!headers1.has(\"content-type\")) {\n headers1.set(\"content-type\", \"text/html\");\n }\n response = new Response(response, {\n headers: headers1\n });\n }\n }\n } catch (err) {\n console.error(` [one] error adding headers: ${err}`);\n }\n }\n return response;\n}\n//# sourceMappingURL=resolveResponse.js.map\n"],"mappings":"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"}
|
|
@@ -50,8 +50,21 @@ function resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {
|
|
|
50
50
|
const requestType = request.method || "GET";
|
|
51
51
|
const handler = imported[requestType] || imported.default;
|
|
52
52
|
if (!handler) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const allowedMethods = [
|
|
54
|
+
"GET",
|
|
55
|
+
"HEAD",
|
|
56
|
+
"POST",
|
|
57
|
+
"PUT",
|
|
58
|
+
"DELETE",
|
|
59
|
+
"CONNECT",
|
|
60
|
+
"OPTIONS",
|
|
61
|
+
"TRACE",
|
|
62
|
+
"PATCH"
|
|
63
|
+
].filter((method) => typeof imported[method] === "function").join(", ");
|
|
64
|
+
return new Response(null, {
|
|
65
|
+
status: 405,
|
|
66
|
+
headers: { Allow: allowedMethods }
|
|
67
|
+
});
|
|
55
68
|
}
|
|
56
69
|
const worker = env !== void 0 || executionCtx !== void 0 ? {
|
|
57
70
|
env,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveResponse.js","names":[],"sources":["esm/vite/resolveResponse.js"],"sourcesContent":["import { isResponse } from \"../utils/isResponse\";\nimport {\n asyncHeadersCache,\n mergeHeaders,\n requestAsyncLocalStore,\n runWithAsyncLocalContext\n} from \"./one-server-only\";\nlet _nextId = 1;\nfunction createId() {\n return { _id: _nextId++ };\n}\nasync function resolveResponse(getResponse) {\n const store = requestAsyncLocalStore ?? globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n const id = createId();\n let response;\n await store.run(id, async () => {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return runWithAsyncLocalContext(async (id) => {\n try {\n const response = await getResponse();\n return await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n const store = requestAsyncLocalStore;\n if (store) {\n const id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async () => {\n const imported = await runEndpoint();\n const requestType = request.method || \"GET\";\n const handler = imported[requestType] || imported.default;\n if (!handler) {\n
|
|
1
|
+
{"version":3,"file":"resolveResponse.js","names":[],"sources":["esm/vite/resolveResponse.js"],"sourcesContent":["import { isResponse } from \"../utils/isResponse\";\nimport {\n asyncHeadersCache,\n mergeHeaders,\n requestAsyncLocalStore,\n runWithAsyncLocalContext\n} from \"./one-server-only\";\nlet _nextId = 1;\nfunction createId() {\n return { _id: _nextId++ };\n}\nasync function resolveResponse(getResponse) {\n const store = requestAsyncLocalStore ?? globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n const id = createId();\n let response;\n await store.run(id, async () => {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return runWithAsyncLocalContext(async (id) => {\n try {\n const response = await getResponse();\n return await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n const store = requestAsyncLocalStore;\n if (store) {\n const id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async () => {\n const imported = await runEndpoint();\n const requestType = request.method || \"GET\";\n const handler = imported[requestType] || imported.default;\n if (!handler) {\n const allowedMethods = [\n \"GET\",\n \"HEAD\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"CONNECT\",\n \"OPTIONS\",\n \"TRACE\",\n \"PATCH\"\n ].filter((method) => typeof imported[method] === \"function\").join(\", \");\n return new Response(null, {\n status: 405,\n headers: { Allow: allowedMethods }\n });\n }\n const worker = env !== void 0 || executionCtx !== void 0 ? { env, executionCtx } : void 0;\n return await handler(request, { params, worker });\n });\n}\nasync function getResponseWithAddedHeaders(response, id) {\n const cache = globalThis[\"__vxrnasyncHeadersCache\"] ?? asyncHeadersCache;\n const asyncHeaders = cache.get(id);\n if (asyncHeaders) {\n try {\n if (response instanceof Response) {\n const cloned = response.clone();\n const headers = new Headers();\n mergeHeaders(headers, cloned.headers);\n mergeHeaders(headers, asyncHeaders);\n response = new Response(cloned.body, {\n status: cloned.status,\n statusText: cloned.statusText,\n headers\n });\n } else {\n if (response && typeof response === \"object\") {\n response = Response.json(response, { headers: asyncHeaders });\n } else {\n const headers = new Headers(asyncHeaders);\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html\");\n }\n response = new Response(response, { headers });\n }\n }\n } catch (err) {\n console.error(` [one] error adding headers: ${err}`);\n }\n }\n return response;\n}\nexport {\n resolveAPIEndpoint,\n resolveResponse,\n withRequestContext\n};\n//# sourceMappingURL=resolveResponse.js.map\n"],"mappings":";;;;AAOA,IAAI,UAAU;AACd,SAAS,WAAW;CAClB,OAAO,EAAE,KAAK,UAAU;AAC1B;AACA,eAAe,gBAAgB,aAAa;CAC1C,MAAM,QAAQ,0BAA0B,WAAW;CACnD,IAAI,OAAO;EACT,MAAM,KAAK,SAAS;EACpB,IAAI;EACJ,MAAM,MAAM,IAAI,IAAI,YAAY;GAC9B,IAAI;IACF,WAAW,MAAM,YAAY;IAC7B,WAAW,MAAM,4BAA4B,UAAU,EAAE;GAC3D,SAAS,KAAK;IACZ,IAAI,WAAW,GAAG,GAAG;KACnB,WAAW;IACb,OAAO;KACL,MAAM;IACR;GACF;EACF,CAAC;EACD,OAAO;CACT;CACA,OAAO,yBAAyB,OAAO,OAAO;EAC5C,IAAI;GACF,MAAM,WAAW,MAAM,YAAY;GACnC,OAAO,MAAM,4BAA4B,UAAU,EAAE;EACvD,SAAS,KAAK;GACZ,IAAI,WAAW,GAAG,GAAG;IACnB,OAAO;GACT;GACA,MAAM;EACR;CACF,CAAC;AACH;AACA,SAAS,mBAAmB,IAAI;CAC9B,MAAM,QAAQ;CACd,IAAI,OAAO;EACT,MAAM,KAAK,SAAS;EACpB,OAAO,MAAM,IAAI,IAAI,EAAE;CACzB;CACA,OAAO,GAAG;AACZ;AACA,SAAS,mBAAmB,aAAa,SAAS,QAAQ,KAAK,cAAc;CAC3E,OAAO,gBAAgB,YAAY;EACjC,MAAM,WAAW,MAAM,YAAY;EACnC,MAAM,cAAc,QAAQ,UAAU;EACtC,MAAM,UAAU,SAAS,gBAAgB,SAAS;EAClD,IAAI,CAAC,SAAS;GACZ,MAAM,iBAAiB;IACrB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC,CAAC,QAAQ,WAAW,OAAO,SAAS,YAAY,UAAU,CAAC,CAAC,KAAK,IAAI;GACtE,OAAO,IAAI,SAAS,MAAM;IACxB,QAAQ;IACR,SAAS,EAAE,OAAO,eAAe;GACnC,CAAC;EACH;EACA,MAAM,SAAS,QAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI;GAAE;GAAK;EAAa,IAAI,KAAK;EACxF,OAAO,MAAM,QAAQ,SAAS;GAAE;GAAQ;EAAO,CAAC;CAClD,CAAC;AACH;AACA,eAAe,4BAA4B,UAAU,IAAI;CACvD,MAAM,QAAQ,WAAW,8BAA8B;CACvD,MAAM,eAAe,MAAM,IAAI,EAAE;CACjC,IAAI,cAAc;EAChB,IAAI;GACF,IAAI,oBAAoB,UAAU;IAChC,MAAM,SAAS,SAAS,MAAM;IAC9B,MAAM,UAAU,IAAI,QAAQ;IAC5B,aAAa,SAAS,OAAO,OAAO;IACpC,aAAa,SAAS,YAAY;IAClC,WAAW,IAAI,SAAS,OAAO,MAAM;KACnC,QAAQ,OAAO;KACf,YAAY,OAAO;KACnB;IACF,CAAC;GACH,OAAO;IACL,IAAI,YAAY,OAAO,aAAa,UAAU;KAC5C,WAAW,SAAS,KAAK,UAAU,EAAE,SAAS,aAAa,CAAC;IAC9D,OAAO;KACL,MAAM,UAAU,IAAI,QAAQ,YAAY;KACxC,IAAI,CAAC,QAAQ,IAAI,cAAc,GAAG;MAChC,QAAQ,IAAI,gBAAgB,WAAW;KACzC;KACA,WAAW,IAAI,SAAS,UAAU,EAAE,QAAQ,CAAC;IAC/C;GACF;EACF,SAAS,KAAK;GACZ,QAAQ,MAAM,gCAAgC,KAAK;EACrD;CACF;CACA,OAAO;AACT"}
|
|
@@ -50,8 +50,23 @@ function resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {
|
|
|
50
50
|
var requestType = request.method || "GET";
|
|
51
51
|
var handler = imported[requestType] || imported.default;
|
|
52
52
|
if (!handler) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
var allowedMethods = [
|
|
54
|
+
"GET",
|
|
55
|
+
"HEAD",
|
|
56
|
+
"POST",
|
|
57
|
+
"PUT",
|
|
58
|
+
"DELETE",
|
|
59
|
+
"CONNECT",
|
|
60
|
+
"OPTIONS",
|
|
61
|
+
"TRACE",
|
|
62
|
+
"PATCH"
|
|
63
|
+
].filter(function(method) {
|
|
64
|
+
return typeof imported[method] === "function";
|
|
65
|
+
}).join(", ");
|
|
66
|
+
return new Response(null, {
|
|
67
|
+
status: 405,
|
|
68
|
+
headers: { Allow: allowedMethods }
|
|
69
|
+
});
|
|
55
70
|
}
|
|
56
71
|
var worker = env !== void 0 || executionCtx !== void 0 ? {
|
|
57
72
|
env,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveResponse.native.js","names":[],"sources":["esm/vite/resolveResponse.native.js"],"sourcesContent":["import { isResponse } from \"../utils/isResponse\";\nimport { asyncHeadersCache, mergeHeaders, requestAsyncLocalStore, runWithAsyncLocalContext } from \"./one-server-only\";\nvar _nextId = 1;\nfunction createId() {\n return {\n _id: _nextId++\n };\n}\nasync function resolveResponse(getResponse) {\n var store = requestAsyncLocalStore !== null && requestAsyncLocalStore !== void 0 ? requestAsyncLocalStore : globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n var id = createId();\n var response;\n await store.run(id, async function() {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return runWithAsyncLocalContext(async function(id2) {\n try {\n var response2 = await getResponse();\n return await getResponseWithAddedHeaders(response2, id2);\n } catch (err) {\n if (isResponse(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n var store = requestAsyncLocalStore;\n if (store) {\n var id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async function() {\n var imported = await runEndpoint();\n var requestType = request.method || \"GET\";\n var handler = imported[requestType] || imported.default;\n if (!handler) {\n
|
|
1
|
+
{"version":3,"file":"resolveResponse.native.js","names":[],"sources":["esm/vite/resolveResponse.native.js"],"sourcesContent":["import { isResponse } from \"../utils/isResponse\";\nimport { asyncHeadersCache, mergeHeaders, requestAsyncLocalStore, runWithAsyncLocalContext } from \"./one-server-only\";\nvar _nextId = 1;\nfunction createId() {\n return {\n _id: _nextId++\n };\n}\nasync function resolveResponse(getResponse) {\n var store = requestAsyncLocalStore !== null && requestAsyncLocalStore !== void 0 ? requestAsyncLocalStore : globalThis[\"__vxrnrequestAsyncLocalStore\"];\n if (store) {\n var id = createId();\n var response;\n await store.run(id, async function() {\n try {\n response = await getResponse();\n response = await getResponseWithAddedHeaders(response, id);\n } catch (err) {\n if (isResponse(err)) {\n response = err;\n } else {\n throw err;\n }\n }\n });\n return response;\n }\n return runWithAsyncLocalContext(async function(id2) {\n try {\n var response2 = await getResponse();\n return await getResponseWithAddedHeaders(response2, id2);\n } catch (err) {\n if (isResponse(err)) {\n return err;\n }\n throw err;\n }\n });\n}\nfunction withRequestContext(fn) {\n var store = requestAsyncLocalStore;\n if (store) {\n var id = createId();\n return store.run(id, fn);\n }\n return fn();\n}\nfunction resolveAPIEndpoint(runEndpoint, request, params, env, executionCtx) {\n return resolveResponse(async function() {\n var imported = await runEndpoint();\n var requestType = request.method || \"GET\";\n var handler = imported[requestType] || imported.default;\n if (!handler) {\n var allowedMethods = [\n \"GET\",\n \"HEAD\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"CONNECT\",\n \"OPTIONS\",\n \"TRACE\",\n \"PATCH\"\n ].filter(function(method) {\n return typeof imported[method] === \"function\";\n }).join(\", \");\n return new Response(null, {\n status: 405,\n headers: {\n Allow: allowedMethods\n }\n });\n }\n var worker = env !== void 0 || executionCtx !== void 0 ? {\n env,\n executionCtx\n } : void 0;\n return await handler(request, {\n params,\n worker\n });\n });\n}\nasync function getResponseWithAddedHeaders(response, id) {\n var _globalThis___vxrnasyncHeadersCache;\n var cache = (_globalThis___vxrnasyncHeadersCache = globalThis[\"__vxrnasyncHeadersCache\"]) !== null && _globalThis___vxrnasyncHeadersCache !== void 0 ? _globalThis___vxrnasyncHeadersCache : asyncHeadersCache;\n var asyncHeaders = cache.get(id);\n if (asyncHeaders) {\n try {\n if (response instanceof Response) {\n var cloned = response.clone();\n var headers = new Headers();\n mergeHeaders(headers, cloned.headers);\n mergeHeaders(headers, asyncHeaders);\n response = new Response(cloned.body, {\n status: cloned.status,\n statusText: cloned.statusText,\n headers\n });\n } else {\n if (response && typeof response === \"object\") {\n response = Response.json(response, {\n headers: asyncHeaders\n });\n } else {\n var headers1 = new Headers(asyncHeaders);\n if (!headers1.has(\"content-type\")) {\n headers1.set(\"content-type\", \"text/html\");\n }\n response = new Response(response, {\n headers: headers1\n });\n }\n }\n } catch (err) {\n console.error(` [one] error adding headers: ${err}`);\n }\n }\n return response;\n}\nexport {\n resolveAPIEndpoint,\n resolveResponse,\n withRequestContext\n};\n//# sourceMappingURL=resolveResponse.js.map\n"],"mappings":";;;;AAEA,IAAI,UAAU;AACd,SAAS,WAAW;CAClB,OAAO,EACL,KAAK,UACP;AACF;AACA,eAAe,gBAAgB,aAAa;CAC1C,IAAI,QAAQ,2BAA2B,QAAQ,2BAA2B,KAAK,IAAI,yBAAyB,WAAW;CACvH,IAAI,OAAO;EACT,IAAI,KAAK,SAAS;EAClB,IAAI;EACJ,MAAM,MAAM,IAAI,IAAI,iBAAiB;GACnC,IAAI;IACF,WAAW,MAAM,YAAY;IAC7B,WAAW,MAAM,4BAA4B,UAAU,EAAE;GAC3D,SAAS,KAAK;IACZ,IAAI,WAAW,GAAG,GAAG;KACnB,WAAW;IACb,OAAO;KACL,MAAM;IACR;GACF;EACF,CAAC;EACD,OAAO;CACT;CACA,OAAO,yBAAyB,eAAe,KAAK;EAClD,IAAI;GACF,IAAI,YAAY,MAAM,YAAY;GAClC,OAAO,MAAM,4BAA4B,WAAW,GAAG;EACzD,SAAS,KAAK;GACZ,IAAI,WAAW,GAAG,GAAG;IACnB,OAAO;GACT;GACA,MAAM;EACR;CACF,CAAC;AACH;AACA,SAAS,mBAAmB,IAAI;CAC9B,IAAI,QAAQ;CACZ,IAAI,OAAO;EACT,IAAI,KAAK,SAAS;EAClB,OAAO,MAAM,IAAI,IAAI,EAAE;CACzB;CACA,OAAO,GAAG;AACZ;AACA,SAAS,mBAAmB,aAAa,SAAS,QAAQ,KAAK,cAAc;CAC3E,OAAO,gBAAgB,iBAAiB;EACtC,IAAI,WAAW,MAAM,YAAY;EACjC,IAAI,cAAc,QAAQ,UAAU;EACpC,IAAI,UAAU,SAAS,gBAAgB,SAAS;EAChD,IAAI,CAAC,SAAS;GACZ,IAAI,iBAAiB;IACnB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACF,CAAC,CAAC,OAAO,SAAS,QAAQ;IACxB,OAAO,OAAO,SAAS,YAAY;GACrC,CAAC,CAAC,CAAC,KAAK,IAAI;GACZ,OAAO,IAAI,SAAS,MAAM;IACxB,QAAQ;IACR,SAAS,EACP,OAAO,eACT;GACF,CAAC;EACH;EACA,IAAI,SAAS,QAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI;GACvD;GACA;EACF,IAAI,KAAK;EACT,OAAO,MAAM,QAAQ,SAAS;GAC5B;GACA;EACF,CAAC;CACH,CAAC;AACH;AACA,eAAe,4BAA4B,UAAU,IAAI;CACvD,IAAI;CACJ,IAAI,SAAS,sCAAsC,WAAW,gCAAgC,QAAQ,wCAAwC,KAAK,IAAI,sCAAsC;CAC7L,IAAI,eAAe,MAAM,IAAI,EAAE;CAC/B,IAAI,cAAc;EAChB,IAAI;GACF,IAAI,oBAAoB,UAAU;IAChC,IAAI,SAAS,SAAS,MAAM;IAC5B,IAAI,UAAU,IAAI,QAAQ;IAC1B,aAAa,SAAS,OAAO,OAAO;IACpC,aAAa,SAAS,YAAY;IAClC,WAAW,IAAI,SAAS,OAAO,MAAM;KACnC,QAAQ,OAAO;KACf,YAAY,OAAO;KACnB;IACF,CAAC;GACH,OAAO;IACL,IAAI,YAAY,OAAO,aAAa,UAAU;KAC5C,WAAW,SAAS,KAAK,UAAU,EACjC,SAAS,aACX,CAAC;IACH,OAAO;KACL,IAAI,WAAW,IAAI,QAAQ,YAAY;KACvC,IAAI,CAAC,SAAS,IAAI,cAAc,GAAG;MACjC,SAAS,IAAI,gBAAgB,WAAW;KAC1C;KACA,WAAW,IAAI,SAAS,UAAU,EAChC,SAAS,SACX,CAAC;IACH;GACF;EACF,SAAS,KAAK;GACZ,QAAQ,MAAM,gCAAgC,KAAK;EACrD;CACF;CACA,OAAO;AACT"}
|
|
@@ -12,9 +12,10 @@ swift build --triple arm64-apple-ios17.0-simulator \
|
|
|
12
12
|
--package-path packages/one/ios/Tests/ImageManipulator
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
The real `SDWebImageWebPCoder` call shape (`
|
|
15
|
+
The real `SDWebImageWebPCoder` call shape (`shared`, `.webP`,
|
|
16
16
|
`.encodeCompressionQuality`) was read off the vendored 0.15.0 pod headers, not
|
|
17
|
-
the stub
|
|
17
|
+
the stub; Xcode 27 imports the header's `sharedCoder` class property as
|
|
18
|
+
`shared`. The stub only proves the production file is internally consistent.
|
|
18
19
|
Real WebP bytes, flip pixels, and validation codes are proven by the
|
|
19
20
|
native-features `image-manipulator` fixture on the iOS 27 simulator and
|
|
20
21
|
Android 37 emulator; this harness does not prove transport, sandbox behavior,
|
|
@@ -12,7 +12,7 @@ public struct SDImageCoderOption: Hashable {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
public final class SDImageWebPCoder {
|
|
15
|
-
public static let
|
|
15
|
+
public static let shared = SDImageWebPCoder()
|
|
16
16
|
public func encodedData(
|
|
17
17
|
with image: UIImage?,
|
|
18
18
|
format: SDImageFormat,
|
|
@@ -3,6 +3,21 @@ import React
|
|
|
3
3
|
|
|
4
4
|
// RNSScreen accessed via NSClassFromString without direct import
|
|
5
5
|
import UIKit
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
// one json line per UIKit call into the zoom providers, at debug level, which
|
|
9
|
+
// costs nothing until a log stream asks for it. tests/native-features reads
|
|
10
|
+
// these to prove UIKit invoked the real providers.
|
|
11
|
+
private let zoomCallbackLog = Logger(subsystem: "dev.onestack.one", category: "zoom")
|
|
12
|
+
|
|
13
|
+
private func logZoomCallback(_ event: @escaping @autoclosure () -> [String: Any]) {
|
|
14
|
+
zoomCallbackLog.debug("\(zoomCallbackJSON(event()), privacy: .public)")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private func zoomCallbackJSON(_ event: [String: Any]) -> String {
|
|
18
|
+
guard let data = try? JSONSerialization.data(withJSONObject: event) else { return "{}" }
|
|
19
|
+
return String(decoding: data, as: UTF8.self)
|
|
20
|
+
}
|
|
6
21
|
|
|
7
22
|
// MARK: - singleton manager for zoom transition repositories
|
|
8
23
|
|
|
@@ -303,21 +318,29 @@ class ZoomTransitionEnablerView: RCTView {
|
|
|
303
318
|
// keep destination geometry through dismissal after React removes its detector.
|
|
304
319
|
var destinationAlignmentRect: CGRect?
|
|
305
320
|
options.alignmentRectProvider = { context in
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
+
let alignment: CGRect? = {
|
|
322
|
+
guard let sourceInfo = self.sourceRepository.getSource(
|
|
323
|
+
identifier: self._zoomTransitionSourceIdentifier)
|
|
324
|
+
else { return nil }
|
|
325
|
+
guard let alignmentView = self.alignmentViewRepository.get(
|
|
326
|
+
identifier: self._zoomTransitionSourceIdentifier)
|
|
327
|
+
else { return destinationAlignmentRect ?? sourceInfo.alignment }
|
|
328
|
+
|
|
329
|
+
let rect = alignmentView.convert(
|
|
330
|
+
alignmentView.bounds, to: context.zoomedViewController.view)
|
|
331
|
+
if sourceInfo.animateAspectRatioChange, let sourceView = sourceInfo.view {
|
|
332
|
+
destinationAlignmentRect = self.calculateAdjustedRect(rect, toMatch: sourceView.bounds.size)
|
|
333
|
+
} else {
|
|
334
|
+
destinationAlignmentRect = rect
|
|
335
|
+
}
|
|
336
|
+
return destinationAlignmentRect
|
|
337
|
+
}()
|
|
338
|
+
logZoomCallback([
|
|
339
|
+
"kind": "alignment",
|
|
340
|
+
"identifier": self._zoomTransitionSourceIdentifier,
|
|
341
|
+
"rect": alignment.map { [$0.origin.x, $0.origin.y, $0.width, $0.height] as Any } ?? NSNull(),
|
|
342
|
+
])
|
|
343
|
+
return alignment
|
|
321
344
|
}
|
|
322
345
|
|
|
323
346
|
if let rect = _dismissalBoundsRect {
|
|
@@ -334,6 +357,7 @@ class ZoomTransitionEnablerView: RCTView {
|
|
|
334
357
|
controller.preferredTransition = .zoom(options: options) { _ in
|
|
335
358
|
let sourceInfo = self.sourceRepository.getSource(
|
|
336
359
|
identifier: self._zoomTransitionSourceIdentifier)
|
|
360
|
+
logZoomCallback(self.sourceCallbackEvent(sourceInfo?.view))
|
|
337
361
|
guard let view = sourceInfo?.view else {
|
|
338
362
|
NSLog("[one] No source view found for identifier %@.", self._zoomTransitionSourceIdentifier)
|
|
339
363
|
return nil
|
|
@@ -349,6 +373,19 @@ class ZoomTransitionEnablerView: RCTView {
|
|
|
349
373
|
}
|
|
350
374
|
}
|
|
351
375
|
|
|
376
|
+
private func sourceCallbackEvent(_ view: UIView?) -> [String: Any] {
|
|
377
|
+
var event: [String: Any] = ["kind": "source", "identifier": _zoomTransitionSourceIdentifier]
|
|
378
|
+
guard let view else {
|
|
379
|
+
event["view"] = "0x0"
|
|
380
|
+
return event
|
|
381
|
+
}
|
|
382
|
+
event["view"] = String(format: "0x%lx", Int(bitPattern: Unmanaged.passUnretained(view).toOpaque()))
|
|
383
|
+
event["testID"] = view.accessibilityIdentifier ?? NSNull()
|
|
384
|
+
event["mounted"] = view.window != nil
|
|
385
|
+
event["bounds"] = NSCoder.string(for: view.bounds)
|
|
386
|
+
return event
|
|
387
|
+
}
|
|
388
|
+
|
|
352
389
|
private func calculateAdjustedRect(_ rect: CGRect, toMatch sourceSize: CGSize) -> CGRect {
|
|
353
390
|
guard sourceSize.width > 0, sourceSize.height > 0, rect.width > 0, rect.height > 0 else {
|
|
354
391
|
return rect
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "one",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.4",
|
|
4
4
|
"description": "One is a React framework for web, iOS, and Android apps.",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"sideEffects": [
|
|
@@ -236,18 +236,18 @@
|
|
|
236
236
|
"@react-navigation/native-stack": "8.0.0-alpha.59",
|
|
237
237
|
"@react-navigation/routers": "8.0.0-alpha.21",
|
|
238
238
|
"@ungap/structured-clone": "^1.2.0",
|
|
239
|
-
"@vxrn/color-scheme": "2.7.
|
|
240
|
-
"@vxrn/compiler": "2.7.
|
|
241
|
-
"@vxrn/resolve": "2.7.
|
|
242
|
-
"@vxrn/tslib-lite": "2.7.
|
|
243
|
-
"@vxrn/use-isomorphic-layout-effect": "2.7.
|
|
244
|
-
"@vxrn/utils": "2.7.
|
|
245
|
-
"@vxrn/vite-plugin-metro": "2.7.
|
|
239
|
+
"@vxrn/color-scheme": "2.7.4",
|
|
240
|
+
"@vxrn/compiler": "2.7.4",
|
|
241
|
+
"@vxrn/resolve": "2.7.4",
|
|
242
|
+
"@vxrn/tslib-lite": "2.7.4",
|
|
243
|
+
"@vxrn/use-isomorphic-layout-effect": "2.7.4",
|
|
244
|
+
"@vxrn/utils": "2.7.4",
|
|
245
|
+
"@vxrn/vite-plugin-metro": "2.7.4",
|
|
246
246
|
"babel-dead-code-elimination": "1.0.10",
|
|
247
247
|
"babel-plugin-module-resolver": "^5.0.2",
|
|
248
248
|
"citty": "^0.1.6",
|
|
249
249
|
"core-js": "^3.38.1",
|
|
250
|
-
"create-vxrn": "2.7.
|
|
250
|
+
"create-vxrn": "2.7.4",
|
|
251
251
|
"escape-string-regexp": "^5.0.0",
|
|
252
252
|
"fast-deep-equal": "^3.1.3",
|
|
253
253
|
"fast-glob": "^3.3.3",
|
|
@@ -269,7 +269,7 @@
|
|
|
269
269
|
"tsconfig-paths": "^4",
|
|
270
270
|
"use-latest-callback": "^0.2.3",
|
|
271
271
|
"vite": "^8.2.2",
|
|
272
|
-
"vxrn": "2.7.
|
|
272
|
+
"vxrn": "2.7.4",
|
|
273
273
|
"web-streams-polyfill": "^4.3.0",
|
|
274
274
|
"ws": "^8.21.0",
|
|
275
275
|
"xxhashjs": "^0.2.2"
|
|
@@ -325,19 +325,19 @@
|
|
|
325
325
|
}
|
|
326
326
|
},
|
|
327
327
|
"devDependencies": {
|
|
328
|
-
"@tamagui/sheet": "3.0.
|
|
328
|
+
"@tamagui/sheet": "3.0.13",
|
|
329
329
|
"@callstack/liquid-glass": "^0.8.1",
|
|
330
330
|
"@react-native/babel-plugin-codegen": "0.87.1",
|
|
331
331
|
"@react-native/codegen": "^0.87.1",
|
|
332
332
|
"@react-navigation/core": "8.0.0-alpha.41",
|
|
333
333
|
"@react-navigation/drawer": "8.0.0-alpha.58",
|
|
334
334
|
"@react-navigation/native": "8.0.0-alpha.51",
|
|
335
|
-
"@tamagui/build": "3.0.
|
|
335
|
+
"@tamagui/build": "3.0.13",
|
|
336
336
|
"@types/node": "^24.10.0",
|
|
337
337
|
"@types/react-dom": "^19.2.2",
|
|
338
338
|
"@types/react-test-renderer": "^19.1.0",
|
|
339
339
|
"@types/xxhashjs": "^0.2.4",
|
|
340
|
-
"@vxrn/emitter": "2.7.
|
|
340
|
+
"@vxrn/emitter": "2.7.4",
|
|
341
341
|
"depcheck": "^1.4.7",
|
|
342
342
|
"esbuild": "^0.25.12",
|
|
343
343
|
"immer": "^10.1.1",
|
|
@@ -356,7 +356,7 @@
|
|
|
356
356
|
"typescript": "7.0.2",
|
|
357
357
|
"vitest": "^4.1.0",
|
|
358
358
|
"yoga-layout": "^3.2.1",
|
|
359
|
-
"@tamagui/web": "3.0.
|
|
359
|
+
"@tamagui/web": "3.0.13"
|
|
360
360
|
},
|
|
361
361
|
"publishConfig": {
|
|
362
362
|
"access": "public"
|
|
@@ -513,7 +513,7 @@
|
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
},
|
|
516
|
-
"releaseSourceCommit": "
|
|
516
|
+
"releaseSourceCommit": "f60870e3a32efb3f3577234b92e5b7de663b12b7",
|
|
517
517
|
"repository": {
|
|
518
518
|
"type": "git",
|
|
519
519
|
"url": "git+https://github.com/onejs/one.git",
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it, vi, beforeEach } from 'vitest'
|
|
2
2
|
import { createHandleRequest } from './createDevHandleRequest'
|
|
3
|
+
import { resolveAPIRoute } from './createHandleRequest'
|
|
4
|
+
import type { Middleware } from './createMiddleware'
|
|
5
|
+
import type { RouteInfoCompiled } from './server/createRoutesManifest'
|
|
3
6
|
|
|
4
7
|
// Mock the manifest. Specific routes come before dynamic ones, matching how
|
|
5
8
|
// the real manifest is ordered after matchers.sortRoutes().
|
|
@@ -355,3 +358,98 @@ describe('createHandleRequest', () => {
|
|
|
355
358
|
})
|
|
356
359
|
})
|
|
357
360
|
})
|
|
361
|
+
|
|
362
|
+
describe('API method contract', () => {
|
|
363
|
+
const route = {
|
|
364
|
+
file: 'app/api/link+api.ts',
|
|
365
|
+
page: '/api/link',
|
|
366
|
+
namedRegex: '^/api/link$',
|
|
367
|
+
routeKeys: {},
|
|
368
|
+
type: 'api',
|
|
369
|
+
middlewares: [{ contextKey: 'app/_middleware.ts' }],
|
|
370
|
+
} as RouteInfoCompiled
|
|
371
|
+
|
|
372
|
+
function dispatch(exports: Record<string, unknown>, method: string, middleware = true) {
|
|
373
|
+
const request = createRequest('/api/link', method)
|
|
374
|
+
return resolveAPIRoute(
|
|
375
|
+
{
|
|
376
|
+
handleAPI: async () => exports,
|
|
377
|
+
loadMiddleware: async () => ({
|
|
378
|
+
default: (async ({ request, next }) => {
|
|
379
|
+
if (request.method === 'OPTIONS') {
|
|
380
|
+
return new Response(null, { status: 204 })
|
|
381
|
+
}
|
|
382
|
+
const response = await next()
|
|
383
|
+
if (!response) throw new Error('expected endpoint response')
|
|
384
|
+
response.headers.set('x-middleware', 'ran')
|
|
385
|
+
return response
|
|
386
|
+
}) satisfies Middleware,
|
|
387
|
+
}),
|
|
388
|
+
},
|
|
389
|
+
request,
|
|
390
|
+
new URL(request.url),
|
|
391
|
+
middleware ? route : { ...route, middlewares: [] }
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
it.each([true, false])(
|
|
396
|
+
'rejects missing methods with middleware=%s',
|
|
397
|
+
async (middleware) => {
|
|
398
|
+
const POST = vi.fn(() => new Response('authentication required', { status: 401 }))
|
|
399
|
+
const exports = { POST, helper: () => {}, GET: undefined }
|
|
400
|
+
const response = await dispatch(exports, 'GET', middleware)
|
|
401
|
+
expect(response.status).toBe(405)
|
|
402
|
+
expect(response.headers.get('allow')).toBe('POST')
|
|
403
|
+
expect(POST).not.toHaveBeenCalled()
|
|
404
|
+
if (middleware) expect(response.headers.get('x-middleware')).toBe('ran')
|
|
405
|
+
const supported = await dispatch(exports, 'POST', middleware)
|
|
406
|
+
expect(supported.status).toBe(401)
|
|
407
|
+
expect(await supported.text()).toBe('authentication required')
|
|
408
|
+
expect(POST).toHaveBeenCalledOnce()
|
|
409
|
+
}
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
it('preserves middleware preflight short circuit', async () => {
|
|
413
|
+
const OPTIONS = vi.fn(() => new Response(null, { status: 202 }))
|
|
414
|
+
expect((await dispatch({ OPTIONS }, 'OPTIONS')).status).toBe(204)
|
|
415
|
+
expect(OPTIONS).not.toHaveBeenCalled()
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
it('preserves named methods ahead of default and default catch-all', async () => {
|
|
419
|
+
const fallback = vi.fn(
|
|
420
|
+
(request: Request) => new Response(request.method, { status: 202 })
|
|
421
|
+
)
|
|
422
|
+
const GET = vi.fn(() => new Response('named'))
|
|
423
|
+
expect(await (await dispatch({ GET, default: fallback }, 'GET')).text()).toBe('named')
|
|
424
|
+
for (const method of ['POST', 'HEAD', 'OPTIONS']) {
|
|
425
|
+
expect((await dispatch({ GET, default: fallback }, method, false)).status).toBe(202)
|
|
426
|
+
}
|
|
427
|
+
expect(GET).toHaveBeenCalledOnce()
|
|
428
|
+
expect(fallback).toHaveBeenCalledTimes(3)
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
it('requires explicit HEAD and OPTIONS exports and preserves their responses', async () => {
|
|
432
|
+
const GET = vi.fn(() => new Response('get'))
|
|
433
|
+
for (const method of ['HEAD', 'OPTIONS']) {
|
|
434
|
+
const missing = await dispatch({ GET }, method, false)
|
|
435
|
+
expect(missing.status).toBe(405)
|
|
436
|
+
expect(missing.headers.get('allow')).toBe('GET')
|
|
437
|
+
const explicit = await dispatch(
|
|
438
|
+
{
|
|
439
|
+
GET,
|
|
440
|
+
[method]: () =>
|
|
441
|
+
new Response(null, {
|
|
442
|
+
status: 204,
|
|
443
|
+
headers: { 'x-method': method },
|
|
444
|
+
}),
|
|
445
|
+
},
|
|
446
|
+
method,
|
|
447
|
+
false
|
|
448
|
+
)
|
|
449
|
+
expect(explicit.status).toBe(204)
|
|
450
|
+
expect(explicit.headers.get('x-method')).toBe(method)
|
|
451
|
+
expect(await explicit.text()).toBe('')
|
|
452
|
+
}
|
|
453
|
+
expect(GET).not.toHaveBeenCalled()
|
|
454
|
+
})
|
|
455
|
+
})
|
|
@@ -74,8 +74,23 @@ export function resolveAPIEndpoint(
|
|
|
74
74
|
const requestType = request.method || 'GET'
|
|
75
75
|
const handler = imported[requestType] || imported.default
|
|
76
76
|
if (!handler) {
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const allowedMethods = [
|
|
78
|
+
'GET',
|
|
79
|
+
'HEAD',
|
|
80
|
+
'POST',
|
|
81
|
+
'PUT',
|
|
82
|
+
'DELETE',
|
|
83
|
+
'CONNECT',
|
|
84
|
+
'OPTIONS',
|
|
85
|
+
'TRACE',
|
|
86
|
+
'PATCH',
|
|
87
|
+
]
|
|
88
|
+
.filter((method) => typeof imported[method] === 'function')
|
|
89
|
+
.join(', ')
|
|
90
|
+
return new Response(null, {
|
|
91
|
+
status: 405,
|
|
92
|
+
headers: { Allow: allowedMethods },
|
|
93
|
+
})
|
|
79
94
|
}
|
|
80
95
|
const worker =
|
|
81
96
|
env !== undefined || executionCtx !== undefined ? { env, executionCtx } : undefined
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveResponse.d.ts","sourceRoot":"","sources":["../../src/vite/resolveResponse.ts"],"names":[],"mappings":"AAeA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,gBAkCzE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOtE;AAED,wBAAgB,kBAAkB,CAEhC,WAAW,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,CAAC,EAAE,OAAO,EACb,YAAY,CAAC,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"resolveResponse.d.ts","sourceRoot":"","sources":["../../src/vite/resolveResponse.ts"],"names":[],"mappings":"AAeA,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,gBAkCzE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOtE;AAED,wBAAgB,kBAAkB,CAEhC,WAAW,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAC/B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,CAAC,EAAE,OAAO,EACb,YAAY,CAAC,EAAE,OAAO,gBA6BvB"}
|