@absolutejs/absolute 0.20.0-beta.46 → 0.20.0-beta.48
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/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/angular/index.js +36 -1
- package/dist/angular/index.js.map +3 -3
- package/dist/angular/server.js +36 -1
- package/dist/angular/server.js.map +3 -3
- package/dist/cli/config/server.js +36 -0
- package/dist/cli/index.js +354 -104
- package/dist/index.js +79 -5
- package/dist/index.js.map +4 -4
- package/dist/mobile/browser.js +38 -1
- package/dist/mobile/browser.js.map +3 -3
- package/dist/mobile/index.js +336 -43
- package/dist/mobile/index.js.map +6 -6
- package/dist/mobile/remoteMacAgentEntry.js +292 -144
- package/dist/mobile/shellExpoAuth.js +3 -3
- package/dist/mobile/shellExpoDevices.js +3 -3
- package/dist/react/index.js +36 -1
- package/dist/react/index.js.map +3 -3
- package/dist/react/server.js +36 -1
- package/dist/react/server.js.map +3 -3
- package/dist/src/mobile/index.d.ts +1 -0
- package/dist/src/mobile/nativeRoute.d.ts +13 -0
- package/dist/src/mobile/pageProtocol.d.ts +2 -0
- package/dist/svelte/index.js +36 -1
- package/dist/svelte/index.js.map +3 -3
- package/dist/svelte/server.js +36 -1
- package/dist/svelte/server.js.map +3 -3
- package/dist/types/build.d.ts +4 -1
- package/dist/vue/index.js +36 -1
- package/dist/vue/index.js.map +3 -3
- package/dist/vue/server.js +36 -1
- package/dist/vue/server.js.map +3 -3
- package/package.json +1 -1
package/dist/mobile/index.js
CHANGED
|
@@ -167,7 +167,7 @@ var init_startupBanner = __esm(() => {
|
|
|
167
167
|
|
|
168
168
|
// src/mobile/config.ts
|
|
169
169
|
import { resolve as resolve6 } from "path";
|
|
170
|
-
var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, HOSTNAME_PATTERN, resolveProjectPath = (projectRoot, value, field2) => {
|
|
170
|
+
var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FINGERPRINT_PATTERN, HOSTNAME_PATTERN, EXPO_RESERVED_ROUTE_PREFIXES, resolveProjectPath = (projectRoot, value, field2) => {
|
|
171
171
|
const root = resolve6(projectRoot);
|
|
172
172
|
const path = resolve6(root, value);
|
|
173
173
|
if (path !== root && !path.startsWith(`${root}/`)) {
|
|
@@ -240,11 +240,31 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
|
|
|
240
240
|
}
|
|
241
241
|
return value.match(/.{2}/g)?.join(":") ?? value;
|
|
242
242
|
}))
|
|
243
|
-
].sort(),
|
|
243
|
+
].sort(), validateExpoNativeRouteSegment = (path, segment, index, count, parameters) => {
|
|
244
|
+
if (segment === "*" && (index !== count - 1 || count === 1)) {
|
|
245
|
+
throw new TypeError(`mobile.routes.native route ${path} must use * once, as the final segment after a static or parameterized prefix.`);
|
|
246
|
+
}
|
|
247
|
+
if (segment === "*")
|
|
248
|
+
return;
|
|
249
|
+
if (!segment.startsWith(":") && (segment.includes("*") || segment.includes(":"))) {
|
|
250
|
+
throw new TypeError(`mobile.routes.native route ${path} contains invalid segment ${segment}.`);
|
|
251
|
+
}
|
|
252
|
+
if (!segment.startsWith(":"))
|
|
253
|
+
return;
|
|
254
|
+
const name = segment.slice(1);
|
|
255
|
+
if (!/^[A-Za-z][A-Za-z0-9_]*$/u.test(name)) {
|
|
256
|
+
throw new TypeError(`mobile.routes.native route ${path} has invalid parameter ${segment}.`);
|
|
257
|
+
}
|
|
258
|
+
if (parameters.has(name)) {
|
|
259
|
+
throw new TypeError(`mobile.routes.native route ${path} repeats parameter ${segment}.`);
|
|
260
|
+
}
|
|
261
|
+
parameters.add(name);
|
|
262
|
+
}, normalizeExpoNativeRoutes = (config, projectRoot) => {
|
|
244
263
|
if (config.engine !== "expo")
|
|
245
264
|
return {};
|
|
246
265
|
const routes = config.routes?.native ?? {};
|
|
247
266
|
const normalized = {};
|
|
267
|
+
const ownership = new Map;
|
|
248
268
|
for (const [route, module] of Object.entries(routes)) {
|
|
249
269
|
const path = normalizeEntry(route);
|
|
250
270
|
if (path.includes("?") || path.includes("#") || path !== "/" && path.endsWith("/")) {
|
|
@@ -253,9 +273,18 @@ var APP_ID_PATTERN, SCHEME_PATTERN, APPLE_APP_ID_PREFIX_PATTERN, CERTIFICATE_FIN
|
|
|
253
273
|
if (path === "/__absolute/native") {
|
|
254
274
|
throw new TypeError("mobile.routes.native reserves /__absolute/native for the Expo diagnostic screen.");
|
|
255
275
|
}
|
|
256
|
-
|
|
257
|
-
|
|
276
|
+
const segments = path.split("/").filter(Boolean);
|
|
277
|
+
if (segments[0] && EXPO_RESERVED_ROUTE_PREFIXES.has(segments[0])) {
|
|
278
|
+
throw new TypeError(`mobile.routes.native route ${path} conflicts with an Expo Router or Metro reserved path.`);
|
|
279
|
+
}
|
|
280
|
+
const parameters = new Set;
|
|
281
|
+
segments.forEach((segment, index) => validateExpoNativeRouteSegment(path, segment, index, segments.length, parameters));
|
|
282
|
+
const signature = segments.map((segment) => segment.startsWith(":") ? ":" : segment).join("/");
|
|
283
|
+
const existing = ownership.get(signature);
|
|
284
|
+
if (existing) {
|
|
285
|
+
throw new TypeError(`mobile.routes.native routes ${existing} and ${path} claim the same Expo route pattern.`);
|
|
258
286
|
}
|
|
287
|
+
ownership.set(signature, path);
|
|
259
288
|
normalized[path] = resolveProjectPath(projectRoot, requireText(module, `mobile.routes.native[${path}]`), `mobile.routes.native[${path}]`);
|
|
260
289
|
}
|
|
261
290
|
return Object.fromEntries(Object.entries(normalized).sort(([left], [right]) => left.localeCompare(right)));
|
|
@@ -294,6 +323,16 @@ var init_config = __esm(() => {
|
|
|
294
323
|
APPLE_APP_ID_PREFIX_PATTERN = /^[A-Z0-9]{10}$/;
|
|
295
324
|
CERTIFICATE_FINGERPRINT_PATTERN = /^[0-9A-F]{64}$/;
|
|
296
325
|
HOSTNAME_PATTERN = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$/;
|
|
326
|
+
EXPO_RESERVED_ROUTE_PREFIXES = new Set([
|
|
327
|
+
"_expo",
|
|
328
|
+
"_flight",
|
|
329
|
+
"_sitemap",
|
|
330
|
+
"assets",
|
|
331
|
+
"expo-dev-plugins",
|
|
332
|
+
"inspector",
|
|
333
|
+
"manifest",
|
|
334
|
+
"public"
|
|
335
|
+
]);
|
|
297
336
|
});
|
|
298
337
|
|
|
299
338
|
// src/utils/stringModifiers.ts
|
|
@@ -5192,6 +5231,7 @@ var getCurrentAbsoluteMobileProducerContext = () => {
|
|
|
5192
5231
|
// src/mobile/pageProtocol.ts
|
|
5193
5232
|
var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json";
|
|
5194
5233
|
var ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION = 1;
|
|
5234
|
+
var ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE = "application/vnd.absolute.native-route+json";
|
|
5195
5235
|
var BAD_REQUEST_STATUS = 400;
|
|
5196
5236
|
var OK_STATUS = 200;
|
|
5197
5237
|
var SERVER_ERROR_STATUS = 500;
|
|
@@ -5210,6 +5250,11 @@ var acceptsAbsoluteMobilePage = (request) => {
|
|
|
5210
5250
|
return false;
|
|
5211
5251
|
return (request.headers.get("accept") ?? "").split(",").some((value) => parseMediaType(value) === ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE);
|
|
5212
5252
|
};
|
|
5253
|
+
var acceptsAbsoluteNativeRouteData = (request) => {
|
|
5254
|
+
if (!request)
|
|
5255
|
+
return false;
|
|
5256
|
+
return (request.headers.get("accept") ?? "").split(",").some((value) => parseMediaType(value) === ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE);
|
|
5257
|
+
};
|
|
5213
5258
|
var readRequiredHeader = (request, name) => {
|
|
5214
5259
|
const value = request.headers.get(name)?.trim();
|
|
5215
5260
|
return value ? value : undefined;
|
|
@@ -5340,6 +5385,32 @@ var finalizeArchivedMobilePage = (context, input) => {
|
|
|
5340
5385
|
return createAbsoluteMobilePageErrorResponse(page.pageId);
|
|
5341
5386
|
}
|
|
5342
5387
|
};
|
|
5388
|
+
var finalizeAbsoluteNativeRouteDevelopmentPage = (input) => {
|
|
5389
|
+
if (false) {}
|
|
5390
|
+
if (input.request?.method !== "GET") {
|
|
5391
|
+
return createAbsoluteMobileInvalidRequestResponse("Native-route data requests must use GET.");
|
|
5392
|
+
}
|
|
5393
|
+
if (input.request.headers.get(MOBILE_PAGE_REQUEST_HEADERS.protocol) !== String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)) {
|
|
5394
|
+
return createAbsoluteMobileInvalidRequestResponse(`Native-route data requires protocol ${ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION}.`);
|
|
5395
|
+
}
|
|
5396
|
+
const [representation] = input.compatibility.representations;
|
|
5397
|
+
if (!representation) {
|
|
5398
|
+
return createAbsoluteMobilePageErrorResponse(input.compatibility.pageId);
|
|
5399
|
+
}
|
|
5400
|
+
try {
|
|
5401
|
+
return envelopeResponse({
|
|
5402
|
+
contract: representation.contract,
|
|
5403
|
+
framework: input.compatibility.framework,
|
|
5404
|
+
kind: "page",
|
|
5405
|
+
pageId: input.compatibility.pageId,
|
|
5406
|
+
props: normalizeJsonValue(representation.mapProps(input.props)),
|
|
5407
|
+
status: input.status ?? OK_STATUS
|
|
5408
|
+
}, input.status ?? OK_STATUS);
|
|
5409
|
+
} catch (error) {
|
|
5410
|
+
console.error(`[Mobile] Failed to produce development native route ${input.compatibility.pageId}:`, error);
|
|
5411
|
+
return createAbsoluteMobilePageErrorResponse(input.compatibility.pageId);
|
|
5412
|
+
}
|
|
5413
|
+
};
|
|
5343
5414
|
var createAbsoluteMobileInvalidRequestResponse = (message) => envelopeResponse({ kind: "invalid-request", message }, BAD_REQUEST_STATUS);
|
|
5344
5415
|
var createAbsoluteMobilePageErrorResponse = (pageId) => envelopeResponse({
|
|
5345
5416
|
code: "representation-failed",
|
|
@@ -5349,6 +5420,9 @@ var createAbsoluteMobilePageErrorResponse = (pageId) => envelopeResponse({
|
|
|
5349
5420
|
}, SERVER_ERROR_STATUS);
|
|
5350
5421
|
var createAbsoluteMobileUpgradeResponse = (result) => envelopeResponse(result, UPGRADE_REQUIRED_STATUS);
|
|
5351
5422
|
var finalizeAbsoluteMobilePage = (input) => {
|
|
5423
|
+
if (acceptsAbsoluteNativeRouteData(input.request)) {
|
|
5424
|
+
return finalizeAbsoluteNativeRouteDevelopmentPage(input);
|
|
5425
|
+
}
|
|
5352
5426
|
const parsed = parseAbsoluteMobilePageRequest(input.request);
|
|
5353
5427
|
if (parsed.kind === "not-mobile")
|
|
5354
5428
|
return;
|
|
@@ -6127,7 +6201,7 @@ import {
|
|
|
6127
6201
|
writeFile as writeFile12
|
|
6128
6202
|
} from "fs/promises";
|
|
6129
6203
|
import { createHash as createHash10 } from "crypto";
|
|
6130
|
-
import { basename as basename4, dirname as dirname10, join as join14, relative as relative10, resolve as resolve12 } from "path";
|
|
6204
|
+
import { basename as basename4, dirname as dirname10, join as join14, relative as relative10, resolve as resolve12, sep as sep6 } from "path";
|
|
6131
6205
|
var EXPO_GENERATED_HEADER = `// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.
|
|
6132
6206
|
`;
|
|
6133
6207
|
var EXPO_ASSET_EXTENSION = ".absasset";
|
|
@@ -6140,18 +6214,65 @@ var exists3 = async (path) => {
|
|
|
6140
6214
|
return false;
|
|
6141
6215
|
}
|
|
6142
6216
|
};
|
|
6217
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6218
|
+
var requireManifestString = (value, field2) => {
|
|
6219
|
+
if (typeof value !== "string" || !value) {
|
|
6220
|
+
throw new TypeError(`AbsoluteJS mobile manifest ${field2} is invalid.`);
|
|
6221
|
+
}
|
|
6222
|
+
return value;
|
|
6223
|
+
};
|
|
6224
|
+
var expoNativeDataManifest = (value) => {
|
|
6225
|
+
if (!isRecord8(value) || !Array.isArray(value.pages) || !Array.isArray(value.routes)) {
|
|
6226
|
+
throw new TypeError("AbsoluteJS mobile manifest is invalid.");
|
|
6227
|
+
}
|
|
6228
|
+
const pages = value.pages.map((page) => {
|
|
6229
|
+
if (!isRecord8(page))
|
|
6230
|
+
throw new TypeError("AbsoluteJS mobile manifest page is invalid.");
|
|
6231
|
+
return {
|
|
6232
|
+
bundleHash: requireManifestString(page.bundleHash, "page.bundleHash"),
|
|
6233
|
+
contract: requireManifestString(page.contract, "page.contract"),
|
|
6234
|
+
pageId: requireManifestString(page.pageId, "page.pageId")
|
|
6235
|
+
};
|
|
6236
|
+
});
|
|
6237
|
+
const routes = value.routes.flatMap((route) => {
|
|
6238
|
+
if (!isRecord8(route) || typeof route.method !== "string") {
|
|
6239
|
+
throw new TypeError("AbsoluteJS mobile manifest route is invalid.");
|
|
6240
|
+
}
|
|
6241
|
+
if (route.method !== "GET")
|
|
6242
|
+
return [];
|
|
6243
|
+
return [
|
|
6244
|
+
{
|
|
6245
|
+
method: "GET",
|
|
6246
|
+
pageId: requireManifestString(route.pageId, "route.pageId"),
|
|
6247
|
+
pattern: requireManifestString(route.pattern, "route.pattern")
|
|
6248
|
+
}
|
|
6249
|
+
];
|
|
6250
|
+
});
|
|
6251
|
+
return {
|
|
6252
|
+
appBuild: requireManifestString(value.appBuild, "appBuild"),
|
|
6253
|
+
pages,
|
|
6254
|
+
productionOrigin: requireManifestString(value.productionOrigin, "productionOrigin"),
|
|
6255
|
+
routes,
|
|
6256
|
+
runtime: requireManifestString(value.runtime, "runtime")
|
|
6257
|
+
};
|
|
6258
|
+
};
|
|
6143
6259
|
var portableRelative2 = (from, destination) => {
|
|
6144
6260
|
const value = relative10(from, destination).replaceAll("\\", "/");
|
|
6145
6261
|
return value.startsWith(".") ? value : `./${value}`;
|
|
6146
6262
|
};
|
|
6147
|
-
var routeSegments = (route) =>
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
|
|
6154
|
-
|
|
6263
|
+
var routeSegments = (route) => {
|
|
6264
|
+
const segments = route.split("/").filter(Boolean);
|
|
6265
|
+
return segments.map((segment, index) => {
|
|
6266
|
+
if (segment.startsWith(":"))
|
|
6267
|
+
return `[${segment.slice(1)}]`;
|
|
6268
|
+
if (segment === "*" && index === segments.length - 1)
|
|
6269
|
+
return "[...absoluteWildcard]";
|
|
6270
|
+
if (segment === "." || segment === ".." || !/^[A-Za-z0-9._~-]+$/u.test(segment)) {
|
|
6271
|
+
throw new TypeError(`Expo native route ${route} contains an unsupported segment ${segment}.`);
|
|
6272
|
+
}
|
|
6273
|
+
return segment;
|
|
6274
|
+
});
|
|
6275
|
+
};
|
|
6155
6276
|
var routeFile = (project, route) => join14(project, "app", ...routeSegments(route), "index.tsx");
|
|
6156
6277
|
var packageDependencies = (plan) => Object.fromEntries(plan.requiredPackages.map((spec) => {
|
|
6157
6278
|
const separator = spec.lastIndexOf("@");
|
|
@@ -6629,6 +6750,7 @@ var webHostSource = (config, auth, sync) => {
|
|
|
6629
6750
|
"/__absolute/native",
|
|
6630
6751
|
...Object.keys(config.expoNativeRoutes)
|
|
6631
6752
|
];
|
|
6753
|
+
const nativeRoutePatterns = nativeRoutes.map((route) => route.split("/").filter(Boolean));
|
|
6632
6754
|
return `${EXPO_GENERATED_HEADER}import * as Linking from 'expo-linking';
|
|
6633
6755
|
import { router, usePathname } from 'expo-router';
|
|
6634
6756
|
import { useEffect, useRef, useState } from 'react';
|
|
@@ -6643,7 +6765,7 @@ ${sync ? "import { createAbsoluteExpoSyncBridge, startAbsoluteExpoSync } from '.
|
|
|
6643
6765
|
const BRIDGE_FORMAT = 3;
|
|
6644
6766
|
const MAX_MESSAGE_BYTES = 64 * 1024;
|
|
6645
6767
|
const MAX_HTTP_BODY_BYTES = 48 * 1024;
|
|
6646
|
-
const
|
|
6768
|
+
const NATIVE_ROUTE_PATTERNS = ${JSON.stringify(nativeRoutePatterns)};
|
|
6647
6769
|
const PRODUCTION_ORIGIN = ${JSON.stringify(config.productionOrigin)};
|
|
6648
6770
|
const DEV_ORIGIN = Platform.OS === 'android'
|
|
6649
6771
|
? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
|
|
@@ -6652,6 +6774,19 @@ const HMR_TARGET = Platform.OS === 'android' ? 'expo-android' : 'expo-ios';
|
|
|
6652
6774
|
const AUTH_ENABLED = ${auth ? "true" : "false"};
|
|
6653
6775
|
const SYNC_ENABLED = ${sync ? "true" : "false"};
|
|
6654
6776
|
|
|
6777
|
+
const isNativeRoute = (pathname: string) => {
|
|
6778
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
6779
|
+
return NATIVE_ROUTE_PATTERNS.some(pattern => {
|
|
6780
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
6781
|
+
const expected = pattern[index]!;
|
|
6782
|
+
if (expected === '*') return segments.length > index;
|
|
6783
|
+
if (segments[index] === undefined) return false;
|
|
6784
|
+
if (!expected.startsWith(':') && expected !== segments[index]) return false;
|
|
6785
|
+
}
|
|
6786
|
+
return segments.length === pattern.length;
|
|
6787
|
+
});
|
|
6788
|
+
};
|
|
6789
|
+
|
|
6655
6790
|
const bridgeBootstrap = (path: string) => {
|
|
6656
6791
|
const initialPath = DEV_ORIGIN
|
|
6657
6792
|
? 'location.pathname + location.search + location.hash'
|
|
@@ -6727,7 +6862,7 @@ const bridgeBootstrap = (path: string) => {
|
|
|
6727
6862
|
const anchor = event.target instanceof Element ? event.target.closest('a[href]') : null;
|
|
6728
6863
|
if (!anchor) return;
|
|
6729
6864
|
const url = new URL(anchor.href, location.href);
|
|
6730
|
-
if (
|
|
6865
|
+
if (!isNativeRoute(url.pathname)) return;
|
|
6731
6866
|
event.preventDefault();
|
|
6732
6867
|
send({ format: 3, kind: 'event', event: 'navigation', path: url.pathname + url.search + url.hash });
|
|
6733
6868
|
}, true);
|
|
@@ -6850,7 +6985,7 @@ export function AbsoluteWebHost() {
|
|
|
6850
6985
|
if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
|
|
6851
6986
|
const target = new URL(message.path, PRODUCTION_ORIGIN);
|
|
6852
6987
|
if (target.origin !== PRODUCTION_ORIGIN) return;
|
|
6853
|
-
if (
|
|
6988
|
+
if (isNativeRoute(target.pathname)) router.push(message.path as never);
|
|
6854
6989
|
else activeWebPath.current = message.path;
|
|
6855
6990
|
return;
|
|
6856
6991
|
}
|
|
@@ -6915,7 +7050,134 @@ var catchAllRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } fr
|
|
|
6915
7050
|
|
|
6916
7051
|
export default AbsoluteWebHost;
|
|
6917
7052
|
`;
|
|
6918
|
-
var
|
|
7053
|
+
var nativeRouteRuntimeSource = (auth) => `${EXPO_GENERATED_HEADER}import { useLocalSearchParams, usePathname } from 'expo-router';
|
|
7054
|
+
import { type ComponentType, useEffect, useMemo, useState } from 'react';
|
|
7055
|
+
import { ActivityIndicator, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
7056
|
+
import { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';
|
|
7057
|
+
${auth ? "import { absoluteExpoAuth } from './AbsoluteAuth';" : ""}
|
|
7058
|
+
|
|
7059
|
+
const PAGE_MEDIA_TYPE = 'application/vnd.absolute.page+json';
|
|
7060
|
+
const NATIVE_DATA_MEDIA_TYPE = 'application/vnd.absolute.native-route+json';
|
|
7061
|
+
const PROTOCOL = 1;
|
|
7062
|
+
const MAX_DATA_BYTES = 1024 * 1024;
|
|
7063
|
+
const DEV_ORIGIN = Platform.OS === 'android'
|
|
7064
|
+
? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
|
|
7065
|
+
: process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
|
|
7066
|
+
|
|
7067
|
+
type RouteParams = Record<string, string | string[] | undefined>;
|
|
7068
|
+
type NativeRouteProps<PageProps extends object, Params extends object> = {
|
|
7069
|
+
pageProps: Readonly<PageProps>;
|
|
7070
|
+
params: Readonly<Params>;
|
|
7071
|
+
reload: () => void;
|
|
7072
|
+
};
|
|
7073
|
+
type NativeRouteState<PageProps> =
|
|
7074
|
+
| { kind: 'loading' }
|
|
7075
|
+
| { kind: 'ready'; pageProps: PageProps }
|
|
7076
|
+
| { kind: 'error' };
|
|
7077
|
+
|
|
7078
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
7079
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7080
|
+
const routeSegmentPattern = (segment: string) => {
|
|
7081
|
+
if (segment === '*') return '.*';
|
|
7082
|
+
if (segment.startsWith(':') && segment.endsWith('?')) return '[^/]*';
|
|
7083
|
+
if (segment.startsWith(':')) return '[^/]+';
|
|
7084
|
+
return segment.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
|
|
7085
|
+
};
|
|
7086
|
+
const matchesRoute = (pattern: string, pathname: string) =>
|
|
7087
|
+
new RegExp('^' + pattern.split('/').map(routeSegmentPattern).join('/') + '/?$').test(pathname);
|
|
7088
|
+
const requestPathFor = (pathname: string, params: RouteParams, pattern: string) => {
|
|
7089
|
+
const pathNames = new Set(pattern.split('/').filter(segment => segment.startsWith(':')).map(segment => segment.replace(/^:/, '').replace(/\\?$/, '')));
|
|
7090
|
+
if (pattern.endsWith('/*')) pathNames.add('absoluteWildcard');
|
|
7091
|
+
const query = new URLSearchParams();
|
|
7092
|
+
for (const [name, value] of Object.entries(params).sort(([left], [right]) => left.localeCompare(right))) {
|
|
7093
|
+
if (pathNames.has(name) || name === '#' || value === undefined) continue;
|
|
7094
|
+
for (const item of Array.isArray(value) ? value : [value]) query.append(name, item);
|
|
7095
|
+
}
|
|
7096
|
+
const search = query.toString();
|
|
7097
|
+
return pathname + (search ? '?' + search : '');
|
|
7098
|
+
};
|
|
7099
|
+
const productionPage = (pathname: string) => {
|
|
7100
|
+
if (!ABSOLUTE_MOBILE_MANIFEST) throw new Error('AbsoluteJS native route data is not prepared for production.');
|
|
7101
|
+
const route = ABSOLUTE_MOBILE_MANIFEST.routes.find(candidate => candidate.method === 'GET' && matchesRoute(candidate.pattern, pathname));
|
|
7102
|
+
if (!route) throw new Error('No trusted AbsoluteJS page route owns this native URL.');
|
|
7103
|
+
const page = ABSOLUTE_MOBILE_MANIFEST.pages.find(candidate => candidate.pageId === route.pageId);
|
|
7104
|
+
if (!page) throw new Error('The embedded AbsoluteJS page contract is incomplete.');
|
|
7105
|
+
return page;
|
|
7106
|
+
};
|
|
7107
|
+
const createDataRequest = (path: string) => {
|
|
7108
|
+
const development = typeof DEV_ORIGIN === 'string' && DEV_ORIGIN.length > 0;
|
|
7109
|
+
const origin = development ? DEV_ORIGIN : ABSOLUTE_MOBILE_MANIFEST?.productionOrigin;
|
|
7110
|
+
if (!origin) throw new Error('AbsoluteJS native route data has no trusted server origin.');
|
|
7111
|
+
const url = new URL(path, origin);
|
|
7112
|
+
if (url.origin !== new URL(origin).origin) throw new Error('AbsoluteJS native route data left its trusted origin.');
|
|
7113
|
+
const headers = new Headers();
|
|
7114
|
+
headers.set('accept', development ? NATIVE_DATA_MEDIA_TYPE : PAGE_MEDIA_TYPE);
|
|
7115
|
+
headers.set('x-absolute-mobile-protocol', String(PROTOCOL));
|
|
7116
|
+
let page: ReturnType<typeof productionPage> | undefined;
|
|
7117
|
+
if (!development) {
|
|
7118
|
+
page = productionPage(url.pathname);
|
|
7119
|
+
headers.set('x-absolute-mobile-app-build', ABSOLUTE_MOBILE_MANIFEST!.appBuild);
|
|
7120
|
+
headers.set('x-absolute-mobile-page-bundle', page.bundleHash);
|
|
7121
|
+
headers.set('x-absolute-mobile-page-contracts', page.contract);
|
|
7122
|
+
headers.set('x-absolute-mobile-page-id', page.pageId);
|
|
7123
|
+
headers.set('x-absolute-mobile-runtime', ABSOLUTE_MOBILE_MANIFEST!.runtime);
|
|
7124
|
+
}
|
|
7125
|
+
return { page, request: new Request(url, { headers, method: 'GET' }) };
|
|
7126
|
+
};
|
|
7127
|
+
const requestData = async <PageProps extends object>(path: string, signal: AbortSignal) => {
|
|
7128
|
+
const { page, request } = createDataRequest(path);
|
|
7129
|
+
const response = await ${auth ? "absoluteExpoAuth.fetchOptional" : "fetch"}(request, { redirect: 'manual', signal });
|
|
7130
|
+
if (new URL(response.url || request.url).origin !== new URL(request.url).origin || response.status >= 300 && response.status < 400) throw new Error('AbsoluteJS native route data redirected outside its contract.');
|
|
7131
|
+
const source = await response.text();
|
|
7132
|
+
if (new TextEncoder().encode(source).byteLength > MAX_DATA_BYTES) throw new Error('AbsoluteJS native route data exceeded 1 MiB.');
|
|
7133
|
+
let envelope: unknown;
|
|
7134
|
+
try { envelope = JSON.parse(source); } catch { throw new Error('The server did not return an AbsoluteJS page envelope.'); }
|
|
7135
|
+
if (!isRecord(envelope) || envelope.protocol !== PROTOCOL || !isRecord(envelope.response)) throw new Error('The server returned an invalid AbsoluteJS page envelope.');
|
|
7136
|
+
const result = envelope.response;
|
|
7137
|
+
if (result.kind === 'upgrade-required') throw new Error('This app version must be updated before opening this screen.');
|
|
7138
|
+
if (result.kind !== 'page' || !isRecord(result.props) || typeof result.pageId !== 'string' || typeof result.contract !== 'string') throw new Error('The server did not produce native route page props.');
|
|
7139
|
+
if (page && (result.pageId !== page.pageId || result.contract !== page.contract)) throw new Error('The server returned a different page contract than this app contains.');
|
|
7140
|
+
return result.props as PageProps;
|
|
7141
|
+
};
|
|
7142
|
+
|
|
7143
|
+
export const createAbsoluteNativeRoute = <
|
|
7144
|
+
PageProps extends object,
|
|
7145
|
+
Params extends object = RouteParams
|
|
7146
|
+
>(Component: ComponentType<NativeRouteProps<PageProps, Params>>, pattern: string) => {
|
|
7147
|
+
function AbsoluteNativeRouteScreen() {
|
|
7148
|
+
const pathname = usePathname() || '/';
|
|
7149
|
+
const params = useLocalSearchParams() as RouteParams;
|
|
7150
|
+
const parameterKey = JSON.stringify(params);
|
|
7151
|
+
const requestPath = useMemo(() => requestPathFor(pathname, params, pattern), [parameterKey, pathname]);
|
|
7152
|
+
const [revision, setRevision] = useState(0);
|
|
7153
|
+
const [state, setState] = useState<NativeRouteState<PageProps>>({ kind: 'loading' });
|
|
7154
|
+
useEffect(() => {
|
|
7155
|
+
const controller = new AbortController();
|
|
7156
|
+
setState({ kind: 'loading' });
|
|
7157
|
+
void requestData<PageProps>(requestPath, controller.signal).then(
|
|
7158
|
+
pageProps => { if (!controller.signal.aborted) setState({ kind: 'ready', pageProps }); },
|
|
7159
|
+
() => { if (!controller.signal.aborted) setState({ kind: 'error' }); }
|
|
7160
|
+
);
|
|
7161
|
+
return () => controller.abort();
|
|
7162
|
+
}, [requestPath, revision]);
|
|
7163
|
+
const reload = () => setRevision(value => value + 1);
|
|
7164
|
+
if (state.kind === 'loading') return <View style={styles.center}><ActivityIndicator accessibilityLabel="Loading screen" /></View>;
|
|
7165
|
+
if (state.kind === 'error') return <View style={styles.center}><Text accessibilityRole="alert" style={styles.error}>This screen could not load.</Text><Pressable accessibilityRole="button" onPress={reload} style={styles.button}><Text>Try again</Text></Pressable></View>;
|
|
7166
|
+
return <Component pageProps={state.pageProps} params={params as Params} reload={reload} />;
|
|
7167
|
+
}
|
|
7168
|
+
return AbsoluteNativeRouteScreen;
|
|
7169
|
+
};
|
|
7170
|
+
|
|
7171
|
+
const styles = StyleSheet.create({
|
|
7172
|
+
button: { backgroundColor: '#e2e8f0', borderRadius: 10, paddingHorizontal: 16, paddingVertical: 12 },
|
|
7173
|
+
center: { alignItems: 'center', flex: 1, gap: 16, justifyContent: 'center', padding: 24 },
|
|
7174
|
+
error: { color: '#b91c1c', fontSize: 16, textAlign: 'center' }
|
|
7175
|
+
});
|
|
7176
|
+
`;
|
|
7177
|
+
var nativeWrapperSource = (wrapper, module, runtime, route) => `${EXPO_GENERATED_HEADER}import ApplicationNativeRoute from ${JSON.stringify(portableRelative2(dirname10(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
7178
|
+
import { createAbsoluteNativeRoute } from ${JSON.stringify(portableRelative2(dirname10(wrapper), runtime).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
7179
|
+
|
|
7180
|
+
export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringify(route)});
|
|
6919
7181
|
`;
|
|
6920
7182
|
var expoTsConfig = (projectRoot, project, auth, sync) => ({
|
|
6921
7183
|
compilerOptions: {
|
|
@@ -6968,11 +7230,33 @@ var writeManagedFile = async (path, source, force) => {
|
|
|
6968
7230
|
await rename11(temporary, path);
|
|
6969
7231
|
return true;
|
|
6970
7232
|
};
|
|
7233
|
+
var pruneStaleManagedExpoRoutes = async (project, expected) => {
|
|
7234
|
+
const appDirectory = join14(project, "app");
|
|
7235
|
+
if (!await exists3(appDirectory))
|
|
7236
|
+
return 0;
|
|
7237
|
+
const files = await walkFiles(appDirectory);
|
|
7238
|
+
const stale = (await Promise.all(files.map(async (path) => ({
|
|
7239
|
+
managed: path.endsWith(".tsx") && (await readFile14(path, "utf8")).startsWith(EXPO_GENERATED_HEADER),
|
|
7240
|
+
path
|
|
7241
|
+
})))).filter(({ managed, path }) => managed && !expected.has(path));
|
|
7242
|
+
await Promise.all(stale.map(({ path }) => rm9(path, { force: true })));
|
|
7243
|
+
return stale.length;
|
|
7244
|
+
};
|
|
6971
7245
|
var jsonSource = (value) => `${JSON.stringify(value, null, "\t")}
|
|
6972
7246
|
`;
|
|
6973
|
-
var
|
|
7247
|
+
var nativeDataManifestTypeSource = `type AbsoluteMobileManifest = {
|
|
7248
|
+
appBuild: string;
|
|
7249
|
+
pages: readonly { bundleHash: string; contract: string; pageId: string }[];
|
|
7250
|
+
productionOrigin: string;
|
|
7251
|
+
routes: readonly { method: 'GET'; pageId: string; pattern: string }[];
|
|
7252
|
+
runtime: string;
|
|
7253
|
+
};
|
|
7254
|
+
`;
|
|
7255
|
+
var emptyWebAssetsSource = `${EXPO_GENERATED_HEADER}${nativeDataManifestTypeSource}
|
|
7256
|
+
export const materializeAbsoluteWebBundle = async () => {
|
|
6974
7257
|
throw new Error('The embedded AbsoluteJS bundle is unavailable. Run absolute prepare before a production Expo build.');
|
|
6975
7258
|
};
|
|
7259
|
+
export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest | undefined = undefined;
|
|
6976
7260
|
`;
|
|
6977
7261
|
var writeAbsoluteExpoProject = async (config, options) => {
|
|
6978
7262
|
if (config.engine !== "expo")
|
|
@@ -7043,6 +7327,10 @@ node_modules/
|
|
|
7043
7327
|
join14(project, "src", "generated", "AbsoluteDevices.ts"),
|
|
7044
7328
|
devicesRuntimeSource(config, devices, authEnabled)
|
|
7045
7329
|
],
|
|
7330
|
+
[
|
|
7331
|
+
join14(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
|
|
7332
|
+
nativeRouteRuntimeSource(authEnabled)
|
|
7333
|
+
],
|
|
7046
7334
|
[
|
|
7047
7335
|
join14(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
7048
7336
|
webHostSource(config, auth, syncEnabled)
|
|
@@ -7062,12 +7350,14 @@ node_modules/
|
|
|
7062
7350
|
files.set(join14(project, "app", "index.tsx"), webRouteSource);
|
|
7063
7351
|
}
|
|
7064
7352
|
files.set(join14(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
7353
|
+
const nativeRouteRuntime = join14(project, "src", "generated", "AbsoluteNativeRoute.tsx");
|
|
7065
7354
|
for (const [route, module] of routeModules) {
|
|
7066
7355
|
const wrapper = route === "/" ? join14(project, "app", "index.tsx") : routeFile(project, route);
|
|
7067
|
-
files.set(wrapper, nativeWrapperSource(wrapper, module));
|
|
7356
|
+
files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
|
|
7068
7357
|
}
|
|
7358
|
+
const removed = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join14(project, "app")}${sep6}`))));
|
|
7069
7359
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
7070
|
-
const changed = changes.filter(Boolean).length;
|
|
7360
|
+
const changed = removed + changes.filter(Boolean).length;
|
|
7071
7361
|
return { changed, path: project, written: [...files.keys()] };
|
|
7072
7362
|
};
|
|
7073
7363
|
var walkFiles = async (root, directory = root) => {
|
|
@@ -7106,11 +7396,13 @@ var installStagedDirectory = async (staging, destination) => {
|
|
|
7106
7396
|
throw error;
|
|
7107
7397
|
}
|
|
7108
7398
|
};
|
|
7109
|
-
var assetModuleSource = (assets, bundleId) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
7399
|
+
var assetModuleSource = (assets, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
7110
7400
|
import { Directory, File, Paths } from 'expo-file-system';
|
|
7111
7401
|
|
|
7402
|
+
${nativeDataManifestTypeSource}
|
|
7112
7403
|
declare const require: (path: string) => number;
|
|
7113
7404
|
const BUNDLE_ID = ${JSON.stringify(bundleId)};
|
|
7405
|
+
export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest = ${JSON.stringify(manifest)};
|
|
7114
7406
|
const ASSETS = [
|
|
7115
7407
|
${assets.map(({ asset, path }) => ` { module: require(${JSON.stringify(asset)}), path: ${JSON.stringify(path)} }`).join(`,
|
|
7116
7408
|
`)}
|
|
@@ -7144,9 +7436,8 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
7144
7436
|
}
|
|
7145
7437
|
const manifestPath = join14(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
7146
7438
|
const manifest = JSON.parse(await readFile14(manifestPath, "utf8"));
|
|
7147
|
-
const
|
|
7148
|
-
|
|
7149
|
-
throw new TypeError("AbsoluteJS mobile manifest has no appBuild.");
|
|
7439
|
+
const nativeDataManifest = expoNativeDataManifest(manifest);
|
|
7440
|
+
const { appBuild } = nativeDataManifest;
|
|
7150
7441
|
const files = await walkFiles(config.bundleDirectory);
|
|
7151
7442
|
const bundleHash = createHash10("sha256");
|
|
7152
7443
|
const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile14(file), file })));
|
|
@@ -7176,7 +7467,7 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
7176
7467
|
throw error;
|
|
7177
7468
|
}
|
|
7178
7469
|
const generated = join14(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
7179
|
-
await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
|
|
7470
|
+
await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
|
|
7180
7471
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
7181
7472
|
};
|
|
7182
7473
|
|
|
@@ -7493,7 +7784,7 @@ var ABSOLUTE_EXPO_BRIDGE_METHODS = [
|
|
|
7493
7784
|
"sync.socket.open",
|
|
7494
7785
|
"sync.socket.sendChunk"
|
|
7495
7786
|
];
|
|
7496
|
-
var
|
|
7787
|
+
var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
7497
7788
|
var validId = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,80}$/u.test(value);
|
|
7498
7789
|
var validPath = (value) => typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && value.length <= 4096;
|
|
7499
7790
|
var parseRequest = (value) => {
|
|
@@ -7503,7 +7794,7 @@ var parseRequest = (value) => {
|
|
|
7503
7794
|
if (!method) {
|
|
7504
7795
|
throw new TypeError("Expo bridge method is not allowed.");
|
|
7505
7796
|
}
|
|
7506
|
-
if (!
|
|
7797
|
+
if (!isRecord9(value.params))
|
|
7507
7798
|
throw new TypeError("Expo bridge request params must be an object.");
|
|
7508
7799
|
if (typeof value.path !== "string" || !validPath(value.path))
|
|
7509
7800
|
throw new TypeError("Expo bridge request path is invalid.");
|
|
@@ -7539,7 +7830,7 @@ var parseRequest = (value) => {
|
|
|
7539
7830
|
throw new TypeError("Expo bridge HTTP body exceeds 48 KiB.");
|
|
7540
7831
|
if ((value.params.method === "GET" || value.params.method === "DELETE") && value.params.body !== undefined)
|
|
7541
7832
|
throw new TypeError("Expo bridge HTTP method cannot contain a body.");
|
|
7542
|
-
if (!
|
|
7833
|
+
if (!isRecord9(value.params.headers))
|
|
7543
7834
|
throw new TypeError("Expo bridge HTTP headers must be an object.");
|
|
7544
7835
|
const headersAllowed = Object.entries(value.params.headers).every(([name, header]) => typeof header === "string" && (name.toLowerCase() === "accept" || name.toLowerCase() === "content-type" || name.toLowerCase().startsWith("x-absolute-mobile-")));
|
|
7545
7836
|
if (!headersAllowed) {
|
|
@@ -7565,13 +7856,13 @@ var parseResponse = (value) => {
|
|
|
7565
7856
|
if (typeof value.id !== "string" || !validId(value.id))
|
|
7566
7857
|
throw new TypeError("Expo bridge response id is invalid.");
|
|
7567
7858
|
if (value.error !== undefined) {
|
|
7568
|
-
if (!
|
|
7859
|
+
if (!isRecord9(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string") {
|
|
7569
7860
|
throw new TypeError("Expo bridge response error is invalid.");
|
|
7570
7861
|
}
|
|
7571
7862
|
if (value.result !== undefined)
|
|
7572
7863
|
throw new TypeError("Expo bridge response cannot contain result and error.");
|
|
7573
7864
|
}
|
|
7574
|
-
if (
|
|
7865
|
+
if (isRecord9(value.error)) {
|
|
7575
7866
|
return {
|
|
7576
7867
|
error: {
|
|
7577
7868
|
code: String(value.error.code),
|
|
@@ -7595,7 +7886,7 @@ var parseEvent = (value) => {
|
|
|
7595
7886
|
}
|
|
7596
7887
|
if (typeof value.path !== "string" || !validPath(value.path))
|
|
7597
7888
|
throw new TypeError("Expo bridge event path is invalid.");
|
|
7598
|
-
if (value.payload !== undefined && !
|
|
7889
|
+
if (value.payload !== undefined && !isRecord9(value.payload)) {
|
|
7599
7890
|
throw new TypeError("Expo bridge event payload must be an object.");
|
|
7600
7891
|
}
|
|
7601
7892
|
return {
|
|
@@ -7629,7 +7920,7 @@ var parseAbsoluteExpoBridgeMessage = (source) => {
|
|
|
7629
7920
|
cause
|
|
7630
7921
|
});
|
|
7631
7922
|
}
|
|
7632
|
-
if (!
|
|
7923
|
+
if (!isRecord9(parsed) || parsed.format !== ABSOLUTE_EXPO_BRIDGE_FORMAT) {
|
|
7633
7924
|
throw new TypeError("Expo bridge message format is unsupported.");
|
|
7634
7925
|
}
|
|
7635
7926
|
if (parsed.kind === "request")
|
|
@@ -7987,7 +8278,7 @@ init_config();
|
|
|
7987
8278
|
// src/mobile/ciWorkflow.ts
|
|
7988
8279
|
import { existsSync as existsSync4 } from "fs";
|
|
7989
8280
|
import { access as access11, mkdir as mkdir12, readFile as readFile16, writeFile as writeFile13 } from "fs/promises";
|
|
7990
|
-
import { dirname as dirname11, extname as extname4, relative as relative11, resolve as resolve14, sep as
|
|
8281
|
+
import { dirname as dirname11, extname as extname4, relative as relative11, resolve as resolve14, sep as sep7 } from "path";
|
|
7991
8282
|
var ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT = 1;
|
|
7992
8283
|
var SECRET_NAME_PATTERN = /^[A-Z][A-Z0-9_]*$/u;
|
|
7993
8284
|
var CI_ENV_INDENTATION = 6;
|
|
@@ -8019,7 +8310,7 @@ var projectPath = (projectRoot, value, field2, options = {}) => {
|
|
|
8019
8310
|
const root = resolve14(projectRoot);
|
|
8020
8311
|
const path = resolve14(root, value);
|
|
8021
8312
|
const portable = relative11(root, path).replaceAll("\\", "/");
|
|
8022
|
-
if (portable === ".." || portable.startsWith(`..${
|
|
8313
|
+
if (portable === ".." || portable.startsWith(`..${sep7}`) || portable.startsWith("../") || portable === "") {
|
|
8023
8314
|
throw new TypeError(`${field2} must remain inside the project root.`);
|
|
8024
8315
|
}
|
|
8025
8316
|
if (/\r|\n/u.test(portable) || portable.startsWith("-"))
|
|
@@ -8033,7 +8324,7 @@ var workflowOutputPath = (projectRoot, value) => {
|
|
|
8033
8324
|
const workflows = resolve14(root, ".github/workflows");
|
|
8034
8325
|
const path = resolve14(root, value ?? ".github/workflows/absolute-mobile.yml");
|
|
8035
8326
|
const portable = relative11(workflows, path);
|
|
8036
|
-
if (portable === ".." || portable.startsWith(`..${
|
|
8327
|
+
if (portable === ".." || portable.startsWith(`..${sep7}`) || extname4(path) !== ".yml" && extname4(path) !== ".yaml") {
|
|
8037
8328
|
throw new TypeError("mobile ci github --output must be a .yml or .yaml file inside .github/workflows.");
|
|
8038
8329
|
}
|
|
8039
8330
|
return path;
|
|
@@ -8627,7 +8918,7 @@ init_telemetryEvent();
|
|
|
8627
8918
|
import { Elysia as Elysia3 } from "elysia";
|
|
8628
8919
|
var ABSOLUTE_MOBILE_PREVIEW_PATH = "/__absolute/mobile-preview";
|
|
8629
8920
|
var escapeHtml2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
8630
|
-
var
|
|
8921
|
+
var isRecord10 = (value) => typeof value === "object" && value !== null;
|
|
8631
8922
|
var normalizeEntry2 = (entry) => {
|
|
8632
8923
|
const parsed = new URL(entry ?? "/", "https://absolute.invalid");
|
|
8633
8924
|
return `${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
@@ -8678,7 +8969,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
|
|
|
8678
8969
|
"X-Robots-Tag": "noindex, nofollow"
|
|
8679
8970
|
}
|
|
8680
8971
|
})).post("/__absolute/mobile-preview-telemetry", ({ body, status }) => {
|
|
8681
|
-
const value =
|
|
8972
|
+
const value = isRecord10(body) ? body : undefined;
|
|
8682
8973
|
const durationMs = value?.durationMs;
|
|
8683
8974
|
const platform2 = value?.platform;
|
|
8684
8975
|
if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < 0 || durationMs > 300000 || platform2 !== "android" && platform2 !== "ios") {
|
|
@@ -9212,7 +9503,7 @@ init_nativeAuth();
|
|
|
9212
9503
|
|
|
9213
9504
|
// src/mobile/releasePublisher.ts
|
|
9214
9505
|
import { access as access12 } from "fs/promises";
|
|
9215
|
-
import { isAbsolute as isAbsolute6, relative as relative12, resolve as resolve15, sep as
|
|
9506
|
+
import { isAbsolute as isAbsolute6, relative as relative12, resolve as resolve15, sep as sep8 } from "path";
|
|
9216
9507
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
9217
9508
|
var prepareAbsoluteIosRelease = async (publisher, options) => {
|
|
9218
9509
|
if (typeof publisher.prepareIosRelease !== "function") {
|
|
@@ -9235,13 +9526,13 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
|
9235
9526
|
}
|
|
9236
9527
|
return versionCode;
|
|
9237
9528
|
};
|
|
9238
|
-
var
|
|
9239
|
-
var isPublisher = (value) =>
|
|
9529
|
+
var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9530
|
+
var isPublisher = (value) => isRecord11(value) && typeof value.publish === "function";
|
|
9240
9531
|
var publisherModulePath = (projectRoot, requested) => {
|
|
9241
9532
|
const root = resolve15(projectRoot);
|
|
9242
9533
|
const path = resolve15(root, requested);
|
|
9243
9534
|
const projectRelative = relative12(root, path);
|
|
9244
|
-
if (projectRelative === ".." || projectRelative.startsWith(`..${
|
|
9535
|
+
if (projectRelative === ".." || projectRelative.startsWith(`..${sep8}`) || isAbsolute6(projectRelative)) {
|
|
9245
9536
|
throw new TypeError("mobile publish --registry must remain inside the project.");
|
|
9246
9537
|
}
|
|
9247
9538
|
return path;
|
|
@@ -9252,7 +9543,7 @@ var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath
|
|
|
9252
9543
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
9253
9544
|
});
|
|
9254
9545
|
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
9255
|
-
const publisher =
|
|
9546
|
+
const publisher = isRecord11(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
9256
9547
|
if (!isPublisher(publisher)) {
|
|
9257
9548
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
9258
9549
|
}
|
|
@@ -10068,6 +10359,7 @@ export {
|
|
|
10068
10359
|
ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL,
|
|
10069
10360
|
ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV,
|
|
10070
10361
|
ABSOLUTE_NATIVE_AUTH_SCOPES,
|
|
10362
|
+
ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE,
|
|
10071
10363
|
ABSOLUTE_REMOTE_MAC_EVENT_PREFIX,
|
|
10072
10364
|
ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION,
|
|
10073
10365
|
ABSOLUTE_SYNC_PACKAGE,
|
|
@@ -10082,6 +10374,7 @@ export {
|
|
|
10082
10374
|
absoluteRemoteMacSshBase,
|
|
10083
10375
|
absoluteRemoteProjectSyncCommands,
|
|
10084
10376
|
acceptsAbsoluteMobilePage,
|
|
10377
|
+
acceptsAbsoluteNativeRouteData,
|
|
10085
10378
|
activateAbsoluteMobilePage,
|
|
10086
10379
|
applyAbsoluteNativeDeepLinks,
|
|
10087
10380
|
applyAbsoluteNativeDeviceCapabilities,
|
|
@@ -10201,5 +10494,5 @@ export {
|
|
|
10201
10494
|
writeAbsoluteMobileGithubWorkflow
|
|
10202
10495
|
};
|
|
10203
10496
|
|
|
10204
|
-
//# debugId=
|
|
10497
|
+
//# debugId=4795A6FB7632A5BE64756E2164756E21
|
|
10205
10498
|
//# sourceMappingURL=index.js.map
|