47 lines
1.8 KiB
JavaScript
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);
|
|
};
|