@absolutejs/absolute 0.20.0-beta.66 → 0.20.0-beta.68
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/build.js +768 -544
- package/dist/build.js.map +10 -8
- package/dist/cli/index.js +1526 -574
- package/dist/dev/serverBootstrap.js +544 -6
- package/dist/index.js +879 -619
- package/dist/index.js.map +13 -10
- package/dist/mobile/index.js +1777 -190
- package/dist/mobile/index.js.map +9 -5
- package/dist/mobile/mobilePreviewClient.ts +246 -0
- package/dist/mobile/remoteMacAgentEntry.js +576 -205
- package/dist/mobile/shellBootstrap.js +152 -0
- package/dist/src/build/chainInlineSourcemaps.d.ts +2 -0
- package/dist/src/build/vueCompileCache.d.ts +43 -0
- package/dist/src/cli/config/server.d.ts +1 -1
- package/dist/src/dev/bootLifecycle.d.ts +11 -0
- package/dist/src/dev/earlyListener.d.ts +41 -0
- package/dist/src/mobile/expoNativeObservability.d.ts +3 -0
- package/dist/src/mobile/index.d.ts +3 -0
- package/dist/src/mobile/mobilePreview.d.ts +1 -1
- package/dist/src/mobile/nativeObservability.d.ts +4 -0
- package/dist/src/mobile/shellNativeObservability.d.ts +21 -0
- package/dist/src/plugins/imageOptimizer.d.ts +1 -1
- package/dist/src/utils/startupTimings.d.ts +4 -0
- package/dist/types/globals.d.ts +15 -0
- package/package.json +7 -7
|
@@ -6710,6 +6710,141 @@ var installAbsoluteMobileShellObservability = (manifest, engine, fetch2 = global
|
|
|
6710
6710
|
};
|
|
6711
6711
|
};
|
|
6712
6712
|
|
|
6713
|
+
// src/mobile/shellNativeObservability.ts
|
|
6714
|
+
import { Capacitor, registerPlugin } from "@capacitor/core";
|
|
6715
|
+
var MAX_REPORTS = 8;
|
|
6716
|
+
var MAX_DETAIL_BYTES = 64 * 1024;
|
|
6717
|
+
var MAX_STRING_LENGTH = 8 * 1024;
|
|
6718
|
+
var MAX_REDACTION_DEPTH = 8;
|
|
6719
|
+
var REPORT_ID = /^[A-Za-z0-9._:-]{1,128}$/u;
|
|
6720
|
+
var REPORT_KINDS = new Set([
|
|
6721
|
+
"anr",
|
|
6722
|
+
"app-launch",
|
|
6723
|
+
"cpu-exception",
|
|
6724
|
+
"crash",
|
|
6725
|
+
"disk-write-exception",
|
|
6726
|
+
"hang",
|
|
6727
|
+
"initialization-failure",
|
|
6728
|
+
"low-memory",
|
|
6729
|
+
"native-crash",
|
|
6730
|
+
"resource-exhaustion",
|
|
6731
|
+
"signal"
|
|
6732
|
+
]);
|
|
6733
|
+
var nativeObservability = registerPlugin("AbsoluteMobileObservability");
|
|
6734
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6735
|
+
var redactText = (value) => value.slice(0, MAX_STRING_LENGTH).replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/giu, "$1 [REDACTED]").replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\s]*/giu, "$1[REDACTED]").replace(/\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\s*[:=]\s*)[^,\s;]+/giu, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/gu, "[REDACTED]");
|
|
6736
|
+
var redactValue2 = (value, depth = 0) => {
|
|
6737
|
+
if (depth >= MAX_REDACTION_DEPTH)
|
|
6738
|
+
return "[TRUNCATED]";
|
|
6739
|
+
if (typeof value === "string")
|
|
6740
|
+
return redactText(value);
|
|
6741
|
+
if (value === null || typeof value === "number" || typeof value === "boolean")
|
|
6742
|
+
return value;
|
|
6743
|
+
if (Array.isArray(value))
|
|
6744
|
+
return value.slice(0, 64).map((entry) => redactValue2(entry, depth + 1));
|
|
6745
|
+
if (!isRecord3(value))
|
|
6746
|
+
return String(value).slice(0, MAX_STRING_LENGTH);
|
|
6747
|
+
return Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [
|
|
6748
|
+
key,
|
|
6749
|
+
/(?:authorization|cookie|password|secret|token)/iu.test(key) ? "[REDACTED]" : redactValue2(entry, depth + 1)
|
|
6750
|
+
]));
|
|
6751
|
+
};
|
|
6752
|
+
var parseReport = (value) => {
|
|
6753
|
+
if (!isRecord3(value) || !isRecord3(value.details))
|
|
6754
|
+
return;
|
|
6755
|
+
if (typeof value.id !== "string" || !REPORT_ID.test(value.id))
|
|
6756
|
+
return;
|
|
6757
|
+
if (typeof value.kind !== "string" || !REPORT_KINDS.has(value.kind))
|
|
6758
|
+
return;
|
|
6759
|
+
if (typeof value.occurredAt !== "number" || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0)
|
|
6760
|
+
return;
|
|
6761
|
+
if (value.platform !== "android" && value.platform !== "ios")
|
|
6762
|
+
return;
|
|
6763
|
+
const details = redactValue2(value.details);
|
|
6764
|
+
if (!isRecord3(details))
|
|
6765
|
+
return;
|
|
6766
|
+
if (new TextEncoder().encode(JSON.stringify(details)).byteLength > MAX_DETAIL_BYTES)
|
|
6767
|
+
return;
|
|
6768
|
+
return {
|
|
6769
|
+
details,
|
|
6770
|
+
id: value.id,
|
|
6771
|
+
kind: value.kind,
|
|
6772
|
+
occurredAt: value.occurredAt,
|
|
6773
|
+
platform: value.platform
|
|
6774
|
+
};
|
|
6775
|
+
};
|
|
6776
|
+
var sampled = (id, sampleRate) => {
|
|
6777
|
+
if (sampleRate >= 1)
|
|
6778
|
+
return true;
|
|
6779
|
+
let hash = 2166136261;
|
|
6780
|
+
for (const character of id) {
|
|
6781
|
+
hash ^= character.codePointAt(0) ?? 0;
|
|
6782
|
+
hash = Math.imul(hash, 16777619);
|
|
6783
|
+
}
|
|
6784
|
+
return (hash >>> 0) / 4294967296 < sampleRate;
|
|
6785
|
+
};
|
|
6786
|
+
var reportEvent = (report, manifest) => ({
|
|
6787
|
+
at: report.occurredAt,
|
|
6788
|
+
extra: {
|
|
6789
|
+
nativeDiagnostic: report.details,
|
|
6790
|
+
nativeDiagnosticId: report.id
|
|
6791
|
+
},
|
|
6792
|
+
groupingKey: `absolute-native:${report.platform}:${report.kind}`,
|
|
6793
|
+
level: [
|
|
6794
|
+
"app-launch",
|
|
6795
|
+
"cpu-exception",
|
|
6796
|
+
"disk-write-exception",
|
|
6797
|
+
"low-memory",
|
|
6798
|
+
"resource-exhaustion",
|
|
6799
|
+
"signal"
|
|
6800
|
+
].includes(report.kind) ? "warning" : "error",
|
|
6801
|
+
message: `Native process diagnostic — ${report.kind}`,
|
|
6802
|
+
name: "AbsoluteMobileNativeDiagnostic",
|
|
6803
|
+
tags: {
|
|
6804
|
+
absoluteMobile: "true",
|
|
6805
|
+
mobileAppBuild: manifest.appBuild,
|
|
6806
|
+
mobileFailurePhase: "native-process",
|
|
6807
|
+
mobileManifestFormat: String(manifest.format),
|
|
6808
|
+
mobileNativeRuntime: manifest.nativeRuntime,
|
|
6809
|
+
mobilePlatform: report.platform,
|
|
6810
|
+
mobileRuntime: manifest.runtime
|
|
6811
|
+
}
|
|
6812
|
+
});
|
|
6813
|
+
var drainAbsoluteMobileNativeObservability = async (manifest, fetch2, options = {}) => {
|
|
6814
|
+
const config = manifest.observability;
|
|
6815
|
+
if (!config || !(options.native ?? Capacitor.isNativePlatform()))
|
|
6816
|
+
return 0;
|
|
6817
|
+
const plugin = options.plugin ?? nativeObservability;
|
|
6818
|
+
const pending = await plugin.pending();
|
|
6819
|
+
const reports = pending.reports.slice(0, MAX_REPORTS).map(parseReport).filter((report) => report !== undefined);
|
|
6820
|
+
const discarded = reports.filter((report) => !sampled(report.id, config.sampleRate));
|
|
6821
|
+
if (discarded.length > 0)
|
|
6822
|
+
await plugin.acknowledge({
|
|
6823
|
+
ids: discarded.map(({ id }) => id)
|
|
6824
|
+
});
|
|
6825
|
+
const selected = reports.filter((report) => sampled(report.id, config.sampleRate));
|
|
6826
|
+
if (selected.length === 0)
|
|
6827
|
+
return 0;
|
|
6828
|
+
const envelope = {
|
|
6829
|
+
...config.environment ? { environment: config.environment } : {},
|
|
6830
|
+
events: selected.map((report) => reportEvent(report, manifest)),
|
|
6831
|
+
project: config.project,
|
|
6832
|
+
release: manifest.appBuild,
|
|
6833
|
+
v: 1
|
|
6834
|
+
};
|
|
6835
|
+
const response = await fetch2(config.endpoint, {
|
|
6836
|
+
body: JSON.stringify(envelope),
|
|
6837
|
+
headers: { "content-type": "application/json" },
|
|
6838
|
+
method: "POST"
|
|
6839
|
+
});
|
|
6840
|
+
if (!response.ok)
|
|
6841
|
+
return 0;
|
|
6842
|
+
await plugin.acknowledge({
|
|
6843
|
+
ids: selected.map(({ id }) => id)
|
|
6844
|
+
});
|
|
6845
|
+
return selected.length;
|
|
6846
|
+
};
|
|
6847
|
+
|
|
6713
6848
|
// src/mobile/shellBootstrap.ts
|
|
6714
6849
|
var MANIFEST_PATH = "./absolute-mobile-manifest.json";
|
|
6715
6850
|
var STATUS_ID = "absolute-mobile-status";
|
|
@@ -6956,6 +7091,23 @@ var startAbsoluteMobileShell = async (options = {}) => {
|
|
|
6956
7091
|
}) : undefined;
|
|
6957
7092
|
const applicationFetch = auth?.fetch ?? options.createFetch?.(manifest) ?? globalThis.fetch;
|
|
6958
7093
|
const observability = installAbsoluteMobileShellObservability(manifest, options.engine ?? "capacitor", applicationFetch);
|
|
7094
|
+
if ((options.engine ?? "capacitor") === "capacitor") {
|
|
7095
|
+
let nativeObservabilityDrain;
|
|
7096
|
+
const drainNativeObservability = () => {
|
|
7097
|
+
nativeObservabilityDrain ??= drainAbsoluteMobileNativeObservability(manifest, applicationFetch).catch(() => 0).finally(() => {
|
|
7098
|
+
nativeObservabilityDrain = undefined;
|
|
7099
|
+
});
|
|
7100
|
+
return nativeObservabilityDrain;
|
|
7101
|
+
};
|
|
7102
|
+
drainNativeObservability();
|
|
7103
|
+
addEventListener("online", () => void drainNativeObservability());
|
|
7104
|
+
App.addListener("appStateChange", ({ isActive }) => {
|
|
7105
|
+
if (isActive)
|
|
7106
|
+
drainNativeObservability();
|
|
7107
|
+
}).catch(() => {
|
|
7108
|
+
return;
|
|
7109
|
+
});
|
|
7110
|
+
}
|
|
6959
7111
|
installAbsoluteMobileShellHttp(manifest.productionOrigin, applicationFetch);
|
|
6960
7112
|
if (auth)
|
|
6961
7113
|
options.connectPush?.(auth);
|
|
@@ -10,5 +10,7 @@ export declare const inlineLineMapComment: (sourcePath: string, sourceContent: s
|
|
|
10
10
|
export declare const remapGeneratedLines: (mappings: string, lineRemap: number[]) => string;
|
|
11
11
|
export declare const chainSourcemap: (outer: SourceMap, fetchInner: (sourcePath: string) => SourceMap | null) => SourceMap;
|
|
12
12
|
export declare const chainBundleInlineSourcemap: (bundleFilePath: string) => void;
|
|
13
|
+
/** Chain every server bundle of a dev build (each bundle is independent). */
|
|
14
|
+
export declare const chainBundleInlineSourcemaps: (bundlePaths: string[]) => Promise<void>;
|
|
13
15
|
export declare const chainExternalSourcemap: (mapFilePath: string) => void;
|
|
14
16
|
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ParsedVueSpaRoute } from './parseVueSpaRoutes';
|
|
2
|
+
export type VueCompileCacheResult = {
|
|
3
|
+
clientPath: string;
|
|
4
|
+
serverPath: string;
|
|
5
|
+
cssPaths: string[];
|
|
6
|
+
cssCodes: string[];
|
|
7
|
+
tsHelperPaths: string[];
|
|
8
|
+
hmrId: string;
|
|
9
|
+
spaRoutes?: ParsedVueSpaRoute[];
|
|
10
|
+
};
|
|
11
|
+
export type VueCompileCacheEntry = {
|
|
12
|
+
key: string;
|
|
13
|
+
clientCode: string;
|
|
14
|
+
serverCode: string;
|
|
15
|
+
result: VueCompileCacheResult;
|
|
16
|
+
/** Absolute path → content hash of every file `compileScript` read
|
|
17
|
+
* while resolving imported types. Re-verified on read. */
|
|
18
|
+
typeDeps: Record<string, string>;
|
|
19
|
+
};
|
|
20
|
+
export declare const vueCompileCacheEnabled: () => boolean;
|
|
21
|
+
export declare const hashContent: (content: string) => string;
|
|
22
|
+
export declare const hashParts: (parts: readonly string[]) => string;
|
|
23
|
+
export declare const frameworkVersionForCache: () => string | null;
|
|
24
|
+
export declare const vueCompileCacheDir: (projectRoot?: string) => string;
|
|
25
|
+
/** Build the environment part of every key: anything that changes the
|
|
26
|
+
* compiler's output without changing the component's own source. */
|
|
27
|
+
export declare const vueCompileCacheFingerprint: (parts: {
|
|
28
|
+
compilerVersion: string | undefined;
|
|
29
|
+
stylePreprocessors: unknown;
|
|
30
|
+
vueRootDir: string;
|
|
31
|
+
outputDirs: {
|
|
32
|
+
client: string;
|
|
33
|
+
server: string;
|
|
34
|
+
css: string;
|
|
35
|
+
};
|
|
36
|
+
}) => string | null;
|
|
37
|
+
/** Read a cached compile for `sourceFilePath` if its key matches and every
|
|
38
|
+
* recorded type dependency is unchanged. Any I/O or shape problem is a
|
|
39
|
+
* miss — the cache can only ever make a build faster, never wrong. */
|
|
40
|
+
export declare const readVueCompileCacheEntry: (sourceFilePath: string, key: string, projectRoot?: string) => VueCompileCacheEntry | null;
|
|
41
|
+
/** Persist a compile. Written via a temp file + rename so a crash mid-write
|
|
42
|
+
* can never leave a torn entry for the next process to trust. */
|
|
43
|
+
export declare const writeVueCompileCacheEntry: (sourceFilePath: string, entry: VueCompileCacheEntry, projectRoot?: string) => void;
|
|
@@ -391,7 +391,7 @@ export declare const launchConfig: (args: string[], cwd?: string) => Promise<imp
|
|
|
391
391
|
status?: number | keyof import("elysia").StatusMap;
|
|
392
392
|
cookie?: Record<string, import("elysia").BaseCookie>;
|
|
393
393
|
};
|
|
394
|
-
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 |
|
|
394
|
+
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 503 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
|
|
395
395
|
readonly 100: "Continue";
|
|
396
396
|
readonly 101: "Switching Protocols";
|
|
397
397
|
readonly 102: "Processing";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Record which boot step is currently running so the early listener's
|
|
2
|
+
* "Building…" page can show it. Cheap enough to call from every step. */
|
|
3
|
+
export declare const getBootPhase: () => string | undefined;
|
|
4
|
+
export declare const setBootPhase: (phase: string) => void;
|
|
5
|
+
type DeferredBootTask = () => void | Promise<void>;
|
|
6
|
+
/** Run every task queued by `deferUntilServing`. Called by the
|
|
7
|
+
* `networking` plugin once the real server is bound, so the work runs
|
|
8
|
+
* after the port is serving real traffic instead of delaying it. */
|
|
9
|
+
export declare const deferUntilServing: (task: DeferredBootTask) => void;
|
|
10
|
+
export declare const runDeferredBootTasks: () => void;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Server } from 'bun';
|
|
2
|
+
export declare const BOOT_STATUS_HEADER = "X-Absolute-Boot";
|
|
3
|
+
export type EarlyListenerOptions = {
|
|
4
|
+
host: string;
|
|
5
|
+
port: number;
|
|
6
|
+
tls?: {
|
|
7
|
+
cert: string;
|
|
8
|
+
key: string;
|
|
9
|
+
} | null;
|
|
10
|
+
};
|
|
11
|
+
export type EarlyListener = {
|
|
12
|
+
/** The placeholder server, or null while a bind retry is pending or
|
|
13
|
+
* after release. */
|
|
14
|
+
readonly server: Server<undefined> | null;
|
|
15
|
+
readonly startedAt: number;
|
|
16
|
+
readonly released: boolean;
|
|
17
|
+
release: () => void;
|
|
18
|
+
};
|
|
19
|
+
export declare const bootStatusSnapshot: (startedAt: number) => {
|
|
20
|
+
elapsedMs: number;
|
|
21
|
+
elapsedSeconds: number;
|
|
22
|
+
phase: string;
|
|
23
|
+
status: "building";
|
|
24
|
+
};
|
|
25
|
+
/** 503 response for one request while the boot build is still running.
|
|
26
|
+
* HTML for browsers (`Accept: text/html`), JSON for JSON clients, plain
|
|
27
|
+
* text otherwise; WebSocket upgrade attempts (the HMR client) get a plain
|
|
28
|
+
* 503 instead of an upgrade so they fail the handshake cleanly and fall
|
|
29
|
+
* back to their `/hmr-status` polling loop. */
|
|
30
|
+
export declare const buildingResponse: (request: Request, startedAt: number) => Response;
|
|
31
|
+
/** Defensive hand-off for entries that call `.listen()` without the
|
|
32
|
+
* `networking` plugin: any `Bun.serve` that targets the placeholder's
|
|
33
|
+
* port first releases it. Installed once per process by the bootstrap. */
|
|
34
|
+
export declare const installEarlyListenerServeGuard: (port: number) => void;
|
|
35
|
+
export declare const releaseEarlyListener: () => boolean;
|
|
36
|
+
/** Bind the placeholder. A failed bind (the previous child's socket is
|
|
37
|
+
* still draining, or the port genuinely conflicts) is retried in the
|
|
38
|
+
* background for a few seconds and then given up on silently — the real
|
|
39
|
+
* `.listen()` still reports the conflict the way it always did. Never
|
|
40
|
+
* throws: the placeholder is a nicety and must not break boot. */
|
|
41
|
+
export declare const startEarlyListener: (options: EarlyListenerOptions) => EarlyListener;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const expoNativeObservabilityRuntimeSource = "// Generated by AbsoluteJS. Edit absolute.config.ts, then run absolute mobile sync.\nimport { requireNativeModule } from 'expo';\nimport { AppState, Platform } from 'react-native';\nimport { ABSOLUTE_MOBILE_MANIFEST } from './webAssets';\n\ntype NativeObservabilityModule = {\n\tacknowledge(options: { ids: string[] }): Promise<void>;\n\tpending(): Promise<{ reports: unknown[] }>;\n};\ntype NativeReport = { details: Record<string, unknown>; id: string; kind: string; occurredAt: number; platform: 'android' | 'ios' };\nconst native = requireNativeModule<NativeObservabilityModule>('AbsoluteMobileObservability');\nconst KINDS = new Set(['anr', 'app-launch', 'cpu-exception', 'crash', 'disk-write-exception', 'hang', 'initialization-failure', 'low-memory', 'native-crash', 'resource-exhaustion', 'signal']);\nconst ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null && !Array.isArray(value);\nconst redactText = (value: string) => value.slice(0, 8192)\n\t.replace(/\\b(Bearer)\\s+[A-Za-z0-9._~+/-]+=*/gi, '$1 [REDACTED]')\n\t.replace(/([?&](?:access_token|api_?key|authorization|code|id_token|password|refresh_token|secret|token)=)[^&#\\s]*/gi, '$1[REDACTED]')\n\t.replace(/\\b((?:access_?token|api_?key|authorization|client_?secret|cookie|id_?token|password|passwd|refresh_?token|secret|token)\\s*[:=]\\s*)[^,\\s;]+/gi, '$1[REDACTED]')\n\t.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/g, '[REDACTED]');\nconst redact = (value: unknown, depth = 0): unknown => {\n\tif (depth >= 8) return '[TRUNCATED]';\n\tif (typeof value === 'string') return redactText(value);\n\tif (value === null || typeof value === 'number' || typeof value === 'boolean') return value;\n\tif (Array.isArray(value)) return value.slice(0, 64).map(entry => redact(entry, depth + 1));\n\tif (!isRecord(value)) return String(value).slice(0, 8192);\n\treturn Object.fromEntries(Object.entries(value).slice(0, 128).map(([key, entry]) => [key, /(?:authorization|cookie|password|secret|token)/i.test(key) ? '[REDACTED]' : redact(entry, depth + 1)]));\n};\nconst parse = (value: unknown): NativeReport | undefined => {\n\tif (!isRecord(value) || !isRecord(value.details) || typeof value.id !== 'string' || !ID.test(value.id) || typeof value.kind !== 'string' || !KINDS.has(value.kind) || typeof value.occurredAt !== 'number' || !Number.isFinite(value.occurredAt) || value.occurredAt <= 0 || value.platform !== 'android' && value.platform !== 'ios') return;\n\tconst details = redact(value.details);\n\tif (!isRecord(details) || new TextEncoder().encode(JSON.stringify(details)).byteLength > 64 * 1024) return;\n\treturn { details, id: value.id, kind: value.kind, occurredAt: value.occurredAt, platform: value.platform };\n};\nconst sampled = (id: string, rate: number) => {\n\tif (rate >= 1) return true;\n\tlet hash = 2166136261;\n\tfor (const character of id) { hash ^= character.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }\n\treturn (hash >>> 0) / 4294967296 < rate;\n};\nlet drainPromise: Promise<void> | undefined;\nlet started = false;\nconst drain = () => {\n\tdrainPromise ??= (async () => {\n\t\tconst manifest = ABSOLUTE_MOBILE_MANIFEST;\n\t\tconst config = manifest?.observability;\n\t\tif (!manifest || !config || Platform.OS !== 'android' && Platform.OS !== 'ios') return;\n\t\tconst reports = (await native.pending()).reports.slice(0, 8).map(parse).filter((report): report is NativeReport => report !== undefined);\n\t\tconst discarded = reports.filter(report => !sampled(report.id, config.sampleRate));\n\t\tif (discarded.length) await native.acknowledge({ ids: discarded.map(report => report.id) });\n\t\tconst selected = reports.filter(report => sampled(report.id, config.sampleRate));\n\t\tif (!selected.length) return;\n\t\tconst response = await fetch(config.endpoint, {\n\t\t\tbody: JSON.stringify({ ...(config.environment ? { environment: config.environment } : {}), events: selected.map(report => ({ at: report.occurredAt, extra: { nativeDiagnostic: report.details, nativeDiagnosticId: report.id }, groupingKey: 'absolute-native:' + report.platform + ':' + report.kind, level: ['app-launch', 'cpu-exception', 'disk-write-exception', 'low-memory', 'resource-exhaustion', 'signal'].includes(report.kind) ? 'warning' : 'error', message: 'Native process diagnostic \u2014 ' + report.kind, name: 'AbsoluteMobileNativeDiagnostic', tags: { absoluteMobile: 'true', mobileAppBuild: manifest.appBuild, mobileEngine: 'expo', mobileFailurePhase: 'native-process', mobileManifestFormat: '1', mobileNativeRuntime: 'expo', mobilePlatform: report.platform, mobileRuntime: manifest.runtime } })), project: config.project, release: manifest.appBuild, v: 1 }),\n\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\tmethod: 'POST'\n\t\t});\n\t\tif (response.ok) await native.acknowledge({ ids: selected.map(report => report.id) });\n\t})().catch(() => undefined).finally(() => { drainPromise = undefined; });\n\treturn drainPromise;\n};\nexport const startAbsoluteExpoNativeObservability = () => {\n\tif (!started) {\n\t\tstarted = true;\n\t\tAppState.addEventListener('change', state => { if (state === 'active') void drain(); });\n\t}\n\treturn drain();\n};\n";
|
|
2
|
+
export declare const absoluteExpoNativeObservabilityFiles: (project: string) => Map<string, string>;
|
|
3
|
+
export declare const absoluteExpoNativeObservabilityPaths: (project: string) => string[];
|
|
@@ -21,6 +21,7 @@ export * from './expoBridge';
|
|
|
21
21
|
export * from './expoCodeSigning';
|
|
22
22
|
export * from './expoDevController';
|
|
23
23
|
export * from './expoProject';
|
|
24
|
+
export * from './expoNativeObservability';
|
|
24
25
|
export * from './expoUpdate';
|
|
25
26
|
export * from './capacitorProject';
|
|
26
27
|
export * from './config';
|
|
@@ -34,6 +35,7 @@ export * from './nativeDeviceCapabilities';
|
|
|
34
35
|
export * from './nativeAuth';
|
|
35
36
|
export * from './nativeRoute';
|
|
36
37
|
export * from './nativeUpdates';
|
|
38
|
+
export * from './nativeObservability';
|
|
37
39
|
export * from './pageProtocol';
|
|
38
40
|
export * from './producerContext';
|
|
39
41
|
export * from './releaseArtifact';
|
|
@@ -41,6 +43,7 @@ export * from './releasePublisher';
|
|
|
41
43
|
export * from './routeMetadataTransform';
|
|
42
44
|
export * from './routeMatcher';
|
|
43
45
|
export * from './shellHttp';
|
|
46
|
+
export * from './shellNativeObservability';
|
|
44
47
|
export * from './shellObservability';
|
|
45
48
|
export * from './transport';
|
|
46
49
|
export * from './uiPrimitives';
|
|
@@ -36,7 +36,7 @@ export declare const createAbsoluteMobilePreviewPlugin: (mobile: MobileConfig |
|
|
|
36
36
|
status?: number | keyof import("elysia").StatusMap;
|
|
37
37
|
cookie?: Record<string, import("elysia").BaseCookie>;
|
|
38
38
|
};
|
|
39
|
-
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 |
|
|
39
|
+
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 503 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
|
|
40
40
|
readonly 100: "Continue";
|
|
41
41
|
readonly 101: "Switching Protocols";
|
|
42
42
|
readonly 102: "Processing";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AbsoluteMobileClientManifest, AbsoluteMobileFetch } from './transport';
|
|
2
|
+
export type AbsoluteMobileNativeDiagnostic = {
|
|
3
|
+
details: Record<string, unknown>;
|
|
4
|
+
id: string;
|
|
5
|
+
kind: string;
|
|
6
|
+
occurredAt: number;
|
|
7
|
+
platform: 'android' | 'ios';
|
|
8
|
+
};
|
|
9
|
+
export type AbsoluteMobileNativeObservabilityPlugin = {
|
|
10
|
+
acknowledge(options: {
|
|
11
|
+
ids: string[];
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
pending(): Promise<{
|
|
14
|
+
reports: unknown[];
|
|
15
|
+
}>;
|
|
16
|
+
};
|
|
17
|
+
export type AbsoluteMobileNativeObservabilityDrainOptions = {
|
|
18
|
+
native?: boolean;
|
|
19
|
+
plugin?: AbsoluteMobileNativeObservabilityPlugin;
|
|
20
|
+
};
|
|
21
|
+
export declare const drainAbsoluteMobileNativeObservability: (manifest: AbsoluteMobileClientManifest, fetch: AbsoluteMobileFetch, options?: AbsoluteMobileNativeObservabilityDrainOptions) => Promise<number>;
|
|
@@ -19,7 +19,7 @@ export declare const imageOptimizer: (config: ImageConfig | undefined, buildDir:
|
|
|
19
19
|
status?: number | keyof import("elysia").StatusMap;
|
|
20
20
|
cookie?: Record<string, import("elysia").BaseCookie>;
|
|
21
21
|
};
|
|
22
|
-
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 |
|
|
22
|
+
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 304 | 503 | 426 | 204 | 101 | 102 | 103 | 201 | 202 | 203 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 428 | 429 | 431 | 451 | 501 | 502 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
|
|
23
23
|
readonly 100: "Continue";
|
|
24
24
|
readonly 101: "Switching Protocols";
|
|
25
25
|
readonly 102: "Processing";
|
|
@@ -2,6 +2,10 @@ export type StartupTimingStep = {
|
|
|
2
2
|
label: string;
|
|
3
3
|
durationMs: number;
|
|
4
4
|
};
|
|
5
|
+
/** `ABSOLUTE_DEV_PROFILE=1` is the one-stop profiling switch: it turns on
|
|
6
|
+
* these per-step startup timings AND the per-phase build trace
|
|
7
|
+
* (`ABSOLUTE_BUILD_TRACE`, written to `<buildDir>/.absolute-trace/`). */
|
|
8
|
+
export declare const devProfileEnabled: boolean;
|
|
5
9
|
export declare const startupTimingsEnabled: boolean;
|
|
6
10
|
export declare const formatStartupTimingBlock: (title: string, steps: StartupTimingStep[]) => string;
|
|
7
11
|
export declare const logStartupTimingBlock: (title: string, steps: StartupTimingStep[]) => void;
|
package/dist/types/globals.d.ts
CHANGED
|
@@ -46,6 +46,21 @@ declare global {
|
|
|
46
46
|
* detect this and call `.reload({ fetch })` on the existing server
|
|
47
47
|
* instead of re-binding the port. Stays unset outside dev. */
|
|
48
48
|
var __absoluteBunServer: import('bun').Server | null | undefined;
|
|
49
|
+
/** "Building…" placeholder bound by the dev bootstrap before the entry
|
|
50
|
+
* is imported; released by `networking` right before the real listen.
|
|
51
|
+
* See `src/dev/earlyListener.ts`. */
|
|
52
|
+
var __absoluteEarlyListener:
|
|
53
|
+
| import('../src/dev/earlyListener').EarlyListener
|
|
54
|
+
| undefined;
|
|
55
|
+
var __absoluteEarlyListenerServeGuard: boolean | undefined;
|
|
56
|
+
/** Label of the boot step currently running (shown on the placeholder
|
|
57
|
+
* page). See `src/dev/bootLifecycle.ts`. */
|
|
58
|
+
var __absoluteBootPhase: string | undefined;
|
|
59
|
+
/** Boot work deferred until the server is serving real traffic. */
|
|
60
|
+
var __absoluteDeferredBootTasks:
|
|
61
|
+
| Array<() => void | Promise<void>>
|
|
62
|
+
| undefined;
|
|
63
|
+
var __absoluteDeferredBootTasksRan: boolean | undefined;
|
|
49
64
|
|
|
50
65
|
/** Dev-only request inspector ring buffer, filled by the global
|
|
51
66
|
* request/afterResponse hooks in `requestInspector` and served at
|
package/package.json
CHANGED
|
@@ -296,12 +296,12 @@
|
|
|
296
296
|
"main": "./dist/index.js",
|
|
297
297
|
"name": "@absolutejs/absolute",
|
|
298
298
|
"optionalDependencies": {
|
|
299
|
-
"@absolutejs/native-darwin-arm64": "0.20.0-beta.
|
|
300
|
-
"@absolutejs/native-darwin-x64": "0.20.0-beta.
|
|
301
|
-
"@absolutejs/native-linux-arm64": "0.20.0-beta.
|
|
302
|
-
"@absolutejs/native-linux-x64": "0.20.0-beta.
|
|
303
|
-
"@absolutejs/native-windows-arm64": "0.20.0-beta.
|
|
304
|
-
"@absolutejs/native-windows-x64": "0.20.0-beta.
|
|
299
|
+
"@absolutejs/native-darwin-arm64": "0.20.0-beta.68",
|
|
300
|
+
"@absolutejs/native-darwin-x64": "0.20.0-beta.68",
|
|
301
|
+
"@absolutejs/native-linux-arm64": "0.20.0-beta.68",
|
|
302
|
+
"@absolutejs/native-linux-x64": "0.20.0-beta.68",
|
|
303
|
+
"@absolutejs/native-windows-arm64": "0.20.0-beta.68",
|
|
304
|
+
"@absolutejs/native-windows-x64": "0.20.0-beta.68"
|
|
305
305
|
},
|
|
306
306
|
"overrides": {
|
|
307
307
|
"@sinclair/typebox": "0.34.52",
|
|
@@ -519,7 +519,7 @@
|
|
|
519
519
|
]
|
|
520
520
|
}
|
|
521
521
|
},
|
|
522
|
-
"version": "0.20.0-beta.
|
|
522
|
+
"version": "0.20.0-beta.68",
|
|
523
523
|
"workspaces": [
|
|
524
524
|
"tests/fixtures/*",
|
|
525
525
|
"tests/fixtures/_packages/*"
|