const TEMPORARY_REFERENCE_TAG = Symbol.for('react.temporary.reference');
export opaque type TemporaryReference<T> = {
$$typeof: symbol,
$$id: string,
};
export function isTemporaryReference(reference: Object): boolean {
return reference.$$typeof === TEMPORARY_REFERENCE_TAG;
}
export function resolveTemporaryReferenceID<T>(
temporaryReference: TemporaryReference<T>,
): string {
return temporaryReference.$$id;
}
const proxyHandlers = {
get: function (
target: Function,
name: string | symbol,
receiver: Proxy<Function>,
) {
switch (name) {
case '$$typeof':
return target.$$typeof;
case '$$id':
return target.$$id;
case '$$async':
return target.$$async;
case 'name':
return undefined;
case 'displayName':
return undefined;
case 'defaultProps':
return undefined;
case 'toJSON':
return undefined;
case Symbol.toPrimitive:
return Object.prototype[Symbol.toPrimitive];
case Symbol.toStringTag:
return Object.prototype[Symbol.toStringTag];
case 'Provider':
throw new Error(
`Cannot render a Client Context Provider on the Server. ` +
`Instead, you can export a Client Component wrapper ` +
`that itself renders a Client Context Provider.`,
);
}
throw new Error(
`Cannot access ${String(name)} on the server. ` +
'You cannot dot into a temporary client reference from a server component. ' +
'You can only pass the value through to the client.',
);
},
set: function () {
throw new Error(
'Cannot assign to a temporary client reference from a server module.',
);
},
};
export function createTemporaryReference<T>(id: string): TemporaryReference<T> {
const reference: TemporaryReference<any> = Object.defineProperties(
(function () {
throw new Error(
`Attempted to call a temporary Client Reference from the server but it is on the client. ` +
`It's not possible to invoke a client function from the server, it can ` +
`only be rendered as a Component or passed to props of a Client Component.`,
);
}: any),
{
$$typeof: {value: TEMPORARY_REFERENCE_TAG},
$$id: {value: id},
},
);
return new Proxy(reference, proxyHandlers);
}