@apollion-dsi/relay 0.27.3 → 0.28.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 +146 -0
- package/lib/chunks/chunk-54QV6DFY.esm.js +1 -0
- package/lib/chunks/chunk-FYOI5Q5V.esm.js +0 -0
- package/lib/chunks/chunk-GZONWSRB.esm.js +1 -0
- package/lib/chunks/chunk-KIA6YWO5.esm.js +1 -0
- package/lib/chunks/chunk-RMYDTZUF.esm.js +1 -0
- package/lib/chunks/chunk-XJA2SRQY.esm.js +1 -0
- package/lib/commitMutation/index.esm.js +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/mutationUtils/index.esm.js +1 -0
- package/lib/relayArgsInterface/index.esm.js +1 -0
- package/lib/relayArgsInterface/relayArgsInterface.d.ts +27 -0
- package/lib/setupRelayEnvironment/index.d.ts +11 -0
- package/lib/setupRelayEnvironment/index.esm.js +1 -0
- package/lib/setupRelayEnvironment/setupRelayEnvironment.d.ts +17 -0
- package/lib/setupRelayEnvironment/setupRelayEnvironment.helpers.d.ts +9 -1
- package/lib/setupRelayEnvironment/subscriptionHandler.d.ts +18 -12
- package/lib/useEnvironment/index.esm.js +1 -0
- package/package.json +31 -3
- package/README.MD +0 -119
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @apollion-dsi/relay
|
|
2
|
+
|
|
3
|
+
Configure and use **Relay** (`react-relay` / `relay-runtime`) the Apollion DS
|
|
4
|
+
way — Environment creation with auth, multipart uploads, WebSocket
|
|
5
|
+
subscriptions, and httpOnly-cookie sessions, without the boilerplate.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@apollion-dsi/relay)
|
|
8
|
+
[](https://www.npmjs.com/package/@apollion-dsi/relay)
|
|
9
|
+
[](https://www.npmjs.com/package/@apollion-dsi/relay)
|
|
10
|
+
|
|
11
|
+
- **Environment in one call.** `CreateRelayEnvironment` wires the network layer,
|
|
12
|
+
auth, and error handling from a single config object.
|
|
13
|
+
- **Two auth models.** `Bearer` tokens or secure **httpOnly cookies** — switch
|
|
14
|
+
with one flag (see below).
|
|
15
|
+
- **Persisted queries.** Ship only build-time hashes over the wire — the server
|
|
16
|
+
executes nothing outside its allowlist (see below).
|
|
17
|
+
- **Batteries included.** Multipart file uploads, `graphql-ws` subscriptions,
|
|
18
|
+
and pluggable network retry / refresh ship with the package.
|
|
19
|
+
- **Typed.** Ships its own types for every option.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
`react` is a **peer dependency** (`^19.0.0`); the Relay stack (`react-relay` /
|
|
24
|
+
`relay-runtime` 21.x, `graphql` 16.x, `graphql-ws`, `fetch-multipart-graphql`,
|
|
25
|
+
`js-cookie`) ships with the package:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
yarn add @apollion-dsi/relay react
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> To generate Relay artifacts, also add `relay-compiler` as a dev dependency and
|
|
32
|
+
> a `relay.config.js`.
|
|
33
|
+
|
|
34
|
+
## Documentation
|
|
35
|
+
|
|
36
|
+
- **Docs & API reference:** <https://www.apollion.com.br>
|
|
37
|
+
- **Changelog:** <https://www.apollion.com.br/changelog>
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
Create the Environment and provide it to your tree:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { CreateRelayEnvironment } from '@apollion-dsi/relay';
|
|
45
|
+
import { RelayEnvironmentProvider } from 'react-relay';
|
|
46
|
+
import { App } from './app';
|
|
47
|
+
|
|
48
|
+
const { Environment } = new CreateRelayEnvironment({
|
|
49
|
+
url: 'https://api.example.com/graphql',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
<RelayEnvironmentProvider environment={Environment}>
|
|
53
|
+
<App />
|
|
54
|
+
</RelayEnvironmentProvider>;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Authentication: Bearer vs. httpOnly cookie
|
|
58
|
+
|
|
59
|
+
The Environment supports two auth models via `authMode`.
|
|
60
|
+
|
|
61
|
+
### `authMode: 'bearer'` (default)
|
|
62
|
+
|
|
63
|
+
Reads the `sessionToken` from storage (`localStorage` or a JS-readable cookie)
|
|
64
|
+
and injects `Authorization: Bearer <token>` into every request; session
|
|
65
|
+
verification uses the `${authUrl}user/me` probe.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
new CreateRelayEnvironment({
|
|
69
|
+
url: 'https://api.example.com/graphql/',
|
|
70
|
+
authUrl: 'https://api.example.com/auth/',
|
|
71
|
+
useAuthorization: true,
|
|
72
|
+
storageType: 'cookie', // JS-readable cookie, or 'localStorage'
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `authMode: 'cookie'` (httpOnly session — recommended for SPAs)
|
|
77
|
+
|
|
78
|
+
The session token lives in an **httpOnly + SameSite** cookie, invisible to JS
|
|
79
|
+
and immune to XSS. The Environment never reads the token or sets
|
|
80
|
+
`Authorization` — `credentials: 'include'` makes the browser attach the cookie
|
|
81
|
+
automatically. On an auth error (e.g. 401), a refresh `POST` is fired to
|
|
82
|
+
`authUrl` with credentials, without probing `user/me`.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
new CreateRelayEnvironment({
|
|
86
|
+
url: 'https://api.example.com/graphql/',
|
|
87
|
+
authUrl: 'https://api.example.com/auth/refresh/',
|
|
88
|
+
authMode: 'cookie',
|
|
89
|
+
redirectOnError: true,
|
|
90
|
+
loginRoute: '/login',
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
| Option | Default | What it does |
|
|
95
|
+
| ----------------- | ---------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
96
|
+
| `authMode` | `'bearer'` | `'bearer'` (token + header) or `'cookie'` (httpOnly). |
|
|
97
|
+
| `credentials` | cookie→`'include'`; bearer→omitted | `RequestCredentials` forwarded to the GraphQL and refresh fetches. Works in both modes. |
|
|
98
|
+
| `sessionCheckUrl` | mode-dependent | Overrides the probe URL; `false` disables it (auth error → direct logout, no extra call). |
|
|
99
|
+
|
|
100
|
+
## Persisted queries
|
|
101
|
+
|
|
102
|
+
With `usePersistedQueries: true`, every operation ships as a **build-time
|
|
103
|
+
hash** instead of GraphQL text. The server keeps the matching query map and
|
|
104
|
+
executes only hashes it knows — a tampered client query is refused, and the
|
|
105
|
+
server can cache aggressively by hash.
|
|
106
|
+
|
|
107
|
+
1. Enable `persistConfig` in your `relay.config.json` so `relay-compiler`
|
|
108
|
+
writes the query map and stamps each artifact's `id`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"src": "./src",
|
|
113
|
+
"schema": "./schema.graphql",
|
|
114
|
+
"language": "typescript",
|
|
115
|
+
"persistConfig": { "file": "./persisted/queryMap.json", "algorithm": "MD5" }
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
2. Ship `queryMap.json` to your GraphQL server as the allowlist.
|
|
120
|
+
|
|
121
|
+
3. Turn the flag on:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
new CreateRelayEnvironment({
|
|
125
|
+
url: 'https://api.example.com/graphql/',
|
|
126
|
+
usePersistedQueries: true,
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The request body becomes `{ name, doc_id, variables }` — no `query` key.
|
|
131
|
+
Uploads carry the hash inside the multipart `operations` field, and
|
|
132
|
+
subscriptions send it in `payload.extensions.doc_id` over `graphql-ws`.
|
|
133
|
+
|
|
134
|
+
| Option | Default | What it does |
|
|
135
|
+
| ------------------------- | ---------- | ------------------------------------------------------------------------------ |
|
|
136
|
+
| `usePersistedQueries` | `false` | Sends only the persisted hash; the GraphQL text never leaves the build. |
|
|
137
|
+
| `persistedOperationField` | `'doc_id'` | Renames the hash field to whatever your server's allowlist middleware expects. |
|
|
138
|
+
|
|
139
|
+
> **Server contract:** resolve the hash against the query map; refuse raw text
|
|
140
|
+
> and unknown hashes replying `200` + `{ "errors": [...] }` with
|
|
141
|
+
> `Content-Type: application/json` — a `4xx` is treated as a transport failure
|
|
142
|
+
> by the client's retry layer instead of surfacing the GraphQL error.
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e}from"./chunk-GZONWSRB.esm.js";import r from"react";var t=r.createContext(void 0);function m({children:n,environment:o}){return r.createElement(t.Provider,{value:{environment:o}},n)}e(m,"EnvironmentProvider");function v(){let n=r.useContext(t);if(n===void 0)throw new Error("useEnvironment must be used within a EnvironmentProvider");if(n.environment===null||n.environment===void 0)throw new Error("You should provide a Relay Environment to EnvironmentProvider component");return n}e(v,"useEnvironment");export{m as a,v as b};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var d=(a,b)=>c(a,"name",{value:b,configurable:!0});export{d as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as s}from"./chunk-GZONWSRB.esm.js";import{Environment as ae,Network as ue,RecordSource as le,Store as ce}from"relay-runtime";import{Observable as te,QueryResponseCache as re}from"relay-runtime";var E=!!(typeof window!="undefined"&&window.document&&window.document.createElement),f={canUseDOM:E,canUseWorkers:typeof Worker!="undefined",canUseEventListeners:E&&!!(window.addEventListener||window.attachEvent),canUseViewport:E&&!!window.screen,isInWorker:!E};function $(e){return async t=>{let r=e.timeout,o=e.retries,a=0,i=0;return new Promise((u,l)=>{let c={};c.sendTimedRequest=()=>{a++,i=Date.now();let n=!0,p=new AbortController,m=setTimeout(()=>{if(n=!1,p.abort(),c.shouldRetry(a))e.useDebug&&console.log("fetchWithRetries: HTTP timeout, retrying."),c.retryRequest();else{let h=new Error(`fetchWithRetries(): Failed to get response from server, tried ${a} times.`);h.name="TimeOutError",l(h)}},r);fetch(e.url,{...t,signal:p.signal}).then(async h=>{if(clearTimeout(m),n)if(h.status>=200&&h.status<300)u(h);else if(c.shouldRetry(a)&&e.retryWhen.includes(h.status))e.useDebug&&console.log("fetchWithRetries: HTTP error, retrying..."),c.retryRequest();else{let d=new Error(`fetchWithRetries(): Still no successful response after ${a} retries, giving up.`);d.response=h,l(d)}}).catch(h=>{clearTimeout(m),h.name!=="AbortError"&&l(h)})},c.retryRequest=()=>{let n=o[a-1],p=i+n;setTimeout(c.sendTimedRequest,p-Date.now())},c.shouldRetry=n=>f.canUseDOM&&e.useRetries&&n<=o.length,c.sendTimedRequest()})}}s($,"fetchWithRetries");import{PatchResolver as X}from"fetch-multipart-graphql";var x=s(e=>e.operationKind==="mutation","isMutation"),O=s(e=>e.operationKind==="query","isQuery"),V=s(e=>!!(e&&e.force),"forceFetch"),Y=s(()=>f.canUseDOM?window.location.search.startsWith("?")?"&":"?":"","getParamsDelimiter"),C=s(()=>f.canUseDOM?window.location.pathname:"","getBrowserLocation"),R=s((e,t,r)=>{let o=e;(e!==t||r.loginRoute!==t)&&(o=`${t}${Y()}redirect=${e}`),window.location.href=o},"redirectUser");function L(e){if(!e.id)throw new Error(`[usePersistedQueries] Operation "${e.name}" has no persisted id \u2014 run relay-compiler with "persistConfig" set in relay.config.json.`);return e.id}s(L,"getPersistedOperationId");function Z(e,t,r,o){let a=new FormData,i=o!=null&&o.usePersistedQueries?{[o.persistedOperationField||"doc_id"]:L(e),variables:t,operationName:e.name}:{query:e.text,variables:t,operationName:e.name};a.append("operations",JSON.stringify(i));let u={};for(let l=0;l<r.files.length;l++)a.append(`${l}`,r.files[l]),u[`${l}`]=[r.path(l)];return a.append("map",JSON.stringify(u)),a}s(Z,"getRequestBodyWithUploadables");function ee(e,t,r){return r!=null&&r.usePersistedQueries?JSON.stringify({name:e.name,[r.persistedOperationField||"doc_id"]:L(e),variables:t}):JSON.stringify({name:e.name,query:e.text,variables:t})}s(ee,"getRequestBodyWithoutUplodables");function B(e,t,r,o){return r?Z(e,t,r,o):ee(e,t,o)}s(B,"getRequestBody");var U=s(e=>{if(e.credentials)return e.credentials;if(e.authMode==="cookie")return"include"},"resolveCredentials"),_=s((e,t)=>{let r=new Headers;if(t?r.append("Accept","*/*"):(r.append("Accept","application/json"),r.append("Content-type","application/json")),e.useAuthorization&&e.authMode!=="cookie"){let{sessionToken:o}=e.StorageHandler.getTokens();o&&C()!==e.loginRoute&&r.append("Authorization",`Bearer ${o}`)}return e.partner&&r.append("X-Partner",e.partner),r},"getHeaders"),j=s((e,t,r)=>{if(e.status<300&&e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("multipart/mixed")>=0){let o=e.body.getReader(),a=new TextDecoder,i=new X({onResponse:s(u=>t.next(u),"onResponse")});o.read().then(s(function u({value:l,done:c}){if(c)t.complete();else{let n;try{n=a.decode(l),i.handleChunk(n)}catch(p){let m=p;m.response=e,m.statusCode=e.status,m.bodyText=n,t.error(m)}o.read().then(u)}},"sendNext"))}else e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("application/json")>=0?e.json().then(r):e.text().then(o=>{t.next([o]),t.complete()})},"handleData"),b=1e3,v=b*60;var J=s(e=>{let t=new re({ttl:e.cacheTime,size:e.cacheSize}),r=$(e);async function o(){if(e.sessionCheckUrl===!1)return!1;let i=U(e);try{if(e.authMode==="cookie"){let n=e.sessionCheckUrl||e.authUrl;return(await fetch(n,{method:"POST",credentials:i||"include"})).status===200}let{sessionToken:u}=e.StorageHandler.getTokens(),l=e.sessionCheckUrl||`${e.authUrl}user/me`;return(await fetch(l,{headers:{"Content-Type":"application/json",Authorization:u},...i?{credentials:i}:{}})).status===200}catch(u){return console.warn(`[Auth] ${u.message}`),!1}}s(o,"checkSession");async function a(i,u,l,c,n){try{let p=i.id||("cacheID"in i?i.cacheID:null)||String(i.text);if(e.useCache&&O(i)&&!V(l)){let d=t.get(p,u);if(d){n.next(d),n.complete();return}}e.useCache&&x(i)&&t.clear();let m=U(e),h=await r({method:"POST",headers:_(e,c),body:B(i,u,c,e),...m?{credentials:m}:{}});j(h,n,async d=>{if(e.useCache&&O(i)&&t.set(p,u,d),!n.closed){if(x(i)&&d.errors&&n.error(d.errors),d.errors){if(await o()||(e.StorageHandler.clear(),R("/",e.loginRoute,e)),e.redirectOnError){let z=[];Array.isArray(d.errors)&&(z=d.errors.map(({status_code:P})=>P));let Q=C();z.some(P=>e.authenticationErrors.includes(P))&&Q!==e.loginRoute&&(e.StorageHandler.clear(),R(Q,e.loginRoute,e))}n.error(d.errors)}else d.data?n.next(d):n.error(d);n.complete()}})}catch(p){if(f.canUseDOM&&!["AbortError","TimeOutError"].includes(p.name)&&e.StorageHandler.clear(),e.redirectOnError){let h=C();h!==e.loginRoute&&R(h,e.loginRoute,e)}await o()||(e.StorageHandler.clear(),R("/",e.loginRoute,e)),n.error(p)}}return s(a,"fetchFn"),(i,u,l,c)=>te.create(n=>{a(i,u,l,c,n)})},"createFetchFunction");import se from"js-cookie";var A=class A{get(t){throw new Error('Must implement a "GET" method')}set(t,r){throw new Error('Must implement a "SET" method')}delete(t){throw new Error('Must implement a "DELETE" method')}};s(A,"DefaultStrategy");var k=A,I=class I extends k{constructor(){super(),this.strategy=localStorage}get(t){return this.strategy.getItem(t)}set(t,r){this.strategy.setItem(t,r)}delete(t){this.strategy.removeItem(t)}};s(I,"LocalStorageStrategy");var D=I,F=class F extends k{constructor(){super(),this.strategy=se}get(t){return this.strategy.get(t)}set(t,r){this.strategy.set(t,r)}delete(t){this.strategy.remove(t)}};s(F,"CookieStrategy");var M=F,y=Symbol("storage-handler"),g=Symbol("prop-session"),w=Symbol("prop-refresh"),H=class H{constructor(t){this[g]=t.sessionStorageProp,this[w]=t.refreshStorageProp,t.storageType==="cookie"?this[y]=new M:this[y]=new D}getTokens(){return{refreshToken:this[y].get(this[w]),sessionToken:this[y].get(this[g])}}setTokens(t){this[y].set(this[w],t.refreshToken),this[y].set(this[g],t.sessionToken)}clear(){this[y].delete(this[w]),this[y].delete(this[g])}hasChangedSession({sessionToken:t}){let{sessionToken:r}=this.getTokens();return t!==r}};s(H,"StorageClass");var S=H;import{createClient as oe}from"graphql-ws";import{Observable as ie}from"relay-runtime";function ne(e,t,r){if(e.usePersistedQueries){if(!t.id)throw new Error(`[usePersistedQueries] Operation "${t.name}" has no persisted id \u2014 run relay-compiler with "persistConfig" set in relay.config.json.`);return{operationName:t.name,query:"",variables:r,extensions:{[e.persistedOperationField||"doc_id"]:t.id}}}return{operationName:t.name,query:t.text||"",variables:r}}s(ne,"getSubscribePayload");function K(e){return()=>{let t;return(r,o)=>ie.create(a=>(t||(t=oe({url:e.socket})),t.subscribe(ne(e,r,o),{next:s(i=>a.next(i),"next"),error:s(i=>a.error(i),"error"),complete:s(()=>a.complete(),"complete")})))}}s(K,"setupSubscription");var G=Symbol("mount-environment"),N=Symbol("handler-fetch"),q=Symbol("handler-subscription"),W=class W{constructor(t){if(this.url=t.url,this.authUrl=t.authUrl,this.socket=t.socket,this.storageType=t.storageType||"localStorage",this.cacheSize=t.cacheSize||250,this.cacheTime=t.cacheTime||v*8,this.timeout=t.timeout||v*15,this.sessionStorageProp=t.sessionStorageProp||"USER_SESSION_TOKEN",this.refreshStorageProp=t.refreshStorageProp||"USER_REFRESH_TOKEN",this.loginRoute=t.loginRoute||"/",this.useCache=t.useCache||!1,this.useDebug=t.useDebug||!1,this.useAuthorization=t.useAuthorization||!1,this.authMode=t.authMode||"bearer",this.credentials=t.credentials,this.sessionCheckUrl=t.sessionCheckUrl,this.useRetries=t.useRetries||!1,this.useSubscription=t.useSubscription||!1,this.redirectOnError=t.redirectOnError||!1,this.retryWhen=t.retryWhen||[503,504,521,522,524],this.authenticationErrors=t.authenticationErrors||[401,403],this.retries=t.retries||[b,b*2,b*3,b*5,b*8,b*13,b*21,b*34],this.partner=t.partner||void 0,this.usePersistedQueries=t.usePersistedQueries||!1,this.persistedOperationField=t.persistedOperationField||"doc_id",!this.url)throw new Error("[HTTPFetchEndpoint] You must at least set url parameter.");if(this.useAuthorization&&!this.authUrl)throw new Error('[useAuthorization] Authorization is set but no "authUrl" was provided.');if(this.authMode==="cookie"&&this.sessionCheckUrl!==!1&&!this.authUrl)throw new Error('[authMode:cookie] Cookie auth refreshes against "authUrl" \u2014 provide it or set "sessionCheckUrl: false" to disable the probe.');if(this.StorageHandler=new S(this),this.useSubscription){if(!this.socket)throw new Error("[useSubscription] If you choose to use WebSocket you must set a socket endpoint.");this[q]=K(this)()}this[N]=J(this),this[G]()}[(N,q,G)](){let t=ue.create(this[N],this[q]||null),r=new le,o=new ce(r);this.Environment=new ae({network:t,store:o})}};s(W,"RelayEnvironment");var T=W;export{T as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as o}from"./chunk-GZONWSRB.esm.js";import{commitMutation as m}from"relay-runtime";var p=o((t,r)=>new Promise((n,e)=>{m(t,{...r,onError:e,onCompleted:n})}),"commitMutation");export{p as a};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as d}from"./chunk-GZONWSRB.esm.js";import{nanoid as g}from"nanoid";import{ConnectionHandler as p}from"relay-runtime";function y(e){return e!==null&&typeof e=="object"}d(y,"isObject");var O=g();function P({parentId:e,itemId:t,parentFieldName:o,store:n}){let r=n.get(e),i=r.getLinkedRecords(o);r.setLinkedRecords(i.filter(c=>c.dataID!==t),o)}d(P,"listRecordRemoveUpdater");function S({parentId:e,item:t,type:o,parentFieldName:n,store:r}){let i=r.create(t.id,o);Object.keys(t).forEach(s=>{i.setValue(t[s],s)});let c=r.get(e),a=c.getLinkedRecords(n);c.setLinkedRecords([...a,i],n)}d(S,"listRecordAddUpdater");function l(e,t,o,n,r=!1){if(n){let i=e.get(t),c=p.getConnection(i,o);if(!c)return;r?p.insertEdgeBefore(c,n):p.insertEdgeAfter(c,n)}}d(l,"connectionUpdater");function m({parentId:e,store:t,connectionName:o,item:n,customNode:r,itemType:i}){let c=r||t.create(n.id,i);!r&&Object.keys(n).forEach(s=>{c.setValue(n[s],s)});let a=t.create(`client:newEdge:${String(c.getDataID).match(/[^:]+$/)[0]}`,`${i}Edge`);a.setLinkedRecord(c,"node"),l(t,e,o,a)}d(m,"optimisticConnectionUpdater");function U({parentId:e,connectionName:t,nodeId:o,store:n}){let r=n.get(e),i=p.getConnection(r,t);if(!i){console.warn(`Connection ${t} not found on ${e}`);return}p.deleteNode(i,o)}d(U,"connectionDeleteEdgeUpdater");function C({object:e,proxy:t}){Object.keys(e).forEach(o=>{y(e[o])||Array.isArray(e[o])||t.setValue(e[o],o)})}d(C,"copyObjScalarsToProxy");export{y as a,O as b,P as c,S as d,l as e,m as f,U as g,C as h};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"../chunks/chunk-RMYDTZUF.esm.js";import"../chunks/chunk-GZONWSRB.esm.js";export{a as commitMutation};
|
package/lib/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* `@apollion-dsi/relay/<name>` when the consumer wants to load
|
|
12
12
|
* less code.
|
|
13
13
|
*/
|
|
14
|
-
export {
|
|
14
|
+
export { CreateRelayEnvironment } from './setupRelayEnvironment';
|
|
15
15
|
export * from './useEnvironment';
|
|
16
16
|
export * from './relayArgsInterface';
|
|
17
17
|
export * from './mutationUtils';
|
package/lib/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Z=Object.defineProperty;var o=(e,t)=>Z(e,"name",{value:t,configurable:!0});import{Environment as ue,Network as le,RecordSource as de,Store as pe}from"relay-runtime";import{Observable as ne,QueryResponseCache as se}from"relay-runtime";var S=!!(typeof window!="undefined"&&window.document&&window.document.createElement),b={canUseDOM:S,canUseWorkers:typeof Worker!="undefined",canUseEventListeners:S&&!!(window.addEventListener||window.attachEvent),canUseViewport:S&&!!window.screen,isInWorker:!S};function j(e){return async t=>{let r=e.timeout,n=e.retries,i=0,s=0;return new Promise((a,l)=>{let u={};u.sendTimedRequest=()=>{i++,s=Date.now();let c=!0,h=new AbortController,m=setTimeout(()=>{if(c=!1,h.abort(),u.shouldRetry(i))e.useDebug&&console.log("fetchWithRetries: HTTP timeout, retrying."),u.retryRequest();else{let d=new Error(`fetchWithRetries(): Failed to get response from server, tried ${i} times.`);d.name="TimeOutError",l(d)}},r);fetch(e.url,{...t,signal:h.signal}).then(async d=>{if(clearTimeout(m),c)if(d.status>=200&&d.status<300)a(d);else if(u.shouldRetry(i)&&e.retryWhen.includes(d.status))e.useDebug&&console.log("fetchWithRetries: HTTP error, retrying..."),u.retryRequest();else{let p=new Error(`fetchWithRetries(): Still no successful response after ${i} retries, giving up.`);p.response=d,l(p)}}).catch(d=>{clearTimeout(m),d.name!=="AbortError"&&l(d)})},u.retryRequest=()=>{let c=n[i-1],h=s+c;setTimeout(u.sendTimedRequest,h-Date.now())},u.shouldRetry=c=>b.canUseDOM&&e.useRetries&&c<=n.length,u.sendTimedRequest()})}}o(j,"fetchWithRetries");import{PatchResolver as ee}from"fetch-multipart-graphql";var k=o(e=>e.operationKind==="mutation","isMutation"),U=o(e=>e.operationKind==="query","isQuery"),B=o(e=>!!(e&&e.force),"forceFetch"),te=o(()=>b.canUseDOM?window.location.search.startsWith("?")?"&":"?":"","getParamsDelimiter"),T=o(()=>b.canUseDOM?window.location.pathname:"","getBrowserLocation"),g=o((e,t,r)=>{let n=e;(e!==t||r.loginRoute!==t)&&(n=`${t}${te()}redirect=${e}`),window.location.href=n},"redirectUser");function re(e,t,r){let n=new FormData;n.append("operations",JSON.stringify({query:e.text,variables:t,operationName:e.name}));let i={};for(let s=0;s<r.files.length;s++)n.append(`${s}`,r.files[s]),i[`${s}`]=[r.path(s)];return n.append("map",JSON.stringify(i)),n}o(re,"getRequestBodyWithUploadables");function oe(e,t){return JSON.stringify({name:e.name,query:e.text,variables:t})}o(oe,"getRequestBodyWithoutUplodables");function K(e,t,r){return r?re(e,t,r):oe(e,t)}o(K,"getRequestBody");var O=o(e=>{if(e.credentials)return e.credentials;if(e.authMode==="cookie")return"include"},"resolveCredentials"),_=o((e,t)=>{let r=new Headers;if(t?r.append("Accept","*/*"):(r.append("Accept","application/json"),r.append("Content-type","application/json")),e.useAuthorization&&e.authMode!=="cookie"){let{sessionToken:n}=e.StorageHandler.getTokens();n&&T()!==e.loginRoute&&r.append("Authorization",`Bearer ${n}`)}return e.partner&&r.append("X-Partner",e.partner),r},"getHeaders"),J=o((e,t,r)=>{if(e.status<300&&e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("multipart/mixed")>=0){let n=e.body.getReader(),i=new TextDecoder,s=new ee({onResponse:o(a=>t.next(a),"onResponse")});n.read().then(o(function a({value:l,done:u}){if(u)t.complete();else{let c;try{c=i.decode(l),s.handleChunk(c)}catch(h){let m=h;m.response=e,m.statusCode=e.status,m.bodyText=c,t.error(m)}n.read().then(a)}},"sendNext"))}else e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("application/json")>=0?e.json().then(r):e.text().then(n=>{t.next([n]),t.complete()})},"handleData"),f=1e3,M=f*60;var Q=o(e=>{let t=new se({ttl:e.cacheTime,size:e.cacheSize}),r=j(e);async function n(){if(e.sessionCheckUrl===!1)return!1;let s=O(e);try{if(e.authMode==="cookie"){let c=e.sessionCheckUrl||e.authUrl;return(await fetch(c,{method:"POST",credentials:s||"include"})).status===200}let{sessionToken:a}=e.StorageHandler.getTokens(),l=e.sessionCheckUrl||`${e.authUrl}user/me`;return(await fetch(l,{headers:{"Content-Type":"application/json",Authorization:a},...s?{credentials:s}:{}})).status===200}catch(a){return console.warn(`[Auth] ${a.message}`),!1}}o(n,"checkSession");async function i(s,a,l,u,c){try{let h=String(s.text);if(e.useCache&&U(s)&&!B(l)){let p=t.get(h,a);if(p){c.next(p),c.complete();return}}e.useCache&&k(s)&&t.clear();let m=O(e),d=await r({method:"POST",headers:_(e,u),body:K(s,a,u),...m?{credentials:m}:{}});J(d,c,async p=>{if(e.useCache&&U(s)&&t.set(h,a,p),!c.closed){if(k(s)&&p.errors&&c.error(p.errors),p.errors){if(await n()||(e.StorageHandler.clear(),g("/",e.loginRoute,e)),e.redirectOnError){let F=[];Array.isArray(p.errors)&&(F=p.errors.map(({status_code:P})=>P));let V=T();F.some(P=>e.authenticationErrors.includes(P))&&V!==e.loginRoute&&(e.StorageHandler.clear(),g(V,e.loginRoute,e))}c.error(p.errors)}else p.data?c.next(p):c.error(p);c.complete()}})}catch(h){if(b.canUseDOM&&!["AbortError","TimeOutError"].includes(h.name)&&e.StorageHandler.clear(),e.redirectOnError){let d=T();d!==e.loginRoute&&g(d,e.loginRoute,e)}await n()||(e.StorageHandler.clear(),g("/",e.loginRoute,e)),c.error(h)}}return o(i,"fetchFn"),(s,a,l,u)=>ne.create(c=>{i(s,a,l,u,c)})},"createFetchFunction");import ie from"js-cookie";var A=class A{get(t){throw new Error('Must implement a "GET" method')}set(t,r){throw new Error('Must implement a "SET" method')}delete(t){throw new Error('Must implement a "DELETE" method')}};o(A,"DefaultStrategy");var w=A,q=class q extends w{constructor(){super(),this.strategy=localStorage}get(t){return this.strategy.getItem(t)}set(t,r){this.strategy.setItem(t,r)}delete(t){this.strategy.removeItem(t)}};o(q,"LocalStorageStrategy");var D=q,H=class H extends w{constructor(){super(),this.strategy=ie}get(t){return this.strategy.get(t)}set(t,r){this.strategy.set(t,r)}delete(t){this.strategy.remove(t)}};o(H,"CookieStrategy");var I=H,y=Symbol("storage-handler"),R=Symbol("prop-session"),E=Symbol("prop-refresh"),N=class N{constructor(t){this[R]=t.sessionStorageProp,this[E]=t.refreshStorageProp,t.storageType==="cookie"?this[y]=new I:this[y]=new D}getTokens(){return{refreshToken:this[y].get(this[E]),sessionToken:this[y].get(this[R])}}setTokens(t){this[y].set(this[E],t.refreshToken),this[y].set(this[R],t.sessionToken)}clear(){this[y].delete(this[E]),this[y].delete(this[R])}hasChangedSession({sessionToken:t}){let{sessionToken:r}=this.getTokens();return t!==r}};o(N,"StorageClass");var x=N;import{createClient as ae}from"graphql-ws";import{Observable as ce}from"relay-runtime";function Y(e){return()=>{let t=ae({url:e.socket});return(r,n)=>ce.create(i=>t.subscribe({operationName:r.name,query:r.text||"",variables:n},{next:o(s=>i.next(s),"next"),error:o(s=>i.error(s),"error"),complete:o(()=>i.complete(),"complete")}))}}o(Y,"setupSubscription");var G=Symbol("mount-environment"),W=Symbol("handler-fetch"),L=Symbol("handler-subscription"),$=class ${constructor(t){if(this.url=t.url,this.authUrl=t.authUrl,this.socket=t.socket,this.storageType=t.storageType||"localStorage",this.cacheSize=t.cacheSize||250,this.cacheTime=t.cacheTime||M*8,this.timeout=t.timeout||M*15,this.sessionStorageProp=t.sessionStorageProp||"USER_SESSION_TOKEN",this.refreshStorageProp=t.refreshStorageProp||"USER_REFRESH_TOKEN",this.loginRoute=t.loginRoute||"/",this.useCache=t.useCache||!1,this.useDebug=t.useDebug||!1,this.useAuthorization=t.useAuthorization||!1,this.authMode=t.authMode||"bearer",this.credentials=t.credentials,this.sessionCheckUrl=t.sessionCheckUrl,this.useRetries=t.useRetries||!1,this.useSubscription=t.useSubscription||!1,this.redirectOnError=t.redirectOnError||!1,this.retryWhen=t.retryWhen||[503,504,521,522,524],this.authenticationErrors=t.authenticationErrors||[401,403],this.retries=t.retries||[f,f*2,f*3,f*5,f*8,f*13,f*21,f*34],this.partner=t.partner||void 0,!this.url)throw new Error("[HTTPFetchEndpoint] You must at least set url parameter.");if(this.useAuthorization&&!this.authUrl)throw new Error('[useAuthorization] Authorization is set but no "authUrl" was provided.');if(this.authMode==="cookie"&&this.sessionCheckUrl!==!1&&!this.authUrl)throw new Error('[authMode:cookie] Cookie auth refreshes against "authUrl" \u2014 provide it or set "sessionCheckUrl: false" to disable the probe.');if(this.StorageHandler=new x(this),this.useSubscription){if(!this.socket)throw new Error("[useSubscription] If you choose to use WebSocket you must set a socket endpoint.");this[L]=Y(this)}this[W]=Q(this),this[G]()}[(W,L,G)](){let t=le.create(this[W],this[L]||null),r=new de,n=new pe(r);this.Environment=new ue({network:t,store:n})}};o($,"RelayEnvironment");var C=$;import z from"react";var X=z.createContext(void 0);function et({children:e,environment:t}){return z.createElement(X.Provider,{value:{environment:t}},e)}o(et,"EnvironmentProvider");function tt(){let e=z.useContext(X);if(e===void 0)throw new Error("useEnvironment must be used within a EnvironmentProvider");if(e.environment===null||e.environment===void 0)throw new Error("You should provide a Relay Environment to EnvironmentProvider component");return e}o(tt,"useEnvironment");import{nanoid as he}from"nanoid";import{ConnectionHandler as v}from"relay-runtime";function me(e){return e!==null&&typeof e=="object"}o(me,"isObject");var dt=he();function pt({parentId:e,itemId:t,parentFieldName:r,store:n}){let i=n.get(e),s=i.getLinkedRecords(r);i.setLinkedRecords(s.filter(a=>a.dataID!==t),r)}o(pt,"listRecordRemoveUpdater");function ht({parentId:e,item:t,type:r,parentFieldName:n,store:i}){let s=i.create(t.id,r);Object.keys(t).forEach(u=>{s.setValue(t[u],u)});let a=i.get(e),l=a.getLinkedRecords(n);a.setLinkedRecords([...l,s],n)}o(ht,"listRecordAddUpdater");function fe(e,t,r,n,i=!1){if(n){let s=e.get(t),a=v.getConnection(s,r);if(!a)return;i?v.insertEdgeBefore(a,n):v.insertEdgeAfter(a,n)}}o(fe,"connectionUpdater");function mt({parentId:e,store:t,connectionName:r,item:n,customNode:i,itemType:s}){let a=i||t.create(n.id,s);!i&&Object.keys(n).forEach(u=>{a.setValue(n[u],u)});let l=t.create(`client:newEdge:${String(a.getDataID).match(/[^:]+$/)[0]}`,`${s}Edge`);l.setLinkedRecord(a,"node"),fe(t,e,r,l)}o(mt,"optimisticConnectionUpdater");function ft({parentId:e,connectionName:t,nodeId:r,store:n}){let i=n.get(e),s=v.getConnection(i,t);if(!s){console.warn(`Connection ${t} not found on ${e}`);return}v.deleteNode(s,r)}o(ft,"connectionDeleteEdgeUpdater");function yt({object:e,proxy:t}){Object.keys(e).forEach(r=>{me(e[r])||Array.isArray(e[r])||t.setValue(e[r],r)})}o(yt,"copyObjScalarsToProxy");import{commitMutation as ye}from"relay-runtime";var Tt=o((e,t)=>new Promise((r,n)=>{ye(e,{...t,onError:n,onCompleted:r})}),"commitMutation");export{dt as ClientMutationID,C as CreateRelayEnvironment,et as EnvironmentProvider,Tt as commitMutation,ft as connectionDeleteEdgeUpdater,fe as connectionUpdater,yt as copyObjScalarsToProxy,me as isObject,ht as listRecordAddUpdater,pt as listRecordRemoveUpdater,mt as optimisticConnectionUpdater,tt as useEnvironment};
|
|
1
|
+
import{a as o}from"./chunks/chunk-RMYDTZUF.esm.js";import{a as m,b as f,c as p,d as x,e as n,f as a,g as i,h as l}from"./chunks/chunk-XJA2SRQY.esm.js";import"./chunks/chunk-FYOI5Q5V.esm.js";import{a as r}from"./chunks/chunk-KIA6YWO5.esm.js";import{a as e,b as t}from"./chunks/chunk-54QV6DFY.esm.js";import"./chunks/chunk-GZONWSRB.esm.js";export{f as ClientMutationID,r as CreateRelayEnvironment,e as EnvironmentProvider,o as commitMutation,i as connectionDeleteEdgeUpdater,n as connectionUpdater,l as copyObjScalarsToProxy,m as isObject,x as listRecordAddUpdater,p as listRecordRemoveUpdater,a as optimisticConnectionUpdater,t as useEnvironment};
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var pe=Object.create;var E=Object.defineProperty;var he=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames;var fe=Object.getPrototypeOf,ye=Object.prototype.hasOwnProperty;var o=(e,t)=>E(e,"name",{value:t,configurable:!0});var be=(e,t)=>{for(var r in t)E(e,r,{get:t[r],enumerable:!0})},_=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of me(t))!ye.call(e,i)&&i!==r&&E(e,i,{get:()=>t[i],enumerable:!(n=he(t,i))||n.enumerable});return e};var J=(e,t,r)=>(r=e!=null?pe(fe(e)):{},_(t||!e||!e.__esModule?E(r,"default",{value:e,enumerable:!0}):r,e)),ge=e=>_(E({},"__esModule",{value:!0}),e);var Me={};be(Me,{ClientMutationID:()=>Te,CreateRelayEnvironment:()=>w,EnvironmentProvider:()=>ve,commitMutation:()=>Oe,connectionDeleteEdgeUpdater:()=>ke,connectionUpdater:()=>le,copyObjScalarsToProxy:()=>Ue,isObject:()=>ue,listRecordAddUpdater:()=>Ce,listRecordRemoveUpdater:()=>we,optimisticConnectionUpdater:()=>Pe,useEnvironment:()=>Se});module.exports=ge(Me);var b=require("relay-runtime");var k=require("relay-runtime");var C=!!(typeof window!="undefined"&&window.document&&window.document.createElement),g={canUseDOM:C,canUseWorkers:typeof Worker!="undefined",canUseEventListeners:C&&!!(window.addEventListener||window.attachEvent),canUseViewport:C&&!!window.screen,isInWorker:!C};function Q(e){return async t=>{let r=e.timeout,n=e.retries,i=0,s=0;return new Promise((a,l)=>{let u={};u.sendTimedRequest=()=>{i++,s=Date.now();let c=!0,h=new AbortController,m=setTimeout(()=>{if(c=!1,h.abort(),u.shouldRetry(i))e.useDebug&&console.log("fetchWithRetries: HTTP timeout, retrying."),u.retryRequest();else{let d=new Error(`fetchWithRetries(): Failed to get response from server, tried ${i} times.`);d.name="TimeOutError",l(d)}},r);fetch(e.url,{...t,signal:h.signal}).then(async d=>{if(clearTimeout(m),c)if(d.status>=200&&d.status<300)a(d);else if(u.shouldRetry(i)&&e.retryWhen.includes(d.status))e.useDebug&&console.log("fetchWithRetries: HTTP error, retrying..."),u.retryRequest();else{let p=new Error(`fetchWithRetries(): Still no successful response after ${i} retries, giving up.`);p.response=d,l(p)}}).catch(d=>{clearTimeout(m),d.name!=="AbortError"&&l(d)})},u.retryRequest=()=>{let c=n[i-1],h=s+c;setTimeout(u.sendTimedRequest,h-Date.now())},u.shouldRetry=c=>g.canUseDOM&&e.useRetries&&c<=n.length,u.sendTimedRequest()})}}o(Q,"fetchWithRetries");var Y=require("fetch-multipart-graphql");var D=o(e=>e.operationKind==="mutation","isMutation"),I=o(e=>e.operationKind==="query","isQuery"),G=o(e=>!!(e&&e.force),"forceFetch"),Re=o(()=>g.canUseDOM?window.location.search.startsWith("?")?"&":"?":"","getParamsDelimiter"),P=o(()=>g.canUseDOM?window.location.pathname:"","getBrowserLocation"),x=o((e,t,r)=>{let n=e;(e!==t||r.loginRoute!==t)&&(n=`${t}${Re()}redirect=${e}`),window.location.href=n},"redirectUser");function Ee(e,t,r){let n=new FormData;n.append("operations",JSON.stringify({query:e.text,variables:t,operationName:e.name}));let i={};for(let s=0;s<r.files.length;s++)n.append(`${s}`,r.files[s]),i[`${s}`]=[r.path(s)];return n.append("map",JSON.stringify(i)),n}o(Ee,"getRequestBodyWithUploadables");function xe(e,t){return JSON.stringify({name:e.name,query:e.text,variables:t})}o(xe,"getRequestBodyWithoutUplodables");function X(e,t,r){return r?Ee(e,t,r):xe(e,t)}o(X,"getRequestBody");var A=o(e=>{if(e.credentials)return e.credentials;if(e.authMode==="cookie")return"include"},"resolveCredentials"),Z=o((e,t)=>{let r=new Headers;if(t?r.append("Accept","*/*"):(r.append("Accept","application/json"),r.append("Content-type","application/json")),e.useAuthorization&&e.authMode!=="cookie"){let{sessionToken:n}=e.StorageHandler.getTokens();n&&P()!==e.loginRoute&&r.append("Authorization",`Bearer ${n}`)}return e.partner&&r.append("X-Partner",e.partner),r},"getHeaders"),ee=o((e,t,r)=>{if(e.status<300&&e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("multipart/mixed")>=0){let n=e.body.getReader(),i=new TextDecoder,s=new Y.PatchResolver({onResponse:o(a=>t.next(a),"onResponse")});n.read().then(o(function a({value:l,done:u}){if(u)t.complete();else{let c;try{c=i.decode(l),s.handleChunk(c)}catch(h){let m=h;m.response=e,m.statusCode=e.status,m.bodyText=c,t.error(m)}n.read().then(a)}},"sendNext"))}else e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("application/json")>=0?e.json().then(r):e.text().then(n=>{t.next([n]),t.complete()})},"handleData"),f=1e3,q=f*60;var te=o(e=>{let t=new k.QueryResponseCache({ttl:e.cacheTime,size:e.cacheSize}),r=Q(e);async function n(){if(e.sessionCheckUrl===!1)return!1;let s=A(e);try{if(e.authMode==="cookie"){let c=e.sessionCheckUrl||e.authUrl;return(await fetch(c,{method:"POST",credentials:s||"include"})).status===200}let{sessionToken:a}=e.StorageHandler.getTokens(),l=e.sessionCheckUrl||`${e.authUrl}user/me`;return(await fetch(l,{headers:{"Content-Type":"application/json",Authorization:a},...s?{credentials:s}:{}})).status===200}catch(a){return console.warn(`[Auth] ${a.message}`),!1}}o(n,"checkSession");async function i(s,a,l,u,c){try{let h=String(s.text);if(e.useCache&&I(s)&&!G(l)){let p=t.get(h,a);if(p){c.next(p),c.complete();return}}e.useCache&&D(s)&&t.clear();let m=A(e),d=await r({method:"POST",headers:Z(e,u),body:X(s,a,u),...m?{credentials:m}:{}});ee(d,c,async p=>{if(e.useCache&&I(s)&&t.set(h,a,p),!c.closed){if(D(s)&&p.errors&&c.error(p.errors),p.errors){if(await n()||(e.StorageHandler.clear(),x("/",e.loginRoute,e)),e.redirectOnError){let B=[];Array.isArray(p.errors)&&(B=p.errors.map(({status_code:M})=>M));let K=P();B.some(M=>e.authenticationErrors.includes(M))&&K!==e.loginRoute&&(e.StorageHandler.clear(),x(K,e.loginRoute,e))}c.error(p.errors)}else p.data?c.next(p):c.error(p);c.complete()}})}catch(h){if(g.canUseDOM&&!["AbortError","TimeOutError"].includes(h.name)&&e.StorageHandler.clear(),e.redirectOnError){let d=P();d!==e.loginRoute&&x(d,e.loginRoute,e)}await n()||(e.StorageHandler.clear(),x("/",e.loginRoute,e)),c.error(h)}}return o(i,"fetchFn"),(s,a,l,u)=>k.Observable.create(c=>{i(s,a,l,u,c)})},"createFetchFunction");var re=J(require("js-cookie"));var W=class W{get(t){throw new Error('Must implement a "GET" method')}set(t,r){throw new Error('Must implement a "SET" method')}delete(t){throw new Error('Must implement a "DELETE" method')}};o(W,"DefaultStrategy");var U=W,L=class L extends U{constructor(){super(),this.strategy=localStorage}get(t){return this.strategy.getItem(t)}set(t,r){this.strategy.setItem(t,r)}delete(t){this.strategy.removeItem(t)}};o(L,"LocalStorageStrategy");var H=L,$=class $ extends U{constructor(){super(),this.strategy=re.default}get(t){return this.strategy.get(t)}set(t,r){this.strategy.set(t,r)}delete(t){this.strategy.remove(t)}};o($,"CookieStrategy");var N=$,y=Symbol("storage-handler"),v=Symbol("prop-session"),S=Symbol("prop-refresh"),z=class z{constructor(t){this[v]=t.sessionStorageProp,this[S]=t.refreshStorageProp,t.storageType==="cookie"?this[y]=new N:this[y]=new H}getTokens(){return{refreshToken:this[y].get(this[S]),sessionToken:this[y].get(this[v])}}setTokens(t){this[y].set(this[S],t.refreshToken),this[y].set(this[v],t.sessionToken)}clear(){this[y].delete(this[S]),this[y].delete(this[v])}hasChangedSession({sessionToken:t}){let{sessionToken:r}=this.getTokens();return t!==r}};o(z,"StorageClass");var T=z;var oe=require("graphql-ws"),ne=require("relay-runtime");function se(e){return()=>{let t=(0,oe.createClient)({url:e.socket});return(r,n)=>ne.Observable.create(i=>t.subscribe({operationName:r.name,query:r.text||"",variables:n},{next:o(s=>i.next(s),"next"),error:o(s=>i.error(s),"error"),complete:o(()=>i.complete(),"complete")}))}}o(se,"setupSubscription");var ie=Symbol("mount-environment"),F=Symbol("handler-fetch"),V=Symbol("handler-subscription"),j=class j{constructor(t){if(this.url=t.url,this.authUrl=t.authUrl,this.socket=t.socket,this.storageType=t.storageType||"localStorage",this.cacheSize=t.cacheSize||250,this.cacheTime=t.cacheTime||q*8,this.timeout=t.timeout||q*15,this.sessionStorageProp=t.sessionStorageProp||"USER_SESSION_TOKEN",this.refreshStorageProp=t.refreshStorageProp||"USER_REFRESH_TOKEN",this.loginRoute=t.loginRoute||"/",this.useCache=t.useCache||!1,this.useDebug=t.useDebug||!1,this.useAuthorization=t.useAuthorization||!1,this.authMode=t.authMode||"bearer",this.credentials=t.credentials,this.sessionCheckUrl=t.sessionCheckUrl,this.useRetries=t.useRetries||!1,this.useSubscription=t.useSubscription||!1,this.redirectOnError=t.redirectOnError||!1,this.retryWhen=t.retryWhen||[503,504,521,522,524],this.authenticationErrors=t.authenticationErrors||[401,403],this.retries=t.retries||[f,f*2,f*3,f*5,f*8,f*13,f*21,f*34],this.partner=t.partner||void 0,!this.url)throw new Error("[HTTPFetchEndpoint] You must at least set url parameter.");if(this.useAuthorization&&!this.authUrl)throw new Error('[useAuthorization] Authorization is set but no "authUrl" was provided.');if(this.authMode==="cookie"&&this.sessionCheckUrl!==!1&&!this.authUrl)throw new Error('[authMode:cookie] Cookie auth refreshes against "authUrl" \u2014 provide it or set "sessionCheckUrl: false" to disable the probe.');if(this.StorageHandler=new T(this),this.useSubscription){if(!this.socket)throw new Error("[useSubscription] If you choose to use WebSocket you must set a socket endpoint.");this[V]=se(this)}this[F]=te(this),this[ie]()}[(F,V,ie)](){let t=b.Network.create(this[F],this[V]||null),r=new b.RecordSource,n=new b.Store(r);this.Environment=new b.Environment({network:t,store:n})}};o(j,"RelayEnvironment");var w=j;var O=J(require("react"));var ae=O.default.createContext(void 0);function ve({children:e,environment:t}){return O.default.createElement(ae.Provider,{value:{environment:t}},e)}o(ve,"EnvironmentProvider");function Se(){let e=O.default.useContext(ae);if(e===void 0)throw new Error("useEnvironment must be used within a EnvironmentProvider");if(e.environment===null||e.environment===void 0)throw new Error("You should provide a Relay Environment to EnvironmentProvider component");return e}o(Se,"useEnvironment");var ce=require("nanoid"),R=require("relay-runtime");function ue(e){return e!==null&&typeof e=="object"}o(ue,"isObject");var Te=(0,ce.nanoid)();function we({parentId:e,itemId:t,parentFieldName:r,store:n}){let i=n.get(e),s=i.getLinkedRecords(r);i.setLinkedRecords(s.filter(a=>a.dataID!==t),r)}o(we,"listRecordRemoveUpdater");function Ce({parentId:e,item:t,type:r,parentFieldName:n,store:i}){let s=i.create(t.id,r);Object.keys(t).forEach(u=>{s.setValue(t[u],u)});let a=i.get(e),l=a.getLinkedRecords(n);a.setLinkedRecords([...l,s],n)}o(Ce,"listRecordAddUpdater");function le(e,t,r,n,i=!1){if(n){let s=e.get(t),a=R.ConnectionHandler.getConnection(s,r);if(!a)return;i?R.ConnectionHandler.insertEdgeBefore(a,n):R.ConnectionHandler.insertEdgeAfter(a,n)}}o(le,"connectionUpdater");function Pe({parentId:e,store:t,connectionName:r,item:n,customNode:i,itemType:s}){let a=i||t.create(n.id,s);!i&&Object.keys(n).forEach(u=>{a.setValue(n[u],u)});let l=t.create(`client:newEdge:${String(a.getDataID).match(/[^:]+$/)[0]}`,`${s}Edge`);l.setLinkedRecord(a,"node"),le(t,e,r,l)}o(Pe,"optimisticConnectionUpdater");function ke({parentId:e,connectionName:t,nodeId:r,store:n}){let i=n.get(e),s=R.ConnectionHandler.getConnection(i,t);if(!s){console.warn(`Connection ${t} not found on ${e}`);return}R.ConnectionHandler.deleteNode(s,r)}o(ke,"connectionDeleteEdgeUpdater");function Ue({object:e,proxy:t}){Object.keys(e).forEach(r=>{ue(e[r])||Array.isArray(e[r])||t.setValue(e[r],r)})}o(Ue,"copyObjScalarsToProxy");var de=require("relay-runtime");var Oe=o((e,t)=>new Promise((r,n)=>{(0,de.commitMutation)(e,{...t,onError:n,onCompleted:r})}),"commitMutation");0&&(module.exports={ClientMutationID,CreateRelayEnvironment,EnvironmentProvider,commitMutation,connectionDeleteEdgeUpdater,connectionUpdater,copyObjScalarsToProxy,isObject,listRecordAddUpdater,listRecordRemoveUpdater,optimisticConnectionUpdater,useEnvironment});
|
|
1
|
+
var ge=Object.create;var S=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Re=Object.getOwnPropertyNames;var xe=Object.getPrototypeOf,Ee=Object.prototype.hasOwnProperty;var o=(e,t)=>S(e,"name",{value:t,configurable:!0});var we=(e,t)=>{for(var r in t)S(e,r,{get:t[r],enumerable:!0})},Y=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Re(t))!Ee.call(e,i)&&i!==r&&S(e,i,{get:()=>t[i],enumerable:!(n=be(t,i))||n.enumerable});return e};var G=(e,t,r)=>(r=e!=null?ge(xe(e)):{},Y(t||!e||!e.__esModule?S(r,"default",{value:e,enumerable:!0}):r,e)),Se=e=>Y(S({},"__esModule",{value:!0}),e);var We={};we(We,{ClientMutationID:()=>Ie,CreateRelayEnvironment:()=>x,EnvironmentProvider:()=>Oe,commitMutation:()=>Le,connectionDeleteEdgeUpdater:()=>Fe,connectionUpdater:()=>fe,copyObjScalarsToProxy:()=>He,isObject:()=>me,listRecordAddUpdater:()=>De,listRecordRemoveUpdater:()=>Ae,optimisticConnectionUpdater:()=>Ne,useEnvironment:()=>ke});module.exports=Se(We);var g=require("relay-runtime");var U=require("relay-runtime");var O=!!(typeof window!="undefined"&&window.document&&window.document.createElement),R={canUseDOM:O,canUseWorkers:typeof Worker!="undefined",canUseEventListeners:O&&!!(window.addEventListener||window.attachEvent),canUseViewport:O&&!!window.screen,isInWorker:!O};function X(e){return async t=>{let r=e.timeout,n=e.retries,i=0,s=0;return new Promise((a,u)=>{let l={};l.sendTimedRequest=()=>{i++,s=Date.now();let c=!0,h=new AbortController,m=setTimeout(()=>{if(c=!1,h.abort(),l.shouldRetry(i))e.useDebug&&console.log("fetchWithRetries: HTTP timeout, retrying."),l.retryRequest();else{let d=new Error(`fetchWithRetries(): Failed to get response from server, tried ${i} times.`);d.name="TimeOutError",u(d)}},r);fetch(e.url,{...t,signal:h.signal}).then(async d=>{if(clearTimeout(m),c)if(d.status>=200&&d.status<300)a(d);else if(l.shouldRetry(i)&&e.retryWhen.includes(d.status))e.useDebug&&console.log("fetchWithRetries: HTTP error, retrying..."),l.retryRequest();else{let p=new Error(`fetchWithRetries(): Still no successful response after ${i} retries, giving up.`);p.response=d,u(p)}}).catch(d=>{clearTimeout(m),d.name!=="AbortError"&&u(d)})},l.retryRequest=()=>{let c=n[i-1],h=s+c;setTimeout(l.sendTimedRequest,h-Date.now())},l.shouldRetry=c=>R.canUseDOM&&e.useRetries&&c<=n.length,l.sendTimedRequest()})}}o(X,"fetchWithRetries");var Z=require("fetch-multipart-graphql");var D=o(e=>e.operationKind==="mutation","isMutation"),N=o(e=>e.operationKind==="query","isQuery"),ee=o(e=>!!(e&&e.force),"forceFetch"),Pe=o(()=>R.canUseDOM?window.location.search.startsWith("?")?"&":"?":"","getParamsDelimiter"),k=o(()=>R.canUseDOM?window.location.pathname:"","getBrowserLocation"),P=o((e,t,r)=>{let n=e;(e!==t||r.loginRoute!==t)&&(n=`${t}${Pe()}redirect=${e}`),window.location.href=n},"redirectUser");function te(e){if(!e.id)throw new Error(`[usePersistedQueries] Operation "${e.name}" has no persisted id \u2014 run relay-compiler with "persistConfig" set in relay.config.json.`);return e.id}o(te,"getPersistedOperationId");function Ce(e,t,r,n){let i=new FormData,s=n!=null&&n.usePersistedQueries?{[n.persistedOperationField||"doc_id"]:te(e),variables:t,operationName:e.name}:{query:e.text,variables:t,operationName:e.name};i.append("operations",JSON.stringify(s));let a={};for(let u=0;u<r.files.length;u++)i.append(`${u}`,r.files[u]),a[`${u}`]=[r.path(u)];return i.append("map",JSON.stringify(a)),i}o(Ce,"getRequestBodyWithUploadables");function ve(e,t,r){return r!=null&&r.usePersistedQueries?JSON.stringify({name:e.name,[r.persistedOperationField||"doc_id"]:te(e),variables:t}):JSON.stringify({name:e.name,query:e.text,variables:t})}o(ve,"getRequestBodyWithoutUplodables");function re(e,t,r,n){return r?Ce(e,t,r,n):ve(e,t,n)}o(re,"getRequestBody");var F=o(e=>{if(e.credentials)return e.credentials;if(e.authMode==="cookie")return"include"},"resolveCredentials"),oe=o((e,t)=>{let r=new Headers;if(t?r.append("Accept","*/*"):(r.append("Accept","application/json"),r.append("Content-type","application/json")),e.useAuthorization&&e.authMode!=="cookie"){let{sessionToken:n}=e.StorageHandler.getTokens();n&&k()!==e.loginRoute&&r.append("Authorization",`Bearer ${n}`)}return e.partner&&r.append("X-Partner",e.partner),r},"getHeaders"),ne=o((e,t,r)=>{if(e.status<300&&e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("multipart/mixed")>=0){let n=e.body.getReader(),i=new TextDecoder,s=new Z.PatchResolver({onResponse:o(a=>t.next(a),"onResponse")});n.read().then(o(function a({value:u,done:l}){if(l)t.complete();else{let c;try{c=i.decode(u),s.handleChunk(c)}catch(h){let m=h;m.response=e,m.statusCode=e.status,m.bodyText=c,t.error(m)}n.read().then(a)}},"sendNext"))}else e.headers&&e.headers.get("Content-Type")&&e.headers.get("Content-Type").indexOf("application/json")>=0?e.json().then(r):e.text().then(n=>{t.next([n]),t.complete()})},"handleData"),f=1e3,H=f*60;var se=o(e=>{let t=new U.QueryResponseCache({ttl:e.cacheTime,size:e.cacheSize}),r=X(e);async function n(){if(e.sessionCheckUrl===!1)return!1;let s=F(e);try{if(e.authMode==="cookie"){let c=e.sessionCheckUrl||e.authUrl;return(await fetch(c,{method:"POST",credentials:s||"include"})).status===200}let{sessionToken:a}=e.StorageHandler.getTokens(),u=e.sessionCheckUrl||`${e.authUrl}user/me`;return(await fetch(u,{headers:{"Content-Type":"application/json",Authorization:a},...s?{credentials:s}:{}})).status===200}catch(a){return console.warn(`[Auth] ${a.message}`),!1}}o(n,"checkSession");async function i(s,a,u,l,c){try{let h=s.id||("cacheID"in s?s.cacheID:null)||String(s.text);if(e.useCache&&N(s)&&!ee(u)){let p=t.get(h,a);if(p){c.next(p),c.complete();return}}e.useCache&&D(s)&&t.clear();let m=F(e),d=await r({method:"POST",headers:oe(e,l),body:re(s,a,l,e),...m?{credentials:m}:{}});ne(d,c,async p=>{if(e.useCache&&N(s)&&t.set(h,a,p),!c.closed){if(D(s)&&p.errors&&c.error(p.errors),p.errors){if(await n()||(e.StorageHandler.clear(),P("/",e.loginRoute,e)),e.redirectOnError){let J=[];Array.isArray(p.errors)&&(J=p.errors.map(({status_code:A})=>A));let K=k();J.some(A=>e.authenticationErrors.includes(A))&&K!==e.loginRoute&&(e.StorageHandler.clear(),P(K,e.loginRoute,e))}c.error(p.errors)}else p.data?c.next(p):c.error(p);c.complete()}})}catch(h){if(R.canUseDOM&&!["AbortError","TimeOutError"].includes(h.name)&&e.StorageHandler.clear(),e.redirectOnError){let d=k();d!==e.loginRoute&&P(d,e.loginRoute,e)}await n()||(e.StorageHandler.clear(),P("/",e.loginRoute,e)),c.error(h)}}return o(i,"fetchFn"),(s,a,u,l)=>U.Observable.create(c=>{i(s,a,u,l,c)})},"createFetchFunction");var ie=G(require("js-cookie"));var q=class q{get(t){throw new Error('Must implement a "GET" method')}set(t,r){throw new Error('Must implement a "SET" method')}delete(t){throw new Error('Must implement a "DELETE" method')}};o(q,"DefaultStrategy");var M=q,V=class V extends M{constructor(){super(),this.strategy=localStorage}get(t){return this.strategy.getItem(t)}set(t,r){this.strategy.setItem(t,r)}delete(t){this.strategy.removeItem(t)}};o(V,"LocalStorageStrategy");var L=V,$=class $ extends M{constructor(){super(),this.strategy=ie.default}get(t){return this.strategy.get(t)}set(t,r){this.strategy.set(t,r)}delete(t){this.strategy.remove(t)}};o($,"CookieStrategy");var W=$,y=Symbol("storage-handler"),C=Symbol("prop-session"),v=Symbol("prop-refresh"),Q=class Q{constructor(t){this[C]=t.sessionStorageProp,this[v]=t.refreshStorageProp,t.storageType==="cookie"?this[y]=new W:this[y]=new L}getTokens(){return{refreshToken:this[y].get(this[v]),sessionToken:this[y].get(this[C])}}setTokens(t){this[y].set(this[v],t.refreshToken),this[y].set(this[C],t.sessionToken)}clear(){this[y].delete(this[v]),this[y].delete(this[C])}hasChangedSession({sessionToken:t}){let{sessionToken:r}=this.getTokens();return t!==r}};o(Q,"StorageClass");var T=Q;var ae=require("graphql-ws"),ce=require("relay-runtime");function Te(e,t,r){if(e.usePersistedQueries){if(!t.id)throw new Error(`[usePersistedQueries] Operation "${t.name}" has no persisted id \u2014 run relay-compiler with "persistConfig" set in relay.config.json.`);return{operationName:t.name,query:"",variables:r,extensions:{[e.persistedOperationField||"doc_id"]:t.id}}}return{operationName:t.name,query:t.text||"",variables:r}}o(Te,"getSubscribePayload");function ue(e){return()=>{let t;return(r,n)=>ce.Observable.create(i=>(t||(t=(0,ae.createClient)({url:e.socket})),t.subscribe(Te(e,r,n),{next:o(s=>i.next(s),"next"),error:o(s=>i.error(s),"error"),complete:o(()=>i.complete(),"complete")})))}}o(ue,"setupSubscription");var le=Symbol("mount-environment"),j=Symbol("handler-fetch"),B=Symbol("handler-subscription"),_=class _{constructor(t){if(this.url=t.url,this.authUrl=t.authUrl,this.socket=t.socket,this.storageType=t.storageType||"localStorage",this.cacheSize=t.cacheSize||250,this.cacheTime=t.cacheTime||H*8,this.timeout=t.timeout||H*15,this.sessionStorageProp=t.sessionStorageProp||"USER_SESSION_TOKEN",this.refreshStorageProp=t.refreshStorageProp||"USER_REFRESH_TOKEN",this.loginRoute=t.loginRoute||"/",this.useCache=t.useCache||!1,this.useDebug=t.useDebug||!1,this.useAuthorization=t.useAuthorization||!1,this.authMode=t.authMode||"bearer",this.credentials=t.credentials,this.sessionCheckUrl=t.sessionCheckUrl,this.useRetries=t.useRetries||!1,this.useSubscription=t.useSubscription||!1,this.redirectOnError=t.redirectOnError||!1,this.retryWhen=t.retryWhen||[503,504,521,522,524],this.authenticationErrors=t.authenticationErrors||[401,403],this.retries=t.retries||[f,f*2,f*3,f*5,f*8,f*13,f*21,f*34],this.partner=t.partner||void 0,this.usePersistedQueries=t.usePersistedQueries||!1,this.persistedOperationField=t.persistedOperationField||"doc_id",!this.url)throw new Error("[HTTPFetchEndpoint] You must at least set url parameter.");if(this.useAuthorization&&!this.authUrl)throw new Error('[useAuthorization] Authorization is set but no "authUrl" was provided.');if(this.authMode==="cookie"&&this.sessionCheckUrl!==!1&&!this.authUrl)throw new Error('[authMode:cookie] Cookie auth refreshes against "authUrl" \u2014 provide it or set "sessionCheckUrl: false" to disable the probe.');if(this.StorageHandler=new T(this),this.useSubscription){if(!this.socket)throw new Error("[useSubscription] If you choose to use WebSocket you must set a socket endpoint.");this[B]=ue(this)()}this[j]=se(this),this[le]()}[(j,B,le)](){let t=g.Network.create(this[j],this[B]||null),r=new g.RecordSource,n=new g.Store(r);this.Environment=new g.Environment({network:t,store:n})}};o(_,"RelayEnvironment");var x=_;var I=G(require("react"));var de=I.default.createContext(void 0);function Oe({children:e,environment:t}){return I.default.createElement(de.Provider,{value:{environment:t}},e)}o(Oe,"EnvironmentProvider");function ke(){let e=I.default.useContext(de);if(e===void 0)throw new Error("useEnvironment must be used within a EnvironmentProvider");if(e.environment===null||e.environment===void 0)throw new Error("You should provide a Relay Environment to EnvironmentProvider component");return e}o(ke,"useEnvironment");var z=require("node:crypto");var pe="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var Ue=128,b,E;function Me(e){if(e<0)throw new RangeError("Wrong ID size");try{!b||b.length<e?(b=Buffer.allocUnsafe(e*Ue),z.webcrypto.getRandomValues(b),E=0):E+e>b.length&&(z.webcrypto.getRandomValues(b),E=0)}catch(t){throw b=void 0,t}E+=e}o(Me,"fillPool");function he(e=21){Me(e|=0);let t="";for(let r=E-e;r<E;r++)t+=pe[b[r]&63];return t}o(he,"nanoid");var w=require("relay-runtime");function me(e){return e!==null&&typeof e=="object"}o(me,"isObject");var Ie=he();function Ae({parentId:e,itemId:t,parentFieldName:r,store:n}){let i=n.get(e),s=i.getLinkedRecords(r);i.setLinkedRecords(s.filter(a=>a.dataID!==t),r)}o(Ae,"listRecordRemoveUpdater");function De({parentId:e,item:t,type:r,parentFieldName:n,store:i}){let s=i.create(t.id,r);Object.keys(t).forEach(l=>{s.setValue(t[l],l)});let a=i.get(e),u=a.getLinkedRecords(n);a.setLinkedRecords([...u,s],n)}o(De,"listRecordAddUpdater");function fe(e,t,r,n,i=!1){if(n){let s=e.get(t),a=w.ConnectionHandler.getConnection(s,r);if(!a)return;i?w.ConnectionHandler.insertEdgeBefore(a,n):w.ConnectionHandler.insertEdgeAfter(a,n)}}o(fe,"connectionUpdater");function Ne({parentId:e,store:t,connectionName:r,item:n,customNode:i,itemType:s}){let a=i||t.create(n.id,s);!i&&Object.keys(n).forEach(l=>{a.setValue(n[l],l)});let u=t.create(`client:newEdge:${String(a.getDataID).match(/[^:]+$/)[0]}`,`${s}Edge`);u.setLinkedRecord(a,"node"),fe(t,e,r,u)}o(Ne,"optimisticConnectionUpdater");function Fe({parentId:e,connectionName:t,nodeId:r,store:n}){let i=n.get(e),s=w.ConnectionHandler.getConnection(i,t);if(!s){console.warn(`Connection ${t} not found on ${e}`);return}w.ConnectionHandler.deleteNode(s,r)}o(Fe,"connectionDeleteEdgeUpdater");function He({object:e,proxy:t}){Object.keys(e).forEach(r=>{me(e[r])||Array.isArray(e[r])||t.setValue(e[r],r)})}o(He,"copyObjScalarsToProxy");var ye=require("relay-runtime");var Le=o((e,t)=>new Promise((r,n)=>{(0,ye.commitMutation)(e,{...t,onError:n,onCompleted:r})}),"commitMutation");0&&(module.exports={ClientMutationID,CreateRelayEnvironment,EnvironmentProvider,commitMutation,connectionDeleteEdgeUpdater,connectionUpdater,copyObjScalarsToProxy,isObject,listRecordAddUpdater,listRecordRemoveUpdater,optimisticConnectionUpdater,useEnvironment});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b,c,d,e,f,g,h}from"../chunks/chunk-XJA2SRQY.esm.js";import"../chunks/chunk-GZONWSRB.esm.js";export{b as ClientMutationID,g as connectionDeleteEdgeUpdater,e as connectionUpdater,h as copyObjScalarsToProxy,a as isObject,d as listRecordAddUpdater,c as listRecordRemoveUpdater,f as optimisticConnectionUpdater};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../chunks/chunk-FYOI5Q5V.esm.js";
|
|
@@ -204,4 +204,31 @@ export interface RelayArgsInterface {
|
|
|
204
204
|
* @defaultValue undefined
|
|
205
205
|
*/
|
|
206
206
|
partner?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Enables **persisted queries**: the request carries only the
|
|
209
|
+
* operation hash generated at build time by `relay-compiler`
|
|
210
|
+
* (`persistConfig`) plus the variables — the GraphQL text never
|
|
211
|
+
* leaves the build.
|
|
212
|
+
*
|
|
213
|
+
* The server must hold the matching query map (hash → text) and
|
|
214
|
+
* accept the hash in the field named by `persistedOperationField`
|
|
215
|
+
* — in the JSON body for queries/mutations, or in
|
|
216
|
+
* `payload.extensions` for subscriptions over `graphql-ws`.
|
|
217
|
+
*
|
|
218
|
+
* Requires the consumer's `relay.config.json` to define
|
|
219
|
+
* `persistConfig` — with the flag on, an artifact without an `id`
|
|
220
|
+
* (compiler ran without `persistConfig`) throws a descriptive error
|
|
221
|
+
* instead of silently sending nothing.
|
|
222
|
+
*
|
|
223
|
+
* @defaultValue false
|
|
224
|
+
*/
|
|
225
|
+
usePersistedQueries?: boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Name of the request field that carries the persisted-operation
|
|
228
|
+
* hash when `usePersistedQueries` is on. Lets the client match
|
|
229
|
+
* whatever field the server's allowlist middleware expects.
|
|
230
|
+
*
|
|
231
|
+
* @defaultValue `'doc_id'`
|
|
232
|
+
*/
|
|
233
|
+
persistedOperationField?: string;
|
|
207
234
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public barrel for the `setupRelayEnvironment` module.
|
|
3
|
+
*
|
|
4
|
+
* Exports only the public surface: the `CreateRelayEnvironment` class
|
|
5
|
+
* (default export of the `setupRelayEnvironment.ts` file). The internals
|
|
6
|
+
* `fetchQuery`, `fetchWithRetries`, `storage`, `subscriptionHandler`,
|
|
7
|
+
* `executeEnvironment` and `setupRelayEnvironment.helpers` stay hidden
|
|
8
|
+
* — they are part of the implementation and not part of the contract.
|
|
9
|
+
*/
|
|
10
|
+
export { default as CreateRelayEnvironment } from './setupRelayEnvironment';
|
|
11
|
+
export { default } from './setupRelayEnvironment';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a}from"../chunks/chunk-KIA6YWO5.esm.js";import"../chunks/chunk-GZONWSRB.esm.js";export{a as CreateRelayEnvironment,a as default};
|
|
@@ -63,6 +63,19 @@ declare const kSubscriptionHandler: unique symbol;
|
|
|
63
63
|
* });
|
|
64
64
|
* ```
|
|
65
65
|
*
|
|
66
|
+
* @example With persisted queries (server-aligned hash allowlist)
|
|
67
|
+
* ```ts
|
|
68
|
+
* // Requires `persistConfig` in the consumer's relay.config.json, e.g.
|
|
69
|
+
* // { "persistConfig": { "file": "./persisted/queryMap.json", "algorithm": "MD5" } }.
|
|
70
|
+
* // The request body becomes `{ name, doc_id, variables }` — the GraphQL
|
|
71
|
+
* // text never leaves the build; the server resolves the hash against the
|
|
72
|
+
* // query map and refuses anything else.
|
|
73
|
+
* const { Environment } = new CreateRelayEnvironment({
|
|
74
|
+
* url: 'https://api.example.com/graphql/',
|
|
75
|
+
* usePersistedQueries: true,
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
66
79
|
* @see {@link RelayArgsInterface} for the complete list of configuration options.
|
|
67
80
|
*/
|
|
68
81
|
export default class RelayEnvironment implements RelayArgsInterface {
|
|
@@ -112,6 +125,10 @@ export default class RelayEnvironment implements RelayArgsInterface {
|
|
|
112
125
|
storageType: 'cookie' | 'localStorage';
|
|
113
126
|
/** Optional partner identifier, sent in the `X-Partner` header. */
|
|
114
127
|
partner?: string;
|
|
128
|
+
/** Sends only the build-time operation hash instead of the GraphQL text. */
|
|
129
|
+
usePersistedQueries?: boolean;
|
|
130
|
+
/** Request field carrying the persisted-operation hash. */
|
|
131
|
+
persistedOperationField?: string;
|
|
115
132
|
/**
|
|
116
133
|
* Fetch function assembled for use by Relay's `Network`. Internal.
|
|
117
134
|
*/
|
|
@@ -38,6 +38,11 @@ export declare const getBrowserLocation: () => string;
|
|
|
38
38
|
* @param config - Environment configuration (used to check `loginRoute`).
|
|
39
39
|
*/
|
|
40
40
|
export declare const redirectUser: (url: string, redirectTo: string, config?: RelayArgsInterface) => void;
|
|
41
|
+
/** Subset of the Environment configuration the body builders read. */
|
|
42
|
+
interface PersistedConfig {
|
|
43
|
+
usePersistedQueries?: boolean;
|
|
44
|
+
persistedOperationField?: string;
|
|
45
|
+
}
|
|
41
46
|
/**
|
|
42
47
|
* Builds the GraphQL request body — multipart if there are uploadables,
|
|
43
48
|
* JSON otherwise.
|
|
@@ -45,8 +50,10 @@ export declare const redirectUser: (url: string, redirectTo: string, config?: Re
|
|
|
45
50
|
* @param request - Relay request parameters.
|
|
46
51
|
* @param variables - Operation variables.
|
|
47
52
|
* @param uploadables - Files to upload (optional).
|
|
53
|
+
* @param config - Environment configuration subset for persisted queries
|
|
54
|
+
* (optional; absent behaves as `usePersistedQueries: false`).
|
|
48
55
|
*/
|
|
49
|
-
export declare function getRequestBody(request: RequestParameters, variables: Variables, uploadables?: UploadableMap): string | FormData;
|
|
56
|
+
export declare function getRequestBody(request: RequestParameters, variables: Variables, uploadables?: UploadableMap, config?: PersistedConfig): string | FormData;
|
|
50
57
|
/**
|
|
51
58
|
* Resolves the effective `credentials` value for the fetches (GraphQL and
|
|
52
59
|
* session verification/refresh).
|
|
@@ -96,3 +103,4 @@ export declare const handleData: (response: Response, sink: Sink, callback: (dat
|
|
|
96
103
|
export declare const ONE_SECOND = 1000;
|
|
97
104
|
/** Time constant: 1 minute in milliseconds. */
|
|
98
105
|
export declare const ONE_MINUTE: number;
|
|
106
|
+
export {};
|
|
@@ -8,22 +8,28 @@
|
|
|
8
8
|
* Not exposed by the root barrel — internal implementation of
|
|
9
9
|
* `CreateRelayEnvironment`.
|
|
10
10
|
*/
|
|
11
|
+
/** Subset of the Environment configuration the subscription handler reads. */
|
|
12
|
+
interface SubscriptionSettings {
|
|
13
|
+
socket?: string;
|
|
14
|
+
usePersistedQueries?: boolean;
|
|
15
|
+
persistedOperationField?: string;
|
|
16
|
+
}
|
|
11
17
|
/**
|
|
12
18
|
* Builds the subscription function for Relay's `Network.create`.
|
|
13
19
|
*
|
|
14
|
-
* Returns a
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
20
|
+
* Returns a factory (invoked once, during Environment setup) which yields the
|
|
21
|
+
* subscribe function Relay calls for each subscription operation. The
|
|
22
|
+
* `graphql-ws` client is created lazily on the first subscription — no socket
|
|
23
|
+
* is opened for environments that never subscribe. The adaptation of
|
|
24
|
+
* `graphql-ws` `next/error/complete` callbacks to the Relay Observable `Sink`
|
|
18
25
|
* happens here.
|
|
19
26
|
*
|
|
20
|
-
* @param settings -
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* function is called.
|
|
24
|
-
* @returns
|
|
27
|
+
* @param settings - Environment configuration subset: the WebSocket endpoint
|
|
28
|
+
* (`socket`) plus the persisted-queries flags. When `useSubscription` is
|
|
29
|
+
* `true` but `socket` was not configured, the `CreateRelayEnvironment`
|
|
30
|
+
* constructor throws before this function is called.
|
|
31
|
+
* @returns Factory that, when invoked, returns the subscribe function
|
|
25
32
|
* compatible with `Network.create(fetchFn, subscribeFn)`.
|
|
26
33
|
*/
|
|
27
|
-
export declare function setupSubscription(settings:
|
|
28
|
-
|
|
29
|
-
}): () => any;
|
|
34
|
+
export declare function setupSubscription(settings: SubscriptionSettings): () => any;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b}from"../chunks/chunk-54QV6DFY.esm.js";import"../chunks/chunk-GZONWSRB.esm.js";export{a as EnvironmentProvider,b as useEnvironment};
|
package/package.json
CHANGED
|
@@ -1,10 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollion-dsi/relay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Frontend services regarding Relay Environment",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/index.esm.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"import": "./lib/index.esm.js",
|
|
12
|
+
"require": "./lib/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./setupRelayEnvironment": {
|
|
15
|
+
"types": "./lib/setupRelayEnvironment/index.d.ts",
|
|
16
|
+
"import": "./lib/setupRelayEnvironment/index.esm.js"
|
|
17
|
+
},
|
|
18
|
+
"./useEnvironment": {
|
|
19
|
+
"types": "./lib/useEnvironment/index.d.ts",
|
|
20
|
+
"import": "./lib/useEnvironment/index.esm.js"
|
|
21
|
+
},
|
|
22
|
+
"./relayArgsInterface": {
|
|
23
|
+
"types": "./lib/relayArgsInterface/index.d.ts",
|
|
24
|
+
"import": "./lib/relayArgsInterface/index.esm.js"
|
|
25
|
+
},
|
|
26
|
+
"./mutationUtils": {
|
|
27
|
+
"types": "./lib/mutationUtils/index.d.ts",
|
|
28
|
+
"import": "./lib/mutationUtils/index.esm.js"
|
|
29
|
+
},
|
|
30
|
+
"./commitMutation": {
|
|
31
|
+
"types": "./lib/commitMutation/index.d.ts",
|
|
32
|
+
"import": "./lib/commitMutation/index.esm.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
8
36
|
"files": [
|
|
9
37
|
"lib/**/*"
|
|
10
38
|
],
|
|
@@ -19,7 +47,7 @@
|
|
|
19
47
|
"prettier": "prettier --check **/*.{ts,tsx} --ignore-path .gitignore --no-error-on-unmatched-pattern",
|
|
20
48
|
"format": "yarn prettier --write",
|
|
21
49
|
"validate": "./scripts/validate.sh",
|
|
22
|
-
"validate:tests": "relay-compiler && jest --coverage",
|
|
50
|
+
"validate:tests": "relay-compiler && relay-compiler relay.persisted.config.json && jest --coverage",
|
|
23
51
|
"build": "node -e \"require('fs').rmSync('./lib',{recursive:true,force:true})\" && node ./esbuild && tsc --emitDeclarationOnly",
|
|
24
52
|
"test": "yarn validate",
|
|
25
53
|
"code:check": "yarn lint && yarn coverage",
|
|
@@ -39,7 +67,7 @@
|
|
|
39
67
|
"relay-test-utils": "^21.0.0"
|
|
40
68
|
},
|
|
41
69
|
"devDependencies": {
|
|
42
|
-
"@apollion-dsi/eslint-config": "0.
|
|
70
|
+
"@apollion-dsi/eslint-config": "0.10.0",
|
|
43
71
|
"@babel/core": "7.29.0",
|
|
44
72
|
"@babel/plugin-transform-class-properties": "7.27.1",
|
|
45
73
|
"@babel/plugin-transform-runtime": "7.29.0",
|
package/README.MD
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
# @apollion-dsi/relay
|
|
2
|
-
|
|
3
|
-
Helpers to configure and use **Relay** (`react-relay` / `relay-runtime`)
|
|
4
|
-
the Apollion DS way. Covers Environment creation with auth,
|
|
5
|
-
multipart upload, subscriptions via WebSocket, and session cookies.
|
|
6
|
-
|
|
7
|
-
[](https://www.npmjs.com/package/@apollion-dsi/relay)
|
|
8
|
-
|
|
9
|
-
## Stack
|
|
10
|
-
|
|
11
|
-
- **react-relay** 20.x
|
|
12
|
-
- **relay-runtime** 20.x
|
|
13
|
-
- **graphql** 15.x
|
|
14
|
-
- **graphql-ws** 6.x (subscriptions)
|
|
15
|
-
- **fetch-multipart-graphql** (uploads)
|
|
16
|
-
- **js-cookie** (session)
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
yarn add @apollion-dsi/relay react@19.2.6
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
> To generate Relay artifacts, the consumer also needs
|
|
25
|
-
> `relay-compiler` as a dev dependency and a `relay.config.js` setup.
|
|
26
|
-
|
|
27
|
-
## Basic usage
|
|
28
|
-
|
|
29
|
-
Create a Relay Environment for the application:
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import { CreateRelayEnvironment } from '@apollion-dsi/relay';
|
|
33
|
-
|
|
34
|
-
export const { Environment } = new CreateRelayEnvironment({
|
|
35
|
-
url: 'https://api.example.com/graphql',
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Then wrap the React tree with `RelayEnvironmentProvider`:
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
import { RelayEnvironmentProvider } from 'react-relay';
|
|
43
|
-
import { Environment } from './relay';
|
|
44
|
-
import { App } from './app';
|
|
45
|
-
|
|
46
|
-
<RelayEnvironmentProvider environment={Environment}>
|
|
47
|
-
<App />
|
|
48
|
-
</RelayEnvironmentProvider>;
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Helper features
|
|
52
|
-
|
|
53
|
-
- **Authentication** in two modes: `Bearer` (JS token) or **httpOnly
|
|
54
|
-
cookie** (see below).
|
|
55
|
-
- **Multipart uploads** (`fetch-multipart-graphql`) — send files
|
|
56
|
-
directly in mutations.
|
|
57
|
-
- **Subscriptions** via `graphql-ws`.
|
|
58
|
-
- Pluggable **network retry / refresh**.
|
|
59
|
-
|
|
60
|
-
## Authentication: Bearer vs. httpOnly cookie
|
|
61
|
-
|
|
62
|
-
The Environment supports two auth models via `authMode`.
|
|
63
|
-
|
|
64
|
-
### `authMode: 'bearer'` (default — backwards compatible)
|
|
65
|
-
|
|
66
|
-
Reads the `sessionToken` from storage (`localStorage`/JS-readable `cookie`) and
|
|
67
|
-
injects `Authorization: Bearer <token>` into every request. Session
|
|
68
|
-
verification uses the `${authUrl}user/me` probe. Behavior is identical to
|
|
69
|
-
previous versions — existing consumers don't need to change anything.
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
new CreateRelayEnvironment({
|
|
73
|
-
url: 'https://api.example.com/graphql/',
|
|
74
|
-
authUrl: 'https://api.example.com/auth/',
|
|
75
|
-
useAuthorization: true, // injects Bearer
|
|
76
|
-
storageType: 'cookie', // JS-readable cookie or 'localStorage'
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### `authMode: 'cookie'` (httpOnly cookie session — recommended for SPAs)
|
|
81
|
-
|
|
82
|
-
The secure model: the session token lives in an **httpOnly + SameSite**
|
|
83
|
-
cookie (invisible to JS, immune to XSS). The Environment does **not** read
|
|
84
|
-
the token or inject `Authorization` — `credentials: 'include'` (the default
|
|
85
|
-
in this mode) makes the browser attach the cookie automatically, including
|
|
86
|
-
cross-origin. On an auth error (e.g. 401), the refresh is fired as a `POST`
|
|
87
|
-
to `authUrl` with `credentials: 'include'` — **without** probing `user/me`.
|
|
88
|
-
|
|
89
|
-
```ts
|
|
90
|
-
new CreateRelayEnvironment({
|
|
91
|
-
url: 'https://api.example.com/graphql/',
|
|
92
|
-
authUrl: 'https://api.example.com/auth/refresh/', // on-401 refresh target
|
|
93
|
-
authMode: 'cookie',
|
|
94
|
-
redirectOnError: true,
|
|
95
|
-
loginRoute: '/login',
|
|
96
|
-
});
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Related options:
|
|
100
|
-
|
|
101
|
-
| Option | Default | What it does |
|
|
102
|
-
|---|---|---|
|
|
103
|
-
| `authMode` | `'bearer'` | `'bearer'` (token + header) or `'cookie'` (httpOnly). |
|
|
104
|
-
| `credentials` | cookie→`'include'`; bearer→omitted | `RequestCredentials` forwarded to the GraphQL and refresh fetches. Works in both modes. |
|
|
105
|
-
| `sessionCheckUrl` | mode-dependent | Overrides the probe URL; `false` disables the probe (auth error → direct logout, no extra request). |
|
|
106
|
-
|
|
107
|
-
## Scripts (workspace)
|
|
108
|
-
|
|
109
|
-
| Script | What it does |
|
|
110
|
-
|---|---|
|
|
111
|
-
| `yarn workspace @apollion-dsi/relay run validate` | Lint + types + prettier + Jest + build. |
|
|
112
|
-
| `yarn workspace @apollion-dsi/relay run coverage` | Jest coverage. |
|
|
113
|
-
| `yarn workspace @apollion-dsi/relay run build` | esbuild + types emit. |
|
|
114
|
-
| `yarn workspace @apollion-dsi/relay run audit-dependencies` | audit-ci. |
|
|
115
|
-
| `yarn workspace @apollion-dsi/relay run pretest` | `relay-compiler` (generates `__generated__` before the tests). |
|
|
116
|
-
|
|
117
|
-
## License
|
|
118
|
-
|
|
119
|
-
MIT.
|