Files

47 lines
1.8 KiB
JavaScript

/** Opaque runtime identity. The wire codec, never ordinary package state, owns
* the raw ID. These handles do not themselves confer authority or a lease. */
const identities = new WeakMap();
class Reference {
constructor(id) {
identities.set(this, id);
Object.freeze(this);
}
equals(other) {
return isObjectReference(other) && identities.get(this) === identities.get(other);
}
toJSON() {
throw new Error("Object references cannot be serialized into ordinary data");
}
toString() {
throw new Error("Object references cannot be coerced to strings");
}
[Symbol.toPrimitive]() {
throw new Error("Object references cannot be coerced to scalar values");
}
}
export const isObjectReference = (value) => typeof value === "object" && value !== null && identities.has(value);
/** Internal transport boundary; intentionally not exported from the SDK entry. */
export const referenceFromWire = (id) => {
if (typeof id !== "string" || !id)
throw new Error("Missing object reference identity");
return new Reference(id);
};
export const referenceToWire = (value) => {
if (!isObjectReference(value))
throw new Error("Expected an opaque object reference, not a raw ID");
return identities.get(value);
};
export const assertReferenceFree = (value, seen = new Set()) => {
if (!value || typeof value !== "object")
return;
if (isObjectReference(value))
throw new Error("Managed references belong in declared RPC references or graph relationships, not ordinary state/messages");
if (seen.has(value))
throw new Error("Cyclic ordinary data");
seen.add(value);
if (!(value instanceof Uint8Array))
for (const child of Object.values(value))
assertReferenceFree(child, seen);
seen.delete(value);
};