@absolutejs/absolute 0.20.0-beta.47 → 0.20.0-beta.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- 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 +442 -112
- package/dist/index.js +36 -1
- package/dist/index.js.map +3 -3
- package/dist/mobile/browser.js +38 -1
- package/dist/mobile/browser.js.map +3 -3
- package/dist/mobile/index.js +268 -25
- package/dist/mobile/index.js.map +7 -7
- package/dist/mobile/remoteMacAgentEntry.js +232 -97
- 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/androidRelease.d.ts +3 -2
- 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/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
|
@@ -1653,6 +1653,7 @@ import {
|
|
|
1653
1653
|
mkdir as mkdir3,
|
|
1654
1654
|
mkdtemp as mkdtemp2,
|
|
1655
1655
|
readFile as readFile4,
|
|
1656
|
+
realpath as realpath2,
|
|
1656
1657
|
rename as rename4,
|
|
1657
1658
|
rm as rm3,
|
|
1658
1659
|
stat,
|
|
@@ -2283,6 +2284,18 @@ var signAab = (artifactPath, capture, jarsigner, signing) => {
|
|
|
2283
2284
|
throw new TypeError("jarsigner could not sign the Android App Bundle with the configured CI identity.");
|
|
2284
2285
|
};
|
|
2285
2286
|
var sha256File = async (path) => createHash4("sha256").update(await readFile4(path)).digest("hex");
|
|
2287
|
+
var fingerprintExpoAndroidProject = async (nativeDirectory) => {
|
|
2288
|
+
const root = await realpath2(nativeDirectory);
|
|
2289
|
+
const files = await Array.fromAsync(new Bun.Glob("**/*").scan({ cwd: root, onlyFiles: true }));
|
|
2290
|
+
const records = await Promise.all(files.filter((path) => {
|
|
2291
|
+
const parts = path.replaceAll("\\", "/").split("/");
|
|
2292
|
+
return !parts.includes(".gradle") && !parts.includes("build");
|
|
2293
|
+
}).sort().map(async (path) => {
|
|
2294
|
+
const contents = await readFile4(join4(root, path));
|
|
2295
|
+
return `${path.replaceAll("\\", "/")}\x00${createHash4("sha256").update(contents).digest("hex")}\x00`;
|
|
2296
|
+
}));
|
|
2297
|
+
return createHash4("sha256").update(records.join("")).digest("hex");
|
|
2298
|
+
};
|
|
2286
2299
|
var safeOutputDirectory = (projectRoot, requested) => {
|
|
2287
2300
|
const root = resolve3(projectRoot);
|
|
2288
2301
|
const output = resolve3(root, requested ?? ".absolutejs/mobile/releases/android");
|
|
@@ -2344,6 +2357,9 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2344
2357
|
}
|
|
2345
2358
|
const projectRoot = resolve3(options.projectRoot);
|
|
2346
2359
|
const host = options.host ?? detectAbsoluteMobileHost();
|
|
2360
|
+
if (options.config.engine === "expo" && host === "wsl") {
|
|
2361
|
+
throw new TypeError("Expo Android production builds from WSL are not available yet. Run the generated CI workflow on Linux or build from native Windows while the WSL projection is completed.");
|
|
2362
|
+
}
|
|
2347
2363
|
const androidRoot = options.androidRoot ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK_ROOT ?? absoluteManagedAndroidSdkRoot(host);
|
|
2348
2364
|
const nativeDirectory = join4(options.config.nativeProjectDirectory, "android");
|
|
2349
2365
|
const manifest = requireManifest(JSON.parse(await readFile4(join4(options.config.bundleDirectory, "absolute-mobile-manifest.json"), "utf8")));
|
|
@@ -2352,7 +2368,9 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2352
2368
|
}
|
|
2353
2369
|
let { versionCode } = options;
|
|
2354
2370
|
if (options.prepareVersionCode) {
|
|
2355
|
-
const nativeFingerprint = await fingerprintAbsoluteAndroidNativeProject({
|
|
2371
|
+
const nativeFingerprint = options.config.engine === "expo" ? await fingerprintExpoAndroidProject(nativeDirectory) : await fingerprintAbsoluteAndroidNativeProject({
|
|
2372
|
+
nativeDirectory
|
|
2373
|
+
});
|
|
2356
2374
|
const buildIdentity = createHash4("sha256").update(`${manifest.appBuild}\x00${nativeFingerprint}`).digest("hex");
|
|
2357
2375
|
versionCode = await options.prepareVersionCode(buildIdentity);
|
|
2358
2376
|
}
|
|
@@ -2361,6 +2379,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2361
2379
|
}
|
|
2362
2380
|
const { artifactPath } = await buildAbsoluteAndroidGradleArtifact({
|
|
2363
2381
|
capture: options.capture,
|
|
2382
|
+
env: options.env,
|
|
2364
2383
|
gradleArguments: versionCode === undefined ? [] : [`-Pandroid.injected.version.code=${versionCode}`],
|
|
2365
2384
|
project: {
|
|
2366
2385
|
androidRoot,
|
|
@@ -2401,7 +2420,7 @@ var buildAbsoluteAndroidRelease = async (options) => {
|
|
|
2401
2420
|
appBuild: manifest.appBuild,
|
|
2402
2421
|
appId: manifest.appId,
|
|
2403
2422
|
bytes,
|
|
2404
|
-
engine:
|
|
2423
|
+
engine: options.config.engine,
|
|
2405
2424
|
format: ABSOLUTE_ANDROID_RELEASE_FORMAT,
|
|
2406
2425
|
platform: "android",
|
|
2407
2426
|
releaseId,
|
|
@@ -5231,6 +5250,7 @@ var getCurrentAbsoluteMobileProducerContext = () => {
|
|
|
5231
5250
|
// src/mobile/pageProtocol.ts
|
|
5232
5251
|
var ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE = "application/vnd.absolute.page+json";
|
|
5233
5252
|
var ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION = 1;
|
|
5253
|
+
var ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE = "application/vnd.absolute.native-route+json";
|
|
5234
5254
|
var BAD_REQUEST_STATUS = 400;
|
|
5235
5255
|
var OK_STATUS = 200;
|
|
5236
5256
|
var SERVER_ERROR_STATUS = 500;
|
|
@@ -5249,6 +5269,11 @@ var acceptsAbsoluteMobilePage = (request) => {
|
|
|
5249
5269
|
return false;
|
|
5250
5270
|
return (request.headers.get("accept") ?? "").split(",").some((value) => parseMediaType(value) === ABSOLUTE_MOBILE_PAGE_MEDIA_TYPE);
|
|
5251
5271
|
};
|
|
5272
|
+
var acceptsAbsoluteNativeRouteData = (request) => {
|
|
5273
|
+
if (!request)
|
|
5274
|
+
return false;
|
|
5275
|
+
return (request.headers.get("accept") ?? "").split(",").some((value) => parseMediaType(value) === ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE);
|
|
5276
|
+
};
|
|
5252
5277
|
var readRequiredHeader = (request, name) => {
|
|
5253
5278
|
const value = request.headers.get(name)?.trim();
|
|
5254
5279
|
return value ? value : undefined;
|
|
@@ -5379,6 +5404,32 @@ var finalizeArchivedMobilePage = (context, input) => {
|
|
|
5379
5404
|
return createAbsoluteMobilePageErrorResponse(page.pageId);
|
|
5380
5405
|
}
|
|
5381
5406
|
};
|
|
5407
|
+
var finalizeAbsoluteNativeRouteDevelopmentPage = (input) => {
|
|
5408
|
+
if (false) {}
|
|
5409
|
+
if (input.request?.method !== "GET") {
|
|
5410
|
+
return createAbsoluteMobileInvalidRequestResponse("Native-route data requests must use GET.");
|
|
5411
|
+
}
|
|
5412
|
+
if (input.request.headers.get(MOBILE_PAGE_REQUEST_HEADERS.protocol) !== String(ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION)) {
|
|
5413
|
+
return createAbsoluteMobileInvalidRequestResponse(`Native-route data requires protocol ${ABSOLUTE_MOBILE_PAGE_PROTOCOL_VERSION}.`);
|
|
5414
|
+
}
|
|
5415
|
+
const [representation] = input.compatibility.representations;
|
|
5416
|
+
if (!representation) {
|
|
5417
|
+
return createAbsoluteMobilePageErrorResponse(input.compatibility.pageId);
|
|
5418
|
+
}
|
|
5419
|
+
try {
|
|
5420
|
+
return envelopeResponse({
|
|
5421
|
+
contract: representation.contract,
|
|
5422
|
+
framework: input.compatibility.framework,
|
|
5423
|
+
kind: "page",
|
|
5424
|
+
pageId: input.compatibility.pageId,
|
|
5425
|
+
props: normalizeJsonValue(representation.mapProps(input.props)),
|
|
5426
|
+
status: input.status ?? OK_STATUS
|
|
5427
|
+
}, input.status ?? OK_STATUS);
|
|
5428
|
+
} catch (error) {
|
|
5429
|
+
console.error(`[Mobile] Failed to produce development native route ${input.compatibility.pageId}:`, error);
|
|
5430
|
+
return createAbsoluteMobilePageErrorResponse(input.compatibility.pageId);
|
|
5431
|
+
}
|
|
5432
|
+
};
|
|
5382
5433
|
var createAbsoluteMobileInvalidRequestResponse = (message) => envelopeResponse({ kind: "invalid-request", message }, BAD_REQUEST_STATUS);
|
|
5383
5434
|
var createAbsoluteMobilePageErrorResponse = (pageId) => envelopeResponse({
|
|
5384
5435
|
code: "representation-failed",
|
|
@@ -5388,6 +5439,9 @@ var createAbsoluteMobilePageErrorResponse = (pageId) => envelopeResponse({
|
|
|
5388
5439
|
}, SERVER_ERROR_STATUS);
|
|
5389
5440
|
var createAbsoluteMobileUpgradeResponse = (result) => envelopeResponse(result, UPGRADE_REQUIRED_STATUS);
|
|
5390
5441
|
var finalizeAbsoluteMobilePage = (input) => {
|
|
5442
|
+
if (acceptsAbsoluteNativeRouteData(input.request)) {
|
|
5443
|
+
return finalizeAbsoluteNativeRouteDevelopmentPage(input);
|
|
5444
|
+
}
|
|
5391
5445
|
const parsed = parseAbsoluteMobilePageRequest(input.request);
|
|
5392
5446
|
if (parsed.kind === "not-mobile")
|
|
5393
5447
|
return;
|
|
@@ -6179,6 +6233,48 @@ var exists3 = async (path) => {
|
|
|
6179
6233
|
return false;
|
|
6180
6234
|
}
|
|
6181
6235
|
};
|
|
6236
|
+
var isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6237
|
+
var requireManifestString = (value, field2) => {
|
|
6238
|
+
if (typeof value !== "string" || !value) {
|
|
6239
|
+
throw new TypeError(`AbsoluteJS mobile manifest ${field2} is invalid.`);
|
|
6240
|
+
}
|
|
6241
|
+
return value;
|
|
6242
|
+
};
|
|
6243
|
+
var expoNativeDataManifest = (value) => {
|
|
6244
|
+
if (!isRecord8(value) || !Array.isArray(value.pages) || !Array.isArray(value.routes)) {
|
|
6245
|
+
throw new TypeError("AbsoluteJS mobile manifest is invalid.");
|
|
6246
|
+
}
|
|
6247
|
+
const pages = value.pages.map((page) => {
|
|
6248
|
+
if (!isRecord8(page))
|
|
6249
|
+
throw new TypeError("AbsoluteJS mobile manifest page is invalid.");
|
|
6250
|
+
return {
|
|
6251
|
+
bundleHash: requireManifestString(page.bundleHash, "page.bundleHash"),
|
|
6252
|
+
contract: requireManifestString(page.contract, "page.contract"),
|
|
6253
|
+
pageId: requireManifestString(page.pageId, "page.pageId")
|
|
6254
|
+
};
|
|
6255
|
+
});
|
|
6256
|
+
const routes = value.routes.flatMap((route) => {
|
|
6257
|
+
if (!isRecord8(route) || typeof route.method !== "string") {
|
|
6258
|
+
throw new TypeError("AbsoluteJS mobile manifest route is invalid.");
|
|
6259
|
+
}
|
|
6260
|
+
if (route.method !== "GET")
|
|
6261
|
+
return [];
|
|
6262
|
+
return [
|
|
6263
|
+
{
|
|
6264
|
+
method: "GET",
|
|
6265
|
+
pageId: requireManifestString(route.pageId, "route.pageId"),
|
|
6266
|
+
pattern: requireManifestString(route.pattern, "route.pattern")
|
|
6267
|
+
}
|
|
6268
|
+
];
|
|
6269
|
+
});
|
|
6270
|
+
return {
|
|
6271
|
+
appBuild: requireManifestString(value.appBuild, "appBuild"),
|
|
6272
|
+
pages,
|
|
6273
|
+
productionOrigin: requireManifestString(value.productionOrigin, "productionOrigin"),
|
|
6274
|
+
routes,
|
|
6275
|
+
runtime: requireManifestString(value.runtime, "runtime")
|
|
6276
|
+
};
|
|
6277
|
+
};
|
|
6182
6278
|
var portableRelative2 = (from, destination) => {
|
|
6183
6279
|
const value = relative10(from, destination).replaceAll("\\", "/");
|
|
6184
6280
|
return value.startsWith(".") ? value : `./${value}`;
|
|
@@ -6973,7 +7069,134 @@ var catchAllRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } fr
|
|
|
6973
7069
|
|
|
6974
7070
|
export default AbsoluteWebHost;
|
|
6975
7071
|
`;
|
|
6976
|
-
var
|
|
7072
|
+
var nativeRouteRuntimeSource = (auth) => `${EXPO_GENERATED_HEADER}import { useLocalSearchParams, usePathname } from 'expo-router';
|
|
7073
|
+
import { type ComponentType, useEffect, useMemo, useState } from 'react';
|
|
7074
|
+
import { ActivityIndicator, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
7075
|
+
import { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';
|
|
7076
|
+
${auth ? "import { absoluteExpoAuth } from './AbsoluteAuth';" : ""}
|
|
7077
|
+
|
|
7078
|
+
const PAGE_MEDIA_TYPE = 'application/vnd.absolute.page+json';
|
|
7079
|
+
const NATIVE_DATA_MEDIA_TYPE = 'application/vnd.absolute.native-route+json';
|
|
7080
|
+
const PROTOCOL = 1;
|
|
7081
|
+
const MAX_DATA_BYTES = 1024 * 1024;
|
|
7082
|
+
const DEV_ORIGIN = Platform.OS === 'android'
|
|
7083
|
+
? process.env.EXPO_PUBLIC_ABSOLUTE_DEV_ANDROID_ORIGIN
|
|
7084
|
+
: process.env.EXPO_PUBLIC_ABSOLUTE_DEV_IOS_ORIGIN;
|
|
7085
|
+
|
|
7086
|
+
type RouteParams = Record<string, string | string[] | undefined>;
|
|
7087
|
+
type NativeRouteProps<PageProps extends object, Params extends object> = {
|
|
7088
|
+
pageProps: Readonly<PageProps>;
|
|
7089
|
+
params: Readonly<Params>;
|
|
7090
|
+
reload: () => void;
|
|
7091
|
+
};
|
|
7092
|
+
type NativeRouteState<PageProps> =
|
|
7093
|
+
| { kind: 'loading' }
|
|
7094
|
+
| { kind: 'ready'; pageProps: PageProps }
|
|
7095
|
+
| { kind: 'error' };
|
|
7096
|
+
|
|
7097
|
+
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
7098
|
+
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7099
|
+
const routeSegmentPattern = (segment: string) => {
|
|
7100
|
+
if (segment === '*') return '.*';
|
|
7101
|
+
if (segment.startsWith(':') && segment.endsWith('?')) return '[^/]*';
|
|
7102
|
+
if (segment.startsWith(':')) return '[^/]+';
|
|
7103
|
+
return segment.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
|
|
7104
|
+
};
|
|
7105
|
+
const matchesRoute = (pattern: string, pathname: string) =>
|
|
7106
|
+
new RegExp('^' + pattern.split('/').map(routeSegmentPattern).join('/') + '/?$').test(pathname);
|
|
7107
|
+
const requestPathFor = (pathname: string, params: RouteParams, pattern: string) => {
|
|
7108
|
+
const pathNames = new Set(pattern.split('/').filter(segment => segment.startsWith(':')).map(segment => segment.replace(/^:/, '').replace(/\\?$/, '')));
|
|
7109
|
+
if (pattern.endsWith('/*')) pathNames.add('absoluteWildcard');
|
|
7110
|
+
const query = new URLSearchParams();
|
|
7111
|
+
for (const [name, value] of Object.entries(params).sort(([left], [right]) => left.localeCompare(right))) {
|
|
7112
|
+
if (pathNames.has(name) || name === '#' || value === undefined) continue;
|
|
7113
|
+
for (const item of Array.isArray(value) ? value : [value]) query.append(name, item);
|
|
7114
|
+
}
|
|
7115
|
+
const search = query.toString();
|
|
7116
|
+
return pathname + (search ? '?' + search : '');
|
|
7117
|
+
};
|
|
7118
|
+
const productionPage = (pathname: string) => {
|
|
7119
|
+
if (!ABSOLUTE_MOBILE_MANIFEST) throw new Error('AbsoluteJS native route data is not prepared for production.');
|
|
7120
|
+
const route = ABSOLUTE_MOBILE_MANIFEST.routes.find(candidate => candidate.method === 'GET' && matchesRoute(candidate.pattern, pathname));
|
|
7121
|
+
if (!route) throw new Error('No trusted AbsoluteJS page route owns this native URL.');
|
|
7122
|
+
const page = ABSOLUTE_MOBILE_MANIFEST.pages.find(candidate => candidate.pageId === route.pageId);
|
|
7123
|
+
if (!page) throw new Error('The embedded AbsoluteJS page contract is incomplete.');
|
|
7124
|
+
return page;
|
|
7125
|
+
};
|
|
7126
|
+
const createDataRequest = (path: string) => {
|
|
7127
|
+
const development = typeof DEV_ORIGIN === 'string' && DEV_ORIGIN.length > 0;
|
|
7128
|
+
const origin = development ? DEV_ORIGIN : ABSOLUTE_MOBILE_MANIFEST?.productionOrigin;
|
|
7129
|
+
if (!origin) throw new Error('AbsoluteJS native route data has no trusted server origin.');
|
|
7130
|
+
const url = new URL(path, origin);
|
|
7131
|
+
if (url.origin !== new URL(origin).origin) throw new Error('AbsoluteJS native route data left its trusted origin.');
|
|
7132
|
+
const headers = new Headers();
|
|
7133
|
+
headers.set('accept', development ? NATIVE_DATA_MEDIA_TYPE : PAGE_MEDIA_TYPE);
|
|
7134
|
+
headers.set('x-absolute-mobile-protocol', String(PROTOCOL));
|
|
7135
|
+
let page: ReturnType<typeof productionPage> | undefined;
|
|
7136
|
+
if (!development) {
|
|
7137
|
+
page = productionPage(url.pathname);
|
|
7138
|
+
headers.set('x-absolute-mobile-app-build', ABSOLUTE_MOBILE_MANIFEST!.appBuild);
|
|
7139
|
+
headers.set('x-absolute-mobile-page-bundle', page.bundleHash);
|
|
7140
|
+
headers.set('x-absolute-mobile-page-contracts', page.contract);
|
|
7141
|
+
headers.set('x-absolute-mobile-page-id', page.pageId);
|
|
7142
|
+
headers.set('x-absolute-mobile-runtime', ABSOLUTE_MOBILE_MANIFEST!.runtime);
|
|
7143
|
+
}
|
|
7144
|
+
return { page, request: new Request(url, { headers, method: 'GET' }) };
|
|
7145
|
+
};
|
|
7146
|
+
const requestData = async <PageProps extends object>(path: string, signal: AbortSignal) => {
|
|
7147
|
+
const { page, request } = createDataRequest(path);
|
|
7148
|
+
const response = await ${auth ? "absoluteExpoAuth.fetchOptional" : "fetch"}(request, { redirect: 'manual', signal });
|
|
7149
|
+
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.');
|
|
7150
|
+
const source = await response.text();
|
|
7151
|
+
if (new TextEncoder().encode(source).byteLength > MAX_DATA_BYTES) throw new Error('AbsoluteJS native route data exceeded 1 MiB.');
|
|
7152
|
+
let envelope: unknown;
|
|
7153
|
+
try { envelope = JSON.parse(source); } catch { throw new Error('The server did not return an AbsoluteJS page envelope.'); }
|
|
7154
|
+
if (!isRecord(envelope) || envelope.protocol !== PROTOCOL || !isRecord(envelope.response)) throw new Error('The server returned an invalid AbsoluteJS page envelope.');
|
|
7155
|
+
const result = envelope.response;
|
|
7156
|
+
if (result.kind === 'upgrade-required') throw new Error('This app version must be updated before opening this screen.');
|
|
7157
|
+
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.');
|
|
7158
|
+
if (page && (result.pageId !== page.pageId || result.contract !== page.contract)) throw new Error('The server returned a different page contract than this app contains.');
|
|
7159
|
+
return result.props as PageProps;
|
|
7160
|
+
};
|
|
7161
|
+
|
|
7162
|
+
export const createAbsoluteNativeRoute = <
|
|
7163
|
+
PageProps extends object,
|
|
7164
|
+
Params extends object = RouteParams
|
|
7165
|
+
>(Component: ComponentType<NativeRouteProps<PageProps, Params>>, pattern: string) => {
|
|
7166
|
+
function AbsoluteNativeRouteScreen() {
|
|
7167
|
+
const pathname = usePathname() || '/';
|
|
7168
|
+
const params = useLocalSearchParams() as RouteParams;
|
|
7169
|
+
const parameterKey = JSON.stringify(params);
|
|
7170
|
+
const requestPath = useMemo(() => requestPathFor(pathname, params, pattern), [parameterKey, pathname]);
|
|
7171
|
+
const [revision, setRevision] = useState(0);
|
|
7172
|
+
const [state, setState] = useState<NativeRouteState<PageProps>>({ kind: 'loading' });
|
|
7173
|
+
useEffect(() => {
|
|
7174
|
+
const controller = new AbortController();
|
|
7175
|
+
setState({ kind: 'loading' });
|
|
7176
|
+
void requestData<PageProps>(requestPath, controller.signal).then(
|
|
7177
|
+
pageProps => { if (!controller.signal.aborted) setState({ kind: 'ready', pageProps }); },
|
|
7178
|
+
() => { if (!controller.signal.aborted) setState({ kind: 'error' }); }
|
|
7179
|
+
);
|
|
7180
|
+
return () => controller.abort();
|
|
7181
|
+
}, [requestPath, revision]);
|
|
7182
|
+
const reload = () => setRevision(value => value + 1);
|
|
7183
|
+
if (state.kind === 'loading') return <View style={styles.center}><ActivityIndicator accessibilityLabel="Loading screen" /></View>;
|
|
7184
|
+
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>;
|
|
7185
|
+
return <Component pageProps={state.pageProps} params={params as Params} reload={reload} />;
|
|
7186
|
+
}
|
|
7187
|
+
return AbsoluteNativeRouteScreen;
|
|
7188
|
+
};
|
|
7189
|
+
|
|
7190
|
+
const styles = StyleSheet.create({
|
|
7191
|
+
button: { backgroundColor: '#e2e8f0', borderRadius: 10, paddingHorizontal: 16, paddingVertical: 12 },
|
|
7192
|
+
center: { alignItems: 'center', flex: 1, gap: 16, justifyContent: 'center', padding: 24 },
|
|
7193
|
+
error: { color: '#b91c1c', fontSize: 16, textAlign: 'center' }
|
|
7194
|
+
});
|
|
7195
|
+
`;
|
|
7196
|
+
var nativeWrapperSource = (wrapper, module, runtime, route) => `${EXPO_GENERATED_HEADER}import ApplicationNativeRoute from ${JSON.stringify(portableRelative2(dirname10(wrapper), module).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
7197
|
+
import { createAbsoluteNativeRoute } from ${JSON.stringify(portableRelative2(dirname10(wrapper), runtime).replace(/\.(?:[cm]?[jt]sx?)$/u, ""))};
|
|
7198
|
+
|
|
7199
|
+
export default createAbsoluteNativeRoute(ApplicationNativeRoute, ${JSON.stringify(route)});
|
|
6977
7200
|
`;
|
|
6978
7201
|
var expoTsConfig = (projectRoot, project, auth, sync) => ({
|
|
6979
7202
|
compilerOptions: {
|
|
@@ -7040,9 +7263,19 @@ var pruneStaleManagedExpoRoutes = async (project, expected) => {
|
|
|
7040
7263
|
};
|
|
7041
7264
|
var jsonSource = (value) => `${JSON.stringify(value, null, "\t")}
|
|
7042
7265
|
`;
|
|
7043
|
-
var
|
|
7266
|
+
var nativeDataManifestTypeSource = `type AbsoluteMobileManifest = {
|
|
7267
|
+
appBuild: string;
|
|
7268
|
+
pages: readonly { bundleHash: string; contract: string; pageId: string }[];
|
|
7269
|
+
productionOrigin: string;
|
|
7270
|
+
routes: readonly { method: 'GET'; pageId: string; pattern: string }[];
|
|
7271
|
+
runtime: string;
|
|
7272
|
+
};
|
|
7273
|
+
`;
|
|
7274
|
+
var emptyWebAssetsSource = `${EXPO_GENERATED_HEADER}${nativeDataManifestTypeSource}
|
|
7275
|
+
export const materializeAbsoluteWebBundle = async () => {
|
|
7044
7276
|
throw new Error('The embedded AbsoluteJS bundle is unavailable. Run absolute prepare before a production Expo build.');
|
|
7045
7277
|
};
|
|
7278
|
+
export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest | undefined = undefined;
|
|
7046
7279
|
`;
|
|
7047
7280
|
var writeAbsoluteExpoProject = async (config, options) => {
|
|
7048
7281
|
if (config.engine !== "expo")
|
|
@@ -7113,6 +7346,10 @@ node_modules/
|
|
|
7113
7346
|
join14(project, "src", "generated", "AbsoluteDevices.ts"),
|
|
7114
7347
|
devicesRuntimeSource(config, devices, authEnabled)
|
|
7115
7348
|
],
|
|
7349
|
+
[
|
|
7350
|
+
join14(project, "src", "generated", "AbsoluteNativeRoute.tsx"),
|
|
7351
|
+
nativeRouteRuntimeSource(authEnabled)
|
|
7352
|
+
],
|
|
7116
7353
|
[
|
|
7117
7354
|
join14(project, "src", "generated", "AbsoluteWebHost.tsx"),
|
|
7118
7355
|
webHostSource(config, auth, syncEnabled)
|
|
@@ -7132,9 +7369,10 @@ node_modules/
|
|
|
7132
7369
|
files.set(join14(project, "app", "index.tsx"), webRouteSource);
|
|
7133
7370
|
}
|
|
7134
7371
|
files.set(join14(project, "app", "[...absolute].tsx"), catchAllRouteSource);
|
|
7372
|
+
const nativeRouteRuntime = join14(project, "src", "generated", "AbsoluteNativeRoute.tsx");
|
|
7135
7373
|
for (const [route, module] of routeModules) {
|
|
7136
7374
|
const wrapper = route === "/" ? join14(project, "app", "index.tsx") : routeFile(project, route);
|
|
7137
|
-
files.set(wrapper, nativeWrapperSource(wrapper, module));
|
|
7375
|
+
files.set(wrapper, nativeWrapperSource(wrapper, module, nativeRouteRuntime, route));
|
|
7138
7376
|
}
|
|
7139
7377
|
const removed = await pruneStaleManagedExpoRoutes(project, new Set([...files.keys()].filter((path) => path.startsWith(`${join14(project, "app")}${sep6}`))));
|
|
7140
7378
|
const changes = await Promise.all([...files].map(([path, source]) => writeManagedFile(path, source, true)));
|
|
@@ -7177,11 +7415,13 @@ var installStagedDirectory = async (staging, destination) => {
|
|
|
7177
7415
|
throw error;
|
|
7178
7416
|
}
|
|
7179
7417
|
};
|
|
7180
|
-
var assetModuleSource = (assets, bundleId) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
7418
|
+
var assetModuleSource = (assets, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
|
|
7181
7419
|
import { Directory, File, Paths } from 'expo-file-system';
|
|
7182
7420
|
|
|
7421
|
+
${nativeDataManifestTypeSource}
|
|
7183
7422
|
declare const require: (path: string) => number;
|
|
7184
7423
|
const BUNDLE_ID = ${JSON.stringify(bundleId)};
|
|
7424
|
+
export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest = ${JSON.stringify(manifest)};
|
|
7185
7425
|
const ASSETS = [
|
|
7186
7426
|
${assets.map(({ asset, path }) => ` { module: require(${JSON.stringify(asset)}), path: ${JSON.stringify(path)} }`).join(`,
|
|
7187
7427
|
`)}
|
|
@@ -7215,9 +7455,8 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
7215
7455
|
}
|
|
7216
7456
|
const manifestPath = join14(config.bundleDirectory, "absolute-mobile-manifest.json");
|
|
7217
7457
|
const manifest = JSON.parse(await readFile14(manifestPath, "utf8"));
|
|
7218
|
-
const
|
|
7219
|
-
|
|
7220
|
-
throw new TypeError("AbsoluteJS mobile manifest has no appBuild.");
|
|
7458
|
+
const nativeDataManifest = expoNativeDataManifest(manifest);
|
|
7459
|
+
const { appBuild } = nativeDataManifest;
|
|
7221
7460
|
const files = await walkFiles(config.bundleDirectory);
|
|
7222
7461
|
const bundleHash = createHash10("sha256");
|
|
7223
7462
|
const filesWithContents = await Promise.all(files.map(async (file) => ({ contents: await readFile14(file), file })));
|
|
@@ -7247,7 +7486,7 @@ var syncAbsoluteExpoWebAssets = async (config) => {
|
|
|
7247
7486
|
throw error;
|
|
7248
7487
|
}
|
|
7249
7488
|
const generated = join14(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
|
|
7250
|
-
await writeManagedFile(generated, assetModuleSource(assets, bundleId), true);
|
|
7489
|
+
await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
|
|
7251
7490
|
return { appBuild, assets: assets.length, bundleId, path: destination };
|
|
7252
7491
|
};
|
|
7253
7492
|
|
|
@@ -7564,7 +7803,7 @@ var ABSOLUTE_EXPO_BRIDGE_METHODS = [
|
|
|
7564
7803
|
"sync.socket.open",
|
|
7565
7804
|
"sync.socket.sendChunk"
|
|
7566
7805
|
];
|
|
7567
|
-
var
|
|
7806
|
+
var isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
7568
7807
|
var validId = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,80}$/u.test(value);
|
|
7569
7808
|
var validPath = (value) => typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && value.length <= 4096;
|
|
7570
7809
|
var parseRequest = (value) => {
|
|
@@ -7574,7 +7813,7 @@ var parseRequest = (value) => {
|
|
|
7574
7813
|
if (!method) {
|
|
7575
7814
|
throw new TypeError("Expo bridge method is not allowed.");
|
|
7576
7815
|
}
|
|
7577
|
-
if (!
|
|
7816
|
+
if (!isRecord9(value.params))
|
|
7578
7817
|
throw new TypeError("Expo bridge request params must be an object.");
|
|
7579
7818
|
if (typeof value.path !== "string" || !validPath(value.path))
|
|
7580
7819
|
throw new TypeError("Expo bridge request path is invalid.");
|
|
@@ -7610,7 +7849,7 @@ var parseRequest = (value) => {
|
|
|
7610
7849
|
throw new TypeError("Expo bridge HTTP body exceeds 48 KiB.");
|
|
7611
7850
|
if ((value.params.method === "GET" || value.params.method === "DELETE") && value.params.body !== undefined)
|
|
7612
7851
|
throw new TypeError("Expo bridge HTTP method cannot contain a body.");
|
|
7613
|
-
if (!
|
|
7852
|
+
if (!isRecord9(value.params.headers))
|
|
7614
7853
|
throw new TypeError("Expo bridge HTTP headers must be an object.");
|
|
7615
7854
|
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-")));
|
|
7616
7855
|
if (!headersAllowed) {
|
|
@@ -7636,13 +7875,13 @@ var parseResponse = (value) => {
|
|
|
7636
7875
|
if (typeof value.id !== "string" || !validId(value.id))
|
|
7637
7876
|
throw new TypeError("Expo bridge response id is invalid.");
|
|
7638
7877
|
if (value.error !== undefined) {
|
|
7639
|
-
if (!
|
|
7878
|
+
if (!isRecord9(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string") {
|
|
7640
7879
|
throw new TypeError("Expo bridge response error is invalid.");
|
|
7641
7880
|
}
|
|
7642
7881
|
if (value.result !== undefined)
|
|
7643
7882
|
throw new TypeError("Expo bridge response cannot contain result and error.");
|
|
7644
7883
|
}
|
|
7645
|
-
if (
|
|
7884
|
+
if (isRecord9(value.error)) {
|
|
7646
7885
|
return {
|
|
7647
7886
|
error: {
|
|
7648
7887
|
code: String(value.error.code),
|
|
@@ -7666,7 +7905,7 @@ var parseEvent = (value) => {
|
|
|
7666
7905
|
}
|
|
7667
7906
|
if (typeof value.path !== "string" || !validPath(value.path))
|
|
7668
7907
|
throw new TypeError("Expo bridge event path is invalid.");
|
|
7669
|
-
if (value.payload !== undefined && !
|
|
7908
|
+
if (value.payload !== undefined && !isRecord9(value.payload)) {
|
|
7670
7909
|
throw new TypeError("Expo bridge event payload must be an object.");
|
|
7671
7910
|
}
|
|
7672
7911
|
return {
|
|
@@ -7700,7 +7939,7 @@ var parseAbsoluteExpoBridgeMessage = (source) => {
|
|
|
7700
7939
|
cause
|
|
7701
7940
|
});
|
|
7702
7941
|
}
|
|
7703
|
-
if (!
|
|
7942
|
+
if (!isRecord9(parsed) || parsed.format !== ABSOLUTE_EXPO_BRIDGE_FORMAT) {
|
|
7704
7943
|
throw new TypeError("Expo bridge message format is unsupported.");
|
|
7705
7944
|
}
|
|
7706
7945
|
if (parsed.kind === "request")
|
|
@@ -8467,8 +8706,10 @@ var requiredSecrets = (platforms, includePublishing, custom) => [
|
|
|
8467
8706
|
];
|
|
8468
8707
|
var createAbsoluteMobileGithubWorkflow = (options) => {
|
|
8469
8708
|
const platforms = [
|
|
8470
|
-
...options.config.platforms
|
|
8709
|
+
...options.config.engine === "expo" ? options.config.platforms.filter((platform) => platform === "android") : options.config.platforms
|
|
8471
8710
|
].sort();
|
|
8711
|
+
if (platforms.length === 0)
|
|
8712
|
+
throw new TypeError("Generated Expo production CI currently requires android in mobile.platforms; Expo iOS release automation is the next checkpoint.");
|
|
8472
8713
|
const includePublishing = options.includePublishing === true;
|
|
8473
8714
|
const customSecrets = normalizeSecretEnvironment(options.secretEnvironment);
|
|
8474
8715
|
const serverEntry = projectPath(options.projectRoot, options.serverEntry ?? "server.ts", "mobile ci github server entry");
|
|
@@ -8544,7 +8785,7 @@ var writeAbsoluteMobileGithubWorkflow = async (options) => {
|
|
|
8544
8785
|
changed: previous !== generated.workflow,
|
|
8545
8786
|
format: ABSOLUTE_MOBILE_CI_WORKFLOW_FORMAT,
|
|
8546
8787
|
path,
|
|
8547
|
-
platforms: [...options.config.platforms].sort(),
|
|
8788
|
+
platforms: options.config.engine === "expo" ? options.config.platforms.filter((platform) => platform === "android") : [...options.config.platforms].sort(),
|
|
8548
8789
|
publishing: options.includePublishing === true,
|
|
8549
8790
|
requiredSecrets: generated.requiredSecrets
|
|
8550
8791
|
};
|
|
@@ -8698,7 +8939,7 @@ init_telemetryEvent();
|
|
|
8698
8939
|
import { Elysia as Elysia3 } from "elysia";
|
|
8699
8940
|
var ABSOLUTE_MOBILE_PREVIEW_PATH = "/__absolute/mobile-preview";
|
|
8700
8941
|
var escapeHtml2 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
8701
|
-
var
|
|
8942
|
+
var isRecord10 = (value) => typeof value === "object" && value !== null;
|
|
8702
8943
|
var normalizeEntry2 = (entry) => {
|
|
8703
8944
|
const parsed = new URL(entry ?? "/", "https://absolute.invalid");
|
|
8704
8945
|
return `${parsed.pathname}${parsed.search}${parsed.hash}`;
|
|
@@ -8749,7 +8990,7 @@ var createAbsoluteMobilePreviewPlugin = (mobile) => {
|
|
|
8749
8990
|
"X-Robots-Tag": "noindex, nofollow"
|
|
8750
8991
|
}
|
|
8751
8992
|
})).post("/__absolute/mobile-preview-telemetry", ({ body, status }) => {
|
|
8752
|
-
const value =
|
|
8993
|
+
const value = isRecord10(body) ? body : undefined;
|
|
8753
8994
|
const durationMs = value?.durationMs;
|
|
8754
8995
|
const platform2 = value?.platform;
|
|
8755
8996
|
if (typeof durationMs !== "number" || !Number.isFinite(durationMs) || durationMs < 0 || durationMs > 300000 || platform2 !== "android" && platform2 !== "ios") {
|
|
@@ -9306,8 +9547,8 @@ var prepareAbsoluteAndroidRelease = async (publisher, options) => {
|
|
|
9306
9547
|
}
|
|
9307
9548
|
return versionCode;
|
|
9308
9549
|
};
|
|
9309
|
-
var
|
|
9310
|
-
var isPublisher = (value) =>
|
|
9550
|
+
var isRecord11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9551
|
+
var isPublisher = (value) => isRecord11(value) && typeof value.publish === "function";
|
|
9311
9552
|
var publisherModulePath = (projectRoot, requested) => {
|
|
9312
9553
|
const root = resolve15(projectRoot);
|
|
9313
9554
|
const path = resolve15(root, requested);
|
|
@@ -9323,7 +9564,7 @@ var loadAbsoluteNativeReleasePublisher = async (projectRoot, requestedModulePath
|
|
|
9323
9564
|
throw new TypeError(`Native release registry module does not exist: ${modulePath}`);
|
|
9324
9565
|
});
|
|
9325
9566
|
const loaded = await import(pathToFileURL3(modulePath).href);
|
|
9326
|
-
const publisher =
|
|
9567
|
+
const publisher = isRecord11(loaded) ? loaded.default ?? loaded.registry : undefined;
|
|
9327
9568
|
if (!isPublisher(publisher)) {
|
|
9328
9569
|
throw new TypeError("Native release registry module must default-export a registry with publish(options).");
|
|
9329
9570
|
}
|
|
@@ -10139,6 +10380,7 @@ export {
|
|
|
10139
10380
|
ABSOLUTE_MOBILE_TRANSFORM_PROTOCOL,
|
|
10140
10381
|
ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV,
|
|
10141
10382
|
ABSOLUTE_NATIVE_AUTH_SCOPES,
|
|
10383
|
+
ABSOLUTE_NATIVE_ROUTE_DATA_MEDIA_TYPE,
|
|
10142
10384
|
ABSOLUTE_REMOTE_MAC_EVENT_PREFIX,
|
|
10143
10385
|
ABSOLUTE_REMOTE_MAC_PROTOCOL_VERSION,
|
|
10144
10386
|
ABSOLUTE_SYNC_PACKAGE,
|
|
@@ -10153,6 +10395,7 @@ export {
|
|
|
10153
10395
|
absoluteRemoteMacSshBase,
|
|
10154
10396
|
absoluteRemoteProjectSyncCommands,
|
|
10155
10397
|
acceptsAbsoluteMobilePage,
|
|
10398
|
+
acceptsAbsoluteNativeRouteData,
|
|
10156
10399
|
activateAbsoluteMobilePage,
|
|
10157
10400
|
applyAbsoluteNativeDeepLinks,
|
|
10158
10401
|
applyAbsoluteNativeDeviceCapabilities,
|
|
@@ -10272,5 +10515,5 @@ export {
|
|
|
10272
10515
|
writeAbsoluteMobileGithubWorkflow
|
|
10273
10516
|
};
|
|
10274
10517
|
|
|
10275
|
-
//# debugId=
|
|
10518
|
+
//# debugId=9EFFDF4D91097A2464756E2164756E21
|
|
10276
10519
|
//# sourceMappingURL=index.js.map
|