fix(platform): snapshot session fault errors safely
This commit is contained in:
+37
-12
@@ -19,39 +19,64 @@ export type GameSessionState =
|
||||
| 'disposing'
|
||||
| 'disposed';
|
||||
|
||||
export type GameSessionOpenFaultErrors = readonly [unknown, unknown];
|
||||
|
||||
export class GameSessionOpenFault extends Error {
|
||||
readonly errors: readonly unknown[];
|
||||
declare readonly errors: GameSessionOpenFaultErrors;
|
||||
|
||||
constructor(primary: unknown, cleanup: unknown) {
|
||||
super('Game session open failed and module cleanup also failed');
|
||||
this.name = 'GameSessionOpenFault';
|
||||
Object.defineProperty(this, GAME_SESSION_OPEN_FAULT_BRAND, { value: true });
|
||||
this.errors = Object.freeze([primary, cleanup]);
|
||||
const errors = Object.freeze([primary, cleanup] as [unknown, unknown]);
|
||||
Object.defineProperties(this, {
|
||||
[GAME_SESSION_OPEN_FAULT_BRAND]: {
|
||||
value: true,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
},
|
||||
errors: {
|
||||
value: errors,
|
||||
writable: false,
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export interface GameSessionOpenFaultShape {
|
||||
readonly errors: readonly [unknown, unknown];
|
||||
readonly errors: GameSessionOpenFaultErrors;
|
||||
}
|
||||
|
||||
/** Recognizes open faults across realms and duplicate module instances. */
|
||||
export function isGameSessionOpenFault(value: unknown): value is GameSessionOpenFaultShape {
|
||||
if (value === null || typeof value !== 'object') return false;
|
||||
/** Snapshots open-fault errors across realms and duplicate module instances. */
|
||||
export function extractGameSessionOpenFaultErrors(
|
||||
value: unknown,
|
||||
): GameSessionOpenFaultErrors | null {
|
||||
if (value === null || typeof value !== 'object') return null;
|
||||
|
||||
try {
|
||||
const brand = ownDataDescriptor(value, GAME_SESSION_OPEN_FAULT_BRAND);
|
||||
const errors = ownDataDescriptor(value, 'errors');
|
||||
if (brand?.value !== true || !errors || !Array.isArray(errors.value)) return false;
|
||||
if (brand?.value !== true || !errors || !Array.isArray(errors.value)) return null;
|
||||
|
||||
const errorList = errors.value;
|
||||
return ownDataDescriptor(errorList, 'length')?.value === 2
|
||||
&& ownDataDescriptor(errorList, '0') !== undefined
|
||||
&& ownDataDescriptor(errorList, '1') !== undefined;
|
||||
const length = ownDataDescriptor(errorList, 'length');
|
||||
const primary = ownDataDescriptor(errorList, '0');
|
||||
const cleanup = ownDataDescriptor(errorList, '1');
|
||||
if (length?.value !== 2 || !primary || !cleanup) return null;
|
||||
|
||||
return Object.freeze([primary.value, cleanup.value] as [unknown, unknown]);
|
||||
} catch {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Recognizes open faults across realms and duplicate module instances. */
|
||||
export function isGameSessionOpenFault(value: unknown): value is GameSessionOpenFaultShape {
|
||||
return extractGameSessionOpenFaultErrors(value) !== null;
|
||||
}
|
||||
|
||||
/** Validates the compile-time game identity before it reaches the runtime. */
|
||||
export function assertGameEntry(entry: GameEntry): void {
|
||||
assertNonEmptyText(entry.key, 'key');
|
||||
|
||||
Reference in New Issue
Block a user