foldkit-remote 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/dist/{index-eVkkbhPA.d.mts → index-86gaaCWm.d.mts} +86 -36
- package/dist/index-86gaaCWm.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/port.d.mts +1 -1
- package/dist/port.mjs +1 -1
- package/dist/{src-oVKXbiTu.mjs → src-Cp71fJac.mjs} +122 -24
- package/dist/src-Cp71fJac.mjs.map +1 -0
- package/package.json +4 -4
- package/dist/index-eVkkbhPA.d.mts.map +0 -1
- package/dist/src-oVKXbiTu.mjs.map +0 -1
|
@@ -740,6 +740,16 @@ var RemoteForbidden = class extends Schema.TaggedError()("Forbidden", {
|
|
|
740
740
|
message: Schema.String,
|
|
741
741
|
reason: Schema.optional(Schema.String)
|
|
742
742
|
}) {};
|
|
743
|
+
/**
|
|
744
|
+
* The server could not tell who is asking: a credential was sent and no
|
|
745
|
+
* longer holds, or none was sent where one is needed. Asking again as the
|
|
746
|
+
* same caller is refused again; signing in again is the remedy. `reason` is
|
|
747
|
+
* words for the person who asked; without it the refusal says nothing of why.
|
|
748
|
+
*/
|
|
749
|
+
var RemoteUnauthenticated = class extends Schema.TaggedError()("Unauthenticated", {
|
|
750
|
+
message: Schema.String,
|
|
751
|
+
reason: Schema.optional(Schema.String)
|
|
752
|
+
}) {};
|
|
743
753
|
var RemoteLiveError = class extends Schema.TaggedError()("RemoteLiveError", { message: Schema.String }) {};
|
|
744
754
|
/** The peer speaks another protocol version; nothing was read. */
|
|
745
755
|
var RemoteProtocolError = class extends Schema.TaggedError()("RemoteProtocolError", {
|
|
@@ -894,17 +904,29 @@ const LiveChange = Schema.Union([
|
|
|
894
904
|
const Read = Rpc.make("FoldkitRemoteRead", {
|
|
895
905
|
payload: ReadBatch,
|
|
896
906
|
success: ReadBatchResult,
|
|
897
|
-
error: Schema.Union([
|
|
907
|
+
error: Schema.Union([
|
|
908
|
+
RemoteReadError,
|
|
909
|
+
RemoteProtocolError,
|
|
910
|
+
RemoteUnauthenticated
|
|
911
|
+
])
|
|
898
912
|
});
|
|
899
913
|
const Mutate = Rpc.make("FoldkitRemoteMutate", {
|
|
900
914
|
payload: MutationRequest,
|
|
901
915
|
success: MutationResult,
|
|
902
|
-
error: Schema.Union([
|
|
916
|
+
error: Schema.Union([
|
|
917
|
+
RemoteMutationError,
|
|
918
|
+
RemoteForbidden,
|
|
919
|
+
RemoteUnauthenticated
|
|
920
|
+
])
|
|
903
921
|
});
|
|
904
922
|
const Live = Rpc.make("FoldkitRemoteLive", {
|
|
905
923
|
payload: LiveRequirement,
|
|
906
924
|
success: LiveChange,
|
|
907
|
-
error: Schema.Union([
|
|
925
|
+
error: Schema.Union([
|
|
926
|
+
RemoteLiveError,
|
|
927
|
+
RemoteProtocolError,
|
|
928
|
+
RemoteUnauthenticated
|
|
929
|
+
]),
|
|
908
930
|
stream: true
|
|
909
931
|
});
|
|
910
932
|
var RemoteQueryError = class extends Schema.TaggedError()("RemoteQueryError", { message: Schema.String }) {};
|
|
@@ -947,7 +969,7 @@ const QueryResult = Schema.Struct({
|
|
|
947
969
|
const QueryRpc = Rpc.make("FoldkitRemoteQuery", {
|
|
948
970
|
payload: QueryRequest,
|
|
949
971
|
success: QueryResult,
|
|
950
|
-
error: RemoteQueryError
|
|
972
|
+
error: Schema.Union([RemoteQueryError, RemoteUnauthenticated])
|
|
951
973
|
});
|
|
952
974
|
const RemoteRpc = RpcGroup.make(Read, Mutate, QueryRpc, Live);
|
|
953
975
|
//#endregion
|
|
@@ -2686,6 +2708,23 @@ const RemotePersistence = {
|
|
|
2686
2708
|
//#endregion
|
|
2687
2709
|
//#region src/remoteData.ts
|
|
2688
2710
|
/** `RemoteData`: the state of a value the store may not hold yet. */
|
|
2711
|
+
/**
|
|
2712
|
+
* The server would not answer who is asking: their session ended or was
|
|
2713
|
+
* never there (`Unauthenticated`, a 401), or they may not (`Forbidden`, a
|
|
2714
|
+
* 403). `reason` is the server's sentence, when it gave one. Not a mutation's
|
|
2715
|
+
* declared `refusal`, which the server answered and `Data.refusal` reads.
|
|
2716
|
+
*/
|
|
2717
|
+
const Denied = defineTaggedUnion({
|
|
2718
|
+
Unauthenticated: { reason: Schema.Option(Schema.String) },
|
|
2719
|
+
Forbidden: { reason: Schema.Option(Schema.String) }
|
|
2720
|
+
});
|
|
2721
|
+
/** The tags `denied` reads: a `RemoteError`'s `_tag` is open, for any failure a transport reports. */
|
|
2722
|
+
const denials = /* @__PURE__ */ new Set(["Unauthenticated", "Forbidden"]);
|
|
2723
|
+
const isDenial = (tag) => denials.has(tag);
|
|
2724
|
+
const deny = {
|
|
2725
|
+
Unauthenticated: Denied.Unauthenticated,
|
|
2726
|
+
Forbidden: Denied.Forbidden
|
|
2727
|
+
};
|
|
2689
2728
|
const fresh = { _tag: "Fresh" };
|
|
2690
2729
|
const refreshing = { _tag: "Refreshing" };
|
|
2691
2730
|
const remoteErrorSchema = Schema.Struct({
|
|
@@ -2786,6 +2825,19 @@ const RemoteData = {
|
|
|
2786
2825
|
});
|
|
2787
2826
|
}
|
|
2788
2827
|
},
|
|
2828
|
+
/**
|
|
2829
|
+
* The denial a failure was, typed, or none for any other failure (a
|
|
2830
|
+
* network error, a protocol mismatch): what to read before telling a reader
|
|
2831
|
+
* to sign in again.
|
|
2832
|
+
*
|
|
2833
|
+
* ```ts
|
|
2834
|
+
* Option.match(RemoteData.denied(error), {
|
|
2835
|
+
* onNone: () => 'Could not load',
|
|
2836
|
+
* onSome: Denied.match({ Unauthenticated: () => 'Sign in again', Forbidden: () => 'Not yours' }),
|
|
2837
|
+
* })
|
|
2838
|
+
* ```
|
|
2839
|
+
*/
|
|
2840
|
+
denied: (error) => isDenial(error._tag) ? Option.some(deny[error._tag]({ reason: Option.fromUndefinedOr(error.reason) })) : Option.none(),
|
|
2789
2841
|
map: (data, f) => {
|
|
2790
2842
|
switch (data._tag) {
|
|
2791
2843
|
case "Ready": return {
|
|
@@ -3965,7 +4017,9 @@ const RemoteJsonAnswer = Schema.Union([Schema.Struct({ result: Schema.Unknown })
|
|
|
3965
4017
|
error: Schema.String,
|
|
3966
4018
|
refusal: Schema.optional(Schema.Unknown),
|
|
3967
4019
|
/** Who is asking was refused, with the application's reason when it gave one. */
|
|
3968
|
-
forbidden: Schema.optional(Schema.Struct({ reason: Schema.optional(Schema.String) }))
|
|
4020
|
+
forbidden: Schema.optional(Schema.Struct({ reason: Schema.optional(Schema.String) })),
|
|
4021
|
+
/** Who is asking could not be told, with the reason when one was given; a 401. */
|
|
4022
|
+
unauthenticated: Schema.optional(Schema.Struct({ reason: Schema.optional(Schema.String) }))
|
|
3969
4023
|
})]);
|
|
3970
4024
|
const decodeAnswer = Schema.decodeUnknownEffect(RemoteJsonAnswer);
|
|
3971
4025
|
const call = (send, operation, payload, fail) => Effect.tryPromise({
|
|
@@ -3975,26 +4029,57 @@ const call = (send, operation, payload, fail) => Effect.tryPromise({
|
|
|
3975
4029
|
})),
|
|
3976
4030
|
catch: (error) => fail({ error: error instanceof Error ? error.message : String(error) })
|
|
3977
4031
|
}).pipe(Effect.flatMap((answer) => decodeAnswer(answer).pipe(Effect.mapError(() => fail({ error: "The server answered with something that is not an answer" })))), Effect.flatMap((answer) => "error" in answer ? Effect.fail(fail(answer)) : Effect.succeed(answer.result)));
|
|
4032
|
+
/**
|
|
4033
|
+
* An error answer as its call's failure: a refusal of who is asking, of
|
|
4034
|
+
* every call kind alike, or the call's own error.
|
|
4035
|
+
*/
|
|
4036
|
+
const failure = (own) => (answer) => answer.unauthenticated === void 0 ? own(answer) : new RemoteUnauthenticated({
|
|
4037
|
+
message: answer.error,
|
|
4038
|
+
...answer.unauthenticated.reason === void 0 ? {} : { reason: answer.unauthenticated.reason }
|
|
4039
|
+
});
|
|
3978
4040
|
/** Remote's client over `send`, for `Remote.clientLayer`. */
|
|
3979
4041
|
const json = (send) => ({
|
|
3980
|
-
FoldkitRemoteRead: (payload) => call(send, "read", payload, ({ error }) => new RemoteReadError({ message: error })),
|
|
3981
|
-
FoldkitRemoteQuery: (payload) => call(send, "query", payload, ({ error }) => new RemoteQueryError({ message: error })),
|
|
3982
|
-
FoldkitRemoteMutate: (payload) => call(send, "mutate", payload, ({ error, refusal, forbidden }) => forbidden === void 0 ? new RemoteMutationError({
|
|
4042
|
+
FoldkitRemoteRead: (payload) => call(send, "read", payload, failure(({ error }) => new RemoteReadError({ message: error }))),
|
|
4043
|
+
FoldkitRemoteQuery: (payload) => call(send, "query", payload, failure(({ error }) => new RemoteQueryError({ message: error }))),
|
|
4044
|
+
FoldkitRemoteMutate: (payload) => call(send, "mutate", payload, failure(({ error, refusal, forbidden }) => forbidden === void 0 ? new RemoteMutationError({
|
|
3983
4045
|
message: error,
|
|
3984
4046
|
refusal
|
|
3985
4047
|
}) : new RemoteForbidden({
|
|
3986
4048
|
message: error,
|
|
3987
4049
|
...forbidden.reason === void 0 ? {} : { reason: forbidden.reason }
|
|
3988
|
-
})),
|
|
4050
|
+
}))),
|
|
3989
4051
|
FoldkitRemoteLive: () => Stream.empty
|
|
3990
4052
|
});
|
|
3991
4053
|
/** A body that did not parse, told apart from every value one can parse to, `null` included. */
|
|
3992
4054
|
const notJson = Symbol("not JSON");
|
|
4055
|
+
const Reason = Schema.Struct({ reason: Schema.optional(Schema.String) });
|
|
4056
|
+
/** A refusal in Remote's own words, by the key it is given under. */
|
|
4057
|
+
const ownRefusal = {
|
|
4058
|
+
unauthenticated: Schema.decodeUnknownOption(Schema.Struct({
|
|
4059
|
+
error: Schema.String,
|
|
4060
|
+
unauthenticated: Reason
|
|
4061
|
+
})),
|
|
4062
|
+
forbidden: Schema.decodeUnknownOption(Schema.Struct({
|
|
4063
|
+
error: Schema.String,
|
|
4064
|
+
forbidden: Reason
|
|
4065
|
+
}))
|
|
4066
|
+
};
|
|
4067
|
+
/**
|
|
4068
|
+
* A 401's or 403's answer, whatever its body: Remote's own refusal as it is,
|
|
4069
|
+
* and anything else (`{ error }` from middleware, HTML, a shape of its own)
|
|
4070
|
+
* as the status alone, so it never reaches a decoder that would call it a
|
|
4071
|
+
* broken answer.
|
|
4072
|
+
*/
|
|
4073
|
+
const refusalOf = (body, kind, status) => Option.getOrElse(ownRefusal[kind](body), () => ({
|
|
4074
|
+
error: status,
|
|
4075
|
+
[kind]: {}
|
|
4076
|
+
}));
|
|
3993
4077
|
/**
|
|
3994
4078
|
* Remote's client over HTTP: each call a `POST` of the request to `url`, the
|
|
3995
|
-
* answer its JSON body whatever its status. A
|
|
3996
|
-
*
|
|
3997
|
-
*
|
|
4079
|
+
* answer its JSON body whatever its status. A 401 is answered as
|
|
4080
|
+
* unauthenticated, for every call kind, and a 403 as forbidden, whatever the
|
|
4081
|
+
* body says: the server's own says why, and middleware in front of Remote
|
|
4082
|
+
* may say anything.
|
|
3998
4083
|
* `headers` is read per request, so a token that changes reaches the next
|
|
3999
4084
|
* call. `fetch` defaults to the global one; pass it to route calls through
|
|
4000
4085
|
* another implementation in tests.
|
|
@@ -4010,11 +4095,8 @@ const http = (url, options = {}) => json(async (request) => {
|
|
|
4010
4095
|
});
|
|
4011
4096
|
const status = `${response.status} ${response.statusText}`;
|
|
4012
4097
|
const body = await response.json().catch(() => notJson);
|
|
4013
|
-
|
|
4014
|
-
if (response.status === 403
|
|
4015
|
-
error: status,
|
|
4016
|
-
forbidden: {}
|
|
4017
|
-
};
|
|
4098
|
+
if (response.status === 401) return refusalOf(body, "unauthenticated", status);
|
|
4099
|
+
if (response.status === 403) return refusalOf(body, "forbidden", status);
|
|
4018
4100
|
if (body === notJson) throw new Error(status);
|
|
4019
4101
|
return body;
|
|
4020
4102
|
});
|
|
@@ -4079,13 +4161,21 @@ async function* changes(body) {
|
|
|
4079
4161
|
if (frame.data.length === 0) continue;
|
|
4080
4162
|
const text = frame.data.join("\n");
|
|
4081
4163
|
if (frame.event === "error") {
|
|
4082
|
-
const
|
|
4083
|
-
|
|
4164
|
+
const said = JSON.parse(text);
|
|
4165
|
+
const message = Predicate.isObject(said) && typeof said.message === "string" ? said.message : text;
|
|
4166
|
+
if (Predicate.isObject(said) && Predicate.isObject(said.unauthenticated)) {
|
|
4167
|
+
const reason = said.unauthenticated.reason;
|
|
4168
|
+
throw new RemoteUnauthenticated({
|
|
4169
|
+
message,
|
|
4170
|
+
...typeof reason === "string" ? { reason } : {}
|
|
4171
|
+
});
|
|
4172
|
+
}
|
|
4173
|
+
throw new RemoteLiveError({ message });
|
|
4084
4174
|
}
|
|
4085
4175
|
yield decodeChange(JSON.parse(text));
|
|
4086
4176
|
}
|
|
4087
4177
|
}
|
|
4088
|
-
const liveError = (error) => error instanceof RemoteLiveError ? error : new RemoteLiveError({ message: error instanceof Error ? error.message : String(error) });
|
|
4178
|
+
const liveError = (error) => error instanceof RemoteLiveError || error instanceof RemoteUnauthenticated ? error : new RemoteLiveError({ message: error instanceof Error ? error.message : String(error) });
|
|
4089
4179
|
/** Remote's live stream over fetch: `serveFetch`'s live open as a `Stream`. */
|
|
4090
4180
|
const liveFetch = (url, options = {}) => (payload) => Stream.unwrap(Effect.gen(function* () {
|
|
4091
4181
|
const via = options.fetch ?? fetch;
|
|
@@ -4110,7 +4200,15 @@ const liveFetch = (url, options = {}) => (payload) => Stream.unwrap(Effect.gen(f
|
|
|
4110
4200
|
try: () => response.json().catch(() => null),
|
|
4111
4201
|
catch: liveError
|
|
4112
4202
|
});
|
|
4113
|
-
|
|
4203
|
+
const message = Predicate.isObject(answered) && "error" in answered ? String(answered.error) : `HTTP ${response.status} ${response.statusText}`;
|
|
4204
|
+
if (response.status === 401) {
|
|
4205
|
+
const said = Predicate.isObject(answered) && Predicate.isObject(answered.unauthenticated) ? answered.unauthenticated.reason : void 0;
|
|
4206
|
+
return yield* new RemoteUnauthenticated({
|
|
4207
|
+
message,
|
|
4208
|
+
...typeof said === "string" ? { reason: said } : {}
|
|
4209
|
+
});
|
|
4210
|
+
}
|
|
4211
|
+
return yield* new RemoteLiveError({ message });
|
|
4114
4212
|
}
|
|
4115
4213
|
if (response.body === null) return yield* new RemoteLiveError({ message: "The server answered live with no body" });
|
|
4116
4214
|
return Stream.fromAsyncIterable(changes(response.body), liveError);
|
|
@@ -6112,7 +6210,7 @@ const bindDomain = (definition, store, options = {}) => {
|
|
|
6112
6210
|
},
|
|
6113
6211
|
wiring: (active, options) => ({
|
|
6114
6212
|
key: `remote:${bound.contract.name}`,
|
|
6115
|
-
handles:
|
|
6213
|
+
handles: Record.keys(remoteMessageCases),
|
|
6116
6214
|
route: (model, message) => isRemoteMessage(message) ? Option.some({ model: reduce(model, message) }) : Option.none(),
|
|
6117
6215
|
subscriptions: brandEntries(domain.subscriptions(active, options)),
|
|
6118
6216
|
contract: bound.contract
|
|
@@ -6156,6 +6254,6 @@ const pickWindow = (window) => ({
|
|
|
6156
6254
|
...window.before === void 0 ? {} : { before: window.before }
|
|
6157
6255
|
});
|
|
6158
6256
|
//#endregion
|
|
6159
|
-
export {
|
|
6257
|
+
export { emptyOptimistic as $, refParts as $n, QueryResult as $t, writeRead as A, schemaOf as An, RemoteClient as At, plan as B, missingFields as Bn, Live as Bt, remoteMessageCases as C, beginMutation as Cn, hasPrevious as Ct, updateRemote as D, optimisticOfWrite as Dn, segment as Dt, retentionRootsSchema as E, mutationStatus as En, merge as Et, REMOTE_CACHE_VERSION as F, hasField as Fn, remoteError as Ft, emptyLiveState as G, tombstone as Gn, MAX_RELATION_DEPTH as Gt, applyConnectionEvent as H, remove as Hn, LiveEdge as Ht, RemotePersistence as I, isFieldStale as In, coalesceQueries as It, ConnectionChange as J, RELATION_ALIAS as Jn, MutationResult as Jt, liveHasNext as K, writeEntities as Kn, Mutate as Kt, gc as L, isFieldUnavailable as Ln, coalesceReads as Lt, RemoteData as M, emptyStore as Mn, connectionChangeOf as Mt, remoteDataSchema as N, entityKey as Nn, liveEventOf as Nt, windowGrowthKey as O, patchOfWrite as On, terminal as Ot, remoteErrorSchema as P, entry as Pn, mutateRemote as Pt, connectionIdentity as Q, isRefPage as Qn, QueryRequest as Qt, reachable as R, isTombstone as Rn, requirementKey as Rt, refreshedAt as S, Refusal as Sn, hasNext as St, remoteModelSchema as T, failMutation as Tn, items as Tt, applyEntityEvent as U, setStale as Un, LiveRequirement as Ut, windowKey as V, readField as Vn, LiveChange as Vt, classifyLive as W, setUnavailable as Wn, MAX_FIELDS_PER_REQUEST as Wt, addOverlay as X, RelationEntityAnnotation as Xn, PageSize as Xt, addLayer as Y, RelationAnnotation as Yn, NormalizedEntity as Yt, beginOptimistic as Z, aliasedField as Zn, QueryEdge as Zt, isRemoteMessage as _, WireBoundary as _n, relationOf as _t, RemoteJsonAnswer as a, ReadRequest as an, RemoteRequirements as ar, visibleItems as at, overlaysOf as b, stableStringify as bn, edge as bt, emptyRefresh as c, RemoteLiveError as cn, requirementsOf as cr, inspectRemote as ct, initialRemoteModel as d, RemoteQueryError as dn, RowPlace as dt, QueryRpc as en, refsIn as er, pruneOverlays as et, invalidateConnections as f, RemoteReadError as fn, placeIn as ft, isQueryLoading as g, WindowSchema as gn, pageSchema as gt, isLoadingThrough as h, SettledFields as hn, assemble as ht, liveFetch as i, ReadBatchResult as in, RemoteConnections as ir, settleSuccess as it, Denied as j, clearStale as jn, coalescedLayer as jt, withRefreshRequested as k, reconcileMutation as kn, unknown as kt, failureOf as l, RemoteMutationError as ln, belongsEncoded as lt, isLoading as m, RemoteUnauthenticated as mn, Selection as mt, RemoteUnsatisfied as n, Read as nn, relationShape as nr, removeOverlay as nt, RemoteJsonRequest as o, RelationRequest as on, Requirement as or, visibleStore as ot, isFieldFailed as p, RemoteRpc as pn, Entity$1 as pt, liveHasPrevious as q, writeEntity as qn, MutationRequest as qt, httpWithLive as r, ReadBatch as rn, targetsOf as rr, settleFailure as rt, RemotePolicy as s, RemoteForbidden as sn, connectionsOf as sr, inspectEntity as st, Remote as t, REMOTE_PROTOCOL_VERSION as tn, relationAlias as tr, removeLayer as tt, forgetRemote as u, RemoteProtocolError as un, matching as ut, noFailures as v, IDENTITY_SEPARATOR as vn, unavailableOf as vt, remoteMessageSchema as w, emptyMutationState as wn, isGapped as wt, refreshIsInFlight as x, Mutation as xn, emptyConnection as xt, onlyOverlaid as y, Query$1 as yn, cursor as yt, deadlineOf as z, markStale as zn, ConnectionChangeSchema as zt };
|
|
6160
6258
|
|
|
6161
|
-
//# sourceMappingURL=src-
|
|
6259
|
+
//# sourceMappingURL=src-Cp71fJac.mjs.map
|