mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
- References are Ref<C> (was Handle<C>), objects ObjectImpl (record.ts is object.ts), ImplementationOf<C> (was
BehaviorOf<C>), ResourceDeclaration (was ResourceSpec); epochs are code versions (codeVersion in Ctx, RootOptions,
Shape, Host, frames and reload reports). Docs say object and reference.
- A remote object's variant is named variant (was kind): factories return { variant }, references expose ref.variant.
- Links announce a protocol version (PROTOCOL_VERSION = 2) in hello; peers of different versions close the link with
reason protocol-version <n> and report it through LinkOptions.onProtocolMismatch.
- ServeOptions.lifetime ("referenced" | "host") replaces eager: a host-lifetime object is local, has an empty input,
exists once per host and lives until the host closes; awaitEager is awaitHostObjects. A reload that makes a type
referenced releases the host's own reference.
76 lines
2.6 KiB
TypeScript
76 lines
2.6 KiB
TypeScript
/** Error codes callers see (guide table). A refused or aborted reload keeps the code of its cause. */
|
|
export const CHORD_ERROR_CODES = [
|
|
"aborted",
|
|
"contract_mismatch",
|
|
"forbidden",
|
|
"gone",
|
|
"invalid",
|
|
"not_in_variant",
|
|
"not_ready",
|
|
"released",
|
|
"superseded",
|
|
"unavailable",
|
|
"upgrade_conflict",
|
|
"upgrade_required",
|
|
] as const;
|
|
export type ChordErrorCode = (typeof CHORD_ERROR_CODES)[number];
|
|
|
|
/**
|
|
* Finer cause inside a code, for logs and tests: e.g. `invalid` + `args`, `result`, `state`, `input`, `implementation`,
|
|
* `duplicate`, `cycle`, `read_only`, `not_host_lifetime`, `registry_conflict`; `unavailable` + `unknown_type`.
|
|
*/
|
|
export type ChordErrorReason = string;
|
|
|
|
const RETRYABLE: ReadonlySet<ChordErrorCode> = new Set(["superseded", "upgrade_conflict"]);
|
|
|
|
export class ChordError extends Error {
|
|
readonly code: ChordErrorCode;
|
|
readonly reason: ChordErrorReason | undefined;
|
|
readonly retryable: boolean;
|
|
readonly details: unknown;
|
|
constructor(
|
|
code: ChordErrorCode,
|
|
message: string,
|
|
options?: { cause?: unknown; details?: unknown; reason?: ChordErrorReason },
|
|
) {
|
|
super(`${code}${options?.reason ? `/${options.reason}` : ""}: ${message}`, {
|
|
cause: options?.cause,
|
|
});
|
|
this.name = "ChordError";
|
|
this.code = code;
|
|
this.reason = options?.reason;
|
|
this.retryable = RETRYABLE.has(code);
|
|
this.details = options?.details;
|
|
}
|
|
}
|
|
|
|
export const isChordError = (error: unknown, code?: ChordErrorCode): error is ChordError =>
|
|
error instanceof ChordError && (code === undefined || error.code === code);
|
|
|
|
/** For factories and methods refusing a principal: `throw forbidden()`. */
|
|
export const forbidden = (message = "forbidden"): ChordError => new ChordError("forbidden", message);
|
|
|
|
export const invalid = (reason: ChordErrorReason, message: string, details?: unknown): ChordError =>
|
|
new ChordError("invalid", message, { reason, details });
|
|
|
|
/** Keeps a ChordError's code; anything else becomes `unavailable` with the original as cause. */
|
|
export const asChordError = (error: unknown, context: string): ChordError =>
|
|
error instanceof ChordError
|
|
? error
|
|
: new ChordError("unavailable", `${context}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
cause: error,
|
|
});
|
|
|
|
/** Runs every step, then throws one error, or an AggregateError when several failed. */
|
|
export async function runAll(steps: readonly (() => unknown)[], message: string): Promise<void> {
|
|
const errors: unknown[] = [];
|
|
for (const step of steps) {
|
|
try {
|
|
await step();
|
|
} catch (error) {
|
|
errors.push(error);
|
|
}
|
|
}
|
|
if (errors.length === 1) throw errors[0];
|
|
if (errors.length > 1) throw new AggregateError(errors, message);
|
|
}
|