47
48
export type CallServerCallback = <A, T>(id: any, args: A) => Promise<T>;
49
50
+export type EncodeFormActionCallback = <A>(
51
+ id: any,
52
+ args: Promise<A>,
53
+) => ReactCustomFormAction;
54
+
55
export type ServerReferenceId = any;
56
57
const knownServerReferences: WeakMap<
459
return thenable;
460
}
461
457
-export function encodeFormAction(
462
+function defaultEncodeFormAction(
463
this: any => Promise<any>,
464
identifierPrefix: string,
465
): ReactCustomFormAction {
508
};
509
}
510
511
+function customEncodeFormAction(
512
+ proxy: any => Promise<any>,
513
+ identifierPrefix: string,
514
+ encodeFormAction: EncodeFormActionCallback,
515
+): ReactCustomFormAction {
516
+ const reference = knownServerReferences.get(proxy);
517
+ if (!reference) {
518
+ throw new Error(
519
+ 'Tried to encode a Server Action from a different instance than the encoder is from. ' +
520
+ 'This is a bug in React.',
521
+ );
522
+ }
523
+ let boundPromise: Promise<Array<any>> = (reference.bound: any);
524
+ if (boundPromise === null) {
525
+ boundPromise = Promise.resolve([]);
526
+ }
527
+ return encodeFormAction(reference.id, boundPromise);
528
+}
529
+
530
function isSignatureEqual(
531
this: any => Promise<any>,
532
referenceId: ServerReferenceId,
593
export function registerServerReference(
594
proxy: any,
595
reference: {id: ServerReferenceId, bound: null | Thenable<Array<any>>},
596
+ encodeFormAction: void | EncodeFormActionCallback,
597
) {
598
// Expose encoder for use by SSR, as well as a special bind that can be used to
599
// keep server capabilities.
600
if (usedWithSSR) {
601
// Only expose this in builds that would actually use it. Not needed on the client.
602
+ const $$FORM_ACTION =
603
+ encodeFormAction === undefined
604
+ ? defaultEncodeFormAction
605
+ : function (
606
+ this: any => Promise<any>,
607
+ identifierPrefix: string,
608
+ ): ReactCustomFormAction {
609
+ return customEncodeFormAction(
610
+ this,
611
+ identifierPrefix,
612
+ encodeFormAction,
613
+ );
614
+ };
615
Object.defineProperties((proxy: any), {
578
- $$FORM_ACTION: {value: encodeFormAction},
616
+ $$FORM_ACTION: {value: $$FORM_ACTION},
617
$$IS_SIGNATURE_EQUAL: {value: isSignatureEqual},
618
bind: {value: bind},
619
});
625
const FunctionBind = Function.prototype.bind;
626
// $FlowFixMe[method-unbinding]
627
const ArraySlice = Array.prototype.slice;
590
-function bind(this: Function) {
628
+function bind(this: Function): Function {
629
// $FlowFixMe[unsupported-syntax]
630
const newFn = FunctionBind.apply(this, arguments);
631
const reference = knownServerReferences.get(this);
639
} else {
640
boundPromise = Promise.resolve(args);
641
}
604
- registerServerReference(newFn, {id: reference.id, bound: boundPromise});
642
+ // Expose encoder for use by SSR, as well as a special bind that can be used to
643
+ // keep server capabilities.
644
+ if (usedWithSSR) {
645
+ // Only expose this in builds that would actually use it. Not needed on the client.
646
+ Object.defineProperties((newFn: any), {
647
+ $$FORM_ACTION: {value: this.$$FORM_ACTION},
648
+ $$IS_SIGNATURE_EQUAL: {value: isSignatureEqual},
649
+ bind: {value: bind},
650
+ });
651
+ }
652
+ knownServerReferences.set(newFn, {id: reference.id, bound: boundPromise});
653
}
654
return newFn;
655
}
657
export function createServerReference<A: Iterable<any>, T>(
658
id: ServerReferenceId,
659
callServer: CallServerCallback,
660
+ encodeFormAction?: EncodeFormActionCallback,
661
): (...A) => Promise<T> {
662
const proxy = function (): Promise<T> {
663
// $FlowFixMe[method-unbinding]
664
const args = Array.prototype.slice.call(arguments);
665
return callServer(id, args);
666
};
618
- registerServerReference(proxy, {id, bound: null});
667
+ registerServerReference(proxy, {id, bound: null}, encodeFormAction);
668
return proxy;
669
}