@gusnips/react 0.1.0 → 0.2.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/dist/guards.d.ts CHANGED
@@ -21,13 +21,21 @@ export interface SessionState {
21
21
  /**
22
22
  * The answer to a "who is this?" query, in the three states it actually has.
23
23
  *
24
- * This shape is invariant 4. A guard reading `!me?.isStaff` collapses "loading", "failed" and
24
+ * This shape is invariant 4. A guard reading `!me?.isStaff` collapses "pending", "failed" and
25
25
  * "no" into one branch — so an operator arriving while `/auth/me` is 500ing is told the page
26
26
  * does not exist. Wrong cause, no retry, and no request id to quote to support. One donor hit
27
27
  * that and fixed it; the other still has the collapsed version.
28
+ *
29
+ * `"pending"` and not `"loading"` for one measured reason: it is react-query's own word for this
30
+ * state since v5, and with the words matching a `UseQueryResult<TMe>` satisfies this type
31
+ * STRUCTURALLY — `createRequireProfile(useMe, …)` takes the hook directly, no adapter. With
32
+ * `"loading"` it does not typecheck and every adopter hand-writes the same six-line mapping;
33
+ * eight of the twelve repos this serves are on react-query, and the first migration wrote that
34
+ * mapping before anyone noticed. Nothing here imports react-query at runtime — the type stays
35
+ * structural, so an app on SWR or a plain `useState` still answers it in three lines.
28
36
  */
29
37
  export type MeQuery<TMe> = {
30
- status: "loading";
38
+ status: "pending";
31
39
  } | {
32
40
  status: "error";
33
41
  error: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;;;GAaG;AAEH,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,CAAC,GAAG,IACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,OAAO,EAAE,SAAS,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,YAAY,EAC9B,UAAU,EAAE,MAAM,EAClB,EAAE,OAAO,EAAE,EAAE,YAAY,IAEG,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAUlE;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,YAAY,EAC9B,QAAQ,EAAE,MAAM,EAChB,EAAE,OAAO,EAAE,EAAE,YAAY,IAEQ,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAMvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,YAAY,IAE1F,OAAO,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,EAC3B,UAAU,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,EACvC,SAAS,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,MAEP,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAQvE"}
1
+ {"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../src/guards.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;;;GAaG;AAEH,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,OAAO,CAAC,GAAG,IACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAAC;AAajG,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,OAAO,EAAE,SAAS,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,YAAY,EAC9B,UAAU,EAAE,MAAM,EAClB,EAAE,OAAO,EAAE,EAAE,YAAY,IAEG,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAUlE;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,YAAY,EAC9B,QAAQ,EAAE,MAAM,EAChB,EAAE,OAAO,EAAE,EAAE,YAAY,IAEQ,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAMvE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,YAAY,IAE1F,OAAO,CAAC,EAAE,EAAE,GAAG,KAAK,OAAO,EAC3B,UAAU,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,EACvC,SAAS,CAAC,KAAK,EAAE,OAAO,KAAK,SAAS,MAEP,cAAc;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,iCAQvE"}
package/dist/guards.js CHANGED
@@ -39,7 +39,7 @@ export function createRequireProfile(useMe, { loading }) {
39
39
  return function requireProfile(allow, onDenied, onError) {
40
40
  return function RequireProfile({ children }) {
41
41
  const query = useMe();
42
- if (query.status === "loading")
42
+ if (query.status === "pending")
43
43
  return _jsx(_Fragment, { children: loading });
44
44
  if (query.status === "error")
45
45
  return _jsx(_Fragment, { children: onError(query.error) });
@@ -1 +1 @@
1
- {"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAuCzD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAA8B,EAC9B,UAAkB,EAClB,EAAE,OAAO,EAAgB;IAEzB,OAAO,SAAS,WAAW,CAAC,EAAE,QAAQ,EAA2B;QAC/D,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,IAAI,SAAS;YAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;QACrC,IAAI,CAAC,eAAe;YAClB,OAAO,CACL,KAAC,QAAQ,IAAC,EAAE,EAAE,UAAU,EAAE,OAAO,QAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAI,CAC3F,CAAC;QACJ,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CACpC,UAA8B,EAC9B,QAAgB,EAChB,EAAE,OAAO,EAAgB;IAEzB,OAAO,SAAS,gBAAgB,CAAC,EAAE,QAAQ,EAA2B;QACpE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;QACpD,IAAI,SAAS;YAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;QACrC,IAAI,eAAe;YAAE,OAAO,KAAC,QAAQ,IAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,SAAG,CAAC;QAC/D,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAM,KAAyB,EAAE,EAAE,OAAO,EAAgB;IAC5F,OAAO,SAAS,cAAc,CAC5B,KAA2B,EAC3B,QAAuC,EACvC,OAAsC;QAEtC,OAAO,SAAS,cAAc,CAAC,EAAE,QAAQ,EAA2B;YAClE,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC;YACtB,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,4BAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAI,CAAC;YACjE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,OAAO,4BAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAI,CAAC;YAC7F,OAAO,4BAAG,QAAQ,GAAI,CAAC;QACzB,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../src/guards.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA0DzD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAA8B,EAC9B,UAAkB,EAClB,EAAE,OAAO,EAAgB;IAEzB,OAAO,SAAS,WAAW,CAAC,EAAE,QAAQ,EAA2B;QAC/D,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,IAAI,SAAS;YAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;QACrC,IAAI,CAAC,eAAe;YAClB,OAAO,CACL,KAAC,QAAQ,IAAC,EAAE,EAAE,UAAU,EAAE,OAAO,QAAC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,GAAI,CAC3F,CAAC;QACJ,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CACpC,UAA8B,EAC9B,QAAgB,EAChB,EAAE,OAAO,EAAgB;IAEzB,OAAO,SAAS,gBAAgB,CAAC,EAAE,QAAQ,EAA2B;QACpE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,CAAC;QACpD,IAAI,SAAS;YAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;QACrC,IAAI,eAAe;YAAE,OAAO,KAAC,QAAQ,IAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,SAAG,CAAC;QAC/D,OAAO,4BAAG,QAAQ,GAAI,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAM,KAAyB,EAAE,EAAE,OAAO,EAAgB;IAC5F,OAAO,SAAS,cAAc,CAC5B,KAA2B,EAC3B,QAAuC,EACvC,OAAsC;QAEtC,OAAO,SAAS,cAAc,CAAC,EAAE,QAAQ,EAA2B;YAClE,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC;YACtB,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;gBAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;YACtD,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,4BAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAI,CAAC;YACjE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,OAAO,4BAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAI,CAAC;YAC7F,OAAO,4BAAG,QAAQ,GAAI,CAAC;QACzB,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gusnips/react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "The headless runtime under a Vite + React SPA: typed fetch client with single-flight refresh, auth store, query defaults, route guards, error boundary, chunk-reload recovery, i18n bootstrap.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/guards.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ import type { UseQueryResult } from "@tanstack/react-query";
1
2
  import type { ReactNode } from "react";
2
3
  import { Navigate, useLocation } from "react-router-dom";
3
4
 
@@ -25,13 +26,32 @@ export interface SessionState {
25
26
  /**
26
27
  * The answer to a "who is this?" query, in the three states it actually has.
27
28
  *
28
- * This shape is invariant 4. A guard reading `!me?.isStaff` collapses "loading", "failed" and
29
+ * This shape is invariant 4. A guard reading `!me?.isStaff` collapses "pending", "failed" and
29
30
  * "no" into one branch — so an operator arriving while `/auth/me` is 500ing is told the page
30
31
  * does not exist. Wrong cause, no retry, and no request id to quote to support. One donor hit
31
32
  * that and fixed it; the other still has the collapsed version.
33
+ *
34
+ * `"pending"` and not `"loading"` for one measured reason: it is react-query's own word for this
35
+ * state since v5, and with the words matching a `UseQueryResult<TMe>` satisfies this type
36
+ * STRUCTURALLY — `createRequireProfile(useMe, …)` takes the hook directly, no adapter. With
37
+ * `"loading"` it does not typecheck and every adopter hand-writes the same six-line mapping;
38
+ * eight of the twelve repos this serves are on react-query, and the first migration wrote that
39
+ * mapping before anyone noticed. Nothing here imports react-query at runtime — the type stays
40
+ * structural, so an app on SWR or a plain `useState` still answers it in three lines.
32
41
  */
33
42
  export type MeQuery<TMe> =
34
- { status: "loading" } | { status: "error"; error: unknown } | { status: "success"; data: TMe };
43
+ { status: "pending" } | { status: "error"; error: unknown } | { status: "success"; data: TMe };
44
+
45
+ /**
46
+ * The paragraph above, pinned so it cannot quietly stop being true. A renamed state or a newly
47
+ * required field stops compiling HERE, which is cheaper than eight repos each finding out by
48
+ * writing an adapter. `import type` erases, so the built barrel never mentions react-query —
49
+ * `bun run exports` is what proves that, and it is why the peer stays optional.
50
+ */
51
+ type Satisfied<T extends true> = T;
52
+ type _QueryResultIsAMeQuery = Satisfied<
53
+ UseQueryResult<{ id: string }, Error> extends MeQuery<{ id: string }> ? true : false
54
+ >;
35
55
 
36
56
  export interface GuardOptions {
37
57
  /** Drawn while the session or the profile is still resolving. */
@@ -90,7 +110,7 @@ export function createRequireProfile<TMe>(useMe: () => MeQuery<TMe>, { loading }
90
110
  ) {
91
111
  return function RequireProfile({ children }: { children: ReactNode }) {
92
112
  const query = useMe();
93
- if (query.status === "loading") return <>{loading}</>;
113
+ if (query.status === "pending") return <>{loading}</>;
94
114
  if (query.status === "error") return <>{onError(query.error)}</>;
95
115
  if (!allow(query.data)) return <>{typeof onDenied === "function" ? onDenied() : onDenied}</>;
96
116
  return <>{children}</>;