@econneq/gql-auth 1.2.11 → 2.0.1

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.
Files changed (51) hide show
  1. package/README.md +304 -22
  2. package/dist/api-factory.d.ts +11 -27
  3. package/dist/api-factory.d.ts.map +1 -1
  4. package/dist/api-factory.js +96 -43
  5. package/dist/api-factory.js.map +1 -0
  6. package/dist/authServer.d.ts +28 -1
  7. package/dist/authServer.d.ts.map +1 -1
  8. package/dist/authServer.js +66 -13
  9. package/dist/authServer.js.map +1 -0
  10. package/dist/client.d.ts +28 -11
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +75 -55
  13. package/dist/client.js.map +1 -0
  14. package/dist/env.d.ts +35 -0
  15. package/dist/env.d.ts.map +1 -0
  16. package/dist/env.js +65 -0
  17. package/dist/env.js.map +1 -0
  18. package/dist/errors.d.ts +10 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +24 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/functions.d.ts +21 -3
  23. package/dist/functions.d.ts.map +1 -1
  24. package/dist/functions.js +74 -26
  25. package/dist/functions.js.map +1 -0
  26. package/dist/index.d.ts +11 -50
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +22 -6
  29. package/dist/index.js.map +1 -0
  30. package/dist/query-server.d.ts +31 -9
  31. package/dist/query-server.d.ts.map +1 -1
  32. package/dist/query-server.js +63 -11
  33. package/dist/query-server.js.map +1 -0
  34. package/dist/tenant.d.ts +21 -0
  35. package/dist/tenant.d.ts.map +1 -0
  36. package/dist/tenant.js +50 -0
  37. package/dist/tenant.js.map +1 -0
  38. package/dist/types.d.ts +124 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +5 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/upload-gql.d.ts +2 -17
  43. package/dist/upload-gql.d.ts.map +1 -1
  44. package/dist/upload-gql.js +63 -44
  45. package/dist/upload-gql.js.map +1 -0
  46. package/dist/utils.d.ts +24 -0
  47. package/dist/utils.d.ts.map +1 -0
  48. package/dist/utils.js +257 -0
  49. package/dist/utilsGeneral.d.ts +1 -1
  50. package/dist/utilsGeneral.d.ts.map +1 -1
  51. package/package.json +49 -22
@@ -1,40 +1,93 @@
1
- // utils/authServer.ts
2
- import { cookies } from 'next/headers';
3
- import { jwtDecode } from "jwt-decode";
1
+ // ============================================================
2
+ // @econneq/gql-auth Server-side auth helpers
3
+ // ============================================================
4
+ //
5
+ // These helpers are Next.js-specific (they use next/headers).
6
+ // Import them only in Server Components, Server Actions, or
7
+ // Route Handlers.
8
+ // ─────────────────────────────────────────────────────────────
9
+ "use server";
10
+ // ─── Token ───────────────────────────────────────────────────
11
+ /**
12
+ * Read the JWT from the incoming request cookies.
13
+ * Returns null when no token cookie is present.
14
+ */
4
15
  export const getServerToken = async () => {
5
- const cookieStore = await cookies();
6
- return cookieStore.get("token")?.value || null;
16
+ try {
17
+ const { cookies } = await import("next/headers");
18
+ const cookieStore = await cookies();
19
+ return cookieStore.get("token")?.value ?? null;
20
+ }
21
+ catch {
22
+ // next/headers not available outside of a Next.js context
23
+ return null;
24
+ }
7
25
  };
26
+ // ─── User ─────────────────────────────────────────────────────
27
+ /**
28
+ * Decode the server-side JWT and return the payload.
29
+ * Returns null when no token is present or decoding fails.
30
+ */
8
31
  export const getServerUser = async () => {
9
32
  const token = await getServerToken();
10
33
  if (!token)
11
34
  return null;
12
35
  try {
13
- const user = jwtDecode(token);
14
- return user;
36
+ const { jwtDecode } = await import("jwt-decode");
37
+ return jwtDecode(token);
15
38
  }
16
- catch (error) {
39
+ catch {
17
40
  return null;
18
41
  }
19
42
  };
43
+ // ─── Permissions ─────────────────────────────────────────────
44
+ /**
45
+ * Check whether a permission list grants access to a resource.
46
+ *
47
+ * @param list - Array of permission strings (from JwtPayload.permissions)
48
+ * @param access - Numeric resource/module identifier
49
+ * @param action - Optional action suffix (e.g. "C", "R", "U", "D")
50
+ *
51
+ * @example
52
+ * // Does the user have ANY access to module 42?
53
+ * getPermissions(user.permissions, 42);
54
+ *
55
+ * // Does the user have CREATE access to module 42?
56
+ * getPermissions(user.permissions, 42, "C");
57
+ */
20
58
  export const getPermissions = (list, access, action) => {
21
- if (!list || list.length < 1)
59
+ if (!list?.length)
22
60
  return false;
23
61
  try {
24
- return list.some(entry => {
25
- // If only num is provided, check if entry starts with that number followed by non-digits
62
+ return list.some((entry) => {
26
63
  if (access && !action) {
64
+ // Match "42", "42C", "42R", etc. — but NOT "420"
27
65
  const regex = new RegExp(`^${access}(?!\\d)`);
28
66
  return regex.test(entry);
29
67
  }
30
- // If both are provided, check for the exact combination
31
68
  if (access && action) {
32
69
  return entry === `${access}${action}`;
33
70
  }
34
71
  return false;
35
72
  });
36
73
  }
37
- catch (error) {
74
+ catch {
38
75
  return false;
39
76
  }
40
77
  };
78
+ // ─── Cookie string ────────────────────────────────────────────
79
+ /**
80
+ * Return the full cookie header string for forwarding to the
81
+ * backend (Django session / CSRF pass-through).
82
+ */
83
+ export const getServerCookieString = async () => {
84
+ try {
85
+ const { cookies } = await import("next/headers");
86
+ const cookieStore = await cookies();
87
+ return cookieStore.toString();
88
+ }
89
+ catch {
90
+ return "";
91
+ }
92
+ };
93
+ //# sourceMappingURL=authServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authServer.js","sourceRoot":"","sources":["../src/authServer.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+CAA+C;AAC/C,+DAA+D;AAC/D,EAAE;AACF,8DAA8D;AAC9D,4DAA4D;AAC5D,kBAAkB;AAClB,gEAAgE;AAEhE,YAAY,CAAC;AAIb,gEAAgE;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAA4B,EAAE;IAC/D,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,OAAO,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,iEAAiE;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAgC,EAAE;IAClE,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,IAAI,CAAC;QACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,OAAO,SAAS,CAAa,KAAK,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,gEAAgE;AAEhE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,IAAc,EACd,MAAc,EACd,MAAe,EACN,EAAE;IACX,IAAI,CAAC,IAAI,EAAE,MAAM;QAAE,OAAO,KAAK,CAAC;IAEhC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACzB,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;gBACtB,iDAAiD;gBACjD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC;gBAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3B,CAAC;YAED,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;gBACrB,OAAO,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;YACxC,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC;AAEF,iEAAiE;AAEjE;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,IAAqB,EAAE;IAC/D,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,OAAO,WAAW,CAAC,QAAQ,EAAE,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
package/dist/client.d.ts CHANGED
@@ -1,12 +1,29 @@
1
- import { ApolloClient } from '@apollo/client';
2
- export default function getApolloClient(options?: {
3
- csrfToken?: string;
4
- cookie?: string;
5
- }, domain?: string | null, config?: {
6
- Subdomains: {
7
- subdomain: string;
8
- processId?: string;
9
- widgetID?: string;
10
- }[];
11
- }): Promise<ApolloClient | null>;
1
+ import { ApolloClient } from "@apollo/client";
2
+ import type { ApolloOptions, ConfigType } from "./types";
3
+ /**
4
+ * Inject Next.js `cookies` at app startup to keep this module
5
+ * free of a hard `next/headers` import (which breaks non-Next projects).
6
+ *
7
+ * Call once in your app layout or instrumentation file:
8
+ *
9
+ * ```ts
10
+ * import { cookies } from "next/headers";
11
+ * import { registerCookiesFn } from "@econneq/gql-auth";
12
+ * registerCookiesFn(cookies);
13
+ * ```
14
+ */
15
+ export declare function registerCookiesFn(fn: () => Promise<{
16
+ get: (k: string) => {
17
+ value: string;
18
+ } | undefined;
19
+ toString: () => string;
20
+ }>): void;
21
+ type ClientOptions = {
22
+ options?: ApolloOptions;
23
+ /** Tenant subdomain. Omit for single-tenant. */
24
+ domain?: string | null;
25
+ config: ConfigType;
26
+ };
27
+ export declare function getApolloClient({ options, domain, config, }: ClientOptions): Promise<ApolloClient>;
28
+ export {};
12
29
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AAGvE,wBAA8B,eAAe,CAC3C,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EACjD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,MAAM,CAAC,EAAE;IACP,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5E,GACA,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgE9B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAazD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,MAAM,OAAO,CAAC;IAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,MAAM,CAAA;CAAE,CAAC,GAC/F,IAAI,CAEN;AAID,KAAK,aAAa,GAAG;IACnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,wBAAsB,eAAe,CAAC,EACpC,OAAO,EACP,MAAM,EACN,MAAM,GACP,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA4DvC"}
package/dist/client.js CHANGED
@@ -1,65 +1,85 @@
1
- // src/client.ts
2
- import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
3
- import Cookies from "js-cookie";
4
- export default async function getApolloClient(options, domain, config) {
5
- if (!config)
6
- throw new Error("Configuration is required for getApolloClient");
7
- const isServer = typeof window === "undefined";
8
- const { Subdomains } = config;
9
- // const apiKey = process.env.API_KEY || "";
10
- const urlDomain = process.env.NEXT_PUBLIC_DOMAIN_URL || process.env.DOMAIN_URL; // e.g e-conneq.com
11
- const protocol = process.env.NEXT_PUBLIC_PROTOCOL || process.env.PROTOCOL; // e.g https:// or e.g http://
12
- const urlBackEndInt = process.env.NEXT_PUBLIC_BACKEND_URL_INT || process.env.BACKEND_URL_INT; // e.g api:8000 (docker) or 127.0.0.1:8100 (VPS host) or localhost:8001 (local host)
13
- const urlBackEndExt = process.env.NEXT_PUBLIC_BACKEND_URL_EXT || process.env.BACKEND_URL_EXT; // e.g https://admin.e-conneq.com
14
- if (!urlDomain)
15
- throw new Error("Env (DOMAIN_URL) is required");
16
- if (!protocol)
17
- throw new Error("Env (PROTOCOL) is required");
18
- if (!urlBackEndInt)
19
- throw new Error("Env (BACKEND_URL_INT) is required");
20
- if (!urlBackEndExt)
21
- throw new Error("Env (BACKEND_URL_EXT) is required");
22
- const tenant = domain
23
- ? Subdomains.find((s) => s.subdomain.toLowerCase() === domain.toLowerCase())
24
- : null;
25
- let uri;
26
- let destUrl;
27
- const sourceHost = `${protocol}${tenant?.subdomain || "public"}.${urlDomain}`;
28
- if (isServer) {
29
- destUrl = `http://${urlBackEndInt}`;
30
- uri = `${destUrl}/graphql/`;
1
+ // ============================================================
2
+ // @econneq/gql-auth Apollo Client factory
3
+ // ============================================================
4
+ //
5
+ // • Server-side → uses internal Docker URL + cookie forwarding
6
+ // Client-side → uses /api/graphql proxy + CSRF token
7
+ // Multi-tenant injects X-Tenant-ID / X-Process-ID headers
8
+ // Single-tenant falls back to Subdomains[0]
9
+ // ─────────────────────────────────────────────────────────────
10
+ import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";
11
+ import { Env, assertServerEnv, externalBaseUrl, externalGraphQLUrl, internalGraphQLUrl, isServer, } from "./env";
12
+ import { buildTenantHeaders, resolveTenant } from "./tenant";
13
+ let _cookiesFn = null;
14
+ /**
15
+ * Inject Next.js `cookies` at app startup to keep this module
16
+ * free of a hard `next/headers` import (which breaks non-Next projects).
17
+ *
18
+ * Call once in your app layout or instrumentation file:
19
+ *
20
+ * ```ts
21
+ * import { cookies } from "next/headers";
22
+ * import { registerCookiesFn } from "@econneq/gql-auth";
23
+ * registerCookiesFn(cookies);
24
+ * ```
25
+ */
26
+ export function registerCookiesFn(fn) {
27
+ _cookiesFn = fn;
28
+ }
29
+ export async function getApolloClient({ options, domain, config, }) {
30
+ const server = isServer();
31
+ if (server)
32
+ assertServerEnv();
33
+ // ── Tenant resolution ────────────────────────────────────
34
+ const tenant = resolveTenant(config, domain ? { domain } : undefined);
35
+ const tenantHeaders = buildTenantHeaders(tenant, Env.apiKey);
36
+ // ── URI ─────────────────────────────────────────────────
37
+ const uri = server ? internalGraphQLUrl() : externalGraphQLUrl();
38
+ const destUrl = server
39
+ ? `http://${Env.backendInt}`
40
+ : externalBaseUrl();
41
+ // ── Source host (Referer / Host) ─────────────────────────
42
+ const sourceSubdomain = tenant?.subdomain ?? "public";
43
+ const sourceHost = `${Env.protocol}${sourceSubdomain}.${Env.domainUrl}`;
44
+ // ── CSRF ─────────────────────────────────────────────────
45
+ let csrfToken = options?.csrfToken ?? "";
46
+ if (!csrfToken && !server) {
47
+ try {
48
+ // Lazy import so SSR never executes this branch
49
+ const Cookies = (await import("js-cookie")).default;
50
+ csrfToken = Cookies.get("csrftoken") ?? "";
51
+ }
52
+ catch {
53
+ // js-cookie not available in some environments
54
+ }
31
55
  }
32
- else {
33
- uri = "/api/graphql";
34
- destUrl = `${protocol}${urlBackEndExt}`;
56
+ // ── Cookie forwarding (server → backend) ─────────────────
57
+ let cookieHeader = options?.cookie ?? "";
58
+ if (!cookieHeader && server && _cookiesFn) {
59
+ try {
60
+ const store = await _cookiesFn();
61
+ cookieHeader = store.toString();
62
+ }
63
+ catch {
64
+ // cookies() may throw outside a request context
65
+ }
35
66
  }
36
- console.log("g-auth uri ==============", uri);
37
- console.log("g-auth sourceHost =======", sourceHost);
38
- console.log("g-auth destinationHost ==========", destUrl);
39
- const csrfToken = options?.csrfToken || (!isServer ? Cookies.get("csrftoken") : "");
67
+ // ── Assemble headers ─────────────────────────────────────
40
68
  const headers = {
41
- 'Content-Type': 'application/json',
42
- // 'X-API-KEY': apiKey,
43
- ...(options?.cookie && { 'Cookie': options.cookie }),
44
- ...(csrfToken && { 'X-CSRFToken': csrfToken }),
45
- ...(tenant && {
46
- 'X-Tenant-ID': tenant.subdomain,
47
- 'X-Process-ID': tenant?.processId || "",
48
- 'X-Widget-ID': tenant?.widgetID || "",
49
- }),
50
- 'Referer': destUrl,
51
- 'Host': isServer ? sourceHost : window.location.host,
69
+ "Content-Type": "application/json",
70
+ ...tenantHeaders,
71
+ ...(cookieHeader ? { Cookie: cookieHeader } : {}),
72
+ ...(csrfToken ? { "X-CSRFToken": csrfToken } : {}),
73
+ Referer: destUrl,
74
+ Host: server ? sourceHost : (typeof window !== "undefined" ? window.location.host : sourceHost),
52
75
  };
53
76
  return new ApolloClient({
54
- link: new HttpLink({
55
- uri,
56
- fetch,
57
- headers,
58
- }),
77
+ link: new HttpLink({ uri, fetch, headers }),
59
78
  cache: new InMemoryCache(),
60
79
  defaultOptions: {
61
- mutate: { fetchPolicy: 'no-cache' },
62
- query: { fetchPolicy: 'no-cache' },
80
+ mutate: { fetchPolicy: "no-cache" },
81
+ query: { fetchPolicy: "no-cache" },
63
82
  },
64
83
  });
65
84
  }
85
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export declare const Env: {
2
+ /** e.g. "e-conneq.com" */
3
+ readonly domainUrl: string;
4
+ /** e.g. "https://" */
5
+ readonly protocol: string;
6
+ /**
7
+ * Internal backend used from within the Docker network (server-side).
8
+ * e.g. "api:8000"
9
+ */
10
+ readonly backendInt: string;
11
+ /**
12
+ * External backend reachable from the browser.
13
+ * e.g. "admin.e-conneq.com"
14
+ */
15
+ readonly backendExt: string;
16
+ /** Optional service-to-service API key. */
17
+ readonly apiKey: string;
18
+ };
19
+ export declare function assertServerEnv(): void;
20
+ export declare const isServer: () => boolean;
21
+ /**
22
+ * GraphQL endpoint used by server-side code (internal Docker network).
23
+ * e.g. http://api:8000/graphql/
24
+ */
25
+ export declare const internalGraphQLUrl: () => string;
26
+ /**
27
+ * GraphQL endpoint used by browser code (proxied Next.js API route).
28
+ */
29
+ export declare const externalGraphQLUrl: () => string;
30
+ /**
31
+ * Full external base URL.
32
+ * e.g. https://admin.e-conneq.com
33
+ */
34
+ export declare const externalBaseUrl: () => string;
35
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,GAAG;IACd,0BAA0B;;IAG1B,sBAAsB;;IAGtB;;;OAGG;;IAGH;;;OAGG;;IAGH,2CAA2C;;CAEnC,CAAC;AAIX,wBAAgB,eAAe,IAAI,IAAI,CAWtC;AAID,eAAO,MAAM,QAAQ,QAAO,OAAwC,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,MACD,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAAO,MAAwB,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAO,MACC,CAAC"}
package/dist/env.js ADDED
@@ -0,0 +1,65 @@
1
+ // ============================================================
2
+ // @econneq/gql-auth — Environment resolver
3
+ // ============================================================
4
+ //
5
+ // All env variables are consumed here so the rest of the
6
+ // codebase never touches process.env directly.
7
+ // ─────────────────────────────────────────────────────────────
8
+ const get = (keys) => {
9
+ for (const key of keys) {
10
+ const val = typeof process !== "undefined" ? process.env[key] : undefined;
11
+ if (val)
12
+ return val;
13
+ }
14
+ return "";
15
+ };
16
+ export const Env = {
17
+ /** e.g. "e-conneq.com" */
18
+ domainUrl: get(["NEXT_PUBLIC_DOMAIN_URL", "DOMAIN_URL"]),
19
+ /** e.g. "https://" */
20
+ protocol: get(["NEXT_PUBLIC_PROTOCOL", "PROTOCOL"]),
21
+ /**
22
+ * Internal backend used from within the Docker network (server-side).
23
+ * e.g. "api:8000"
24
+ */
25
+ backendInt: get(["BACKEND_URL_INT", "NEXT_PUBLIC_BACKEND_URL_INT"]),
26
+ /**
27
+ * External backend reachable from the browser.
28
+ * e.g. "admin.e-conneq.com"
29
+ */
30
+ backendExt: get(["NEXT_PUBLIC_BACKEND_URL_EXT", "BACKEND_URL_EXT"]),
31
+ /** Optional service-to-service API key. */
32
+ apiKey: get(["API_KEY", "NEXT_PUBLIC_API_KEY"]),
33
+ };
34
+ // ─── Runtime validators ───────────────────────────────────────
35
+ export function assertServerEnv() {
36
+ const missing = [];
37
+ if (!Env.domainUrl)
38
+ missing.push("DOMAIN_URL");
39
+ if (!Env.protocol)
40
+ missing.push("PROTOCOL");
41
+ if (!Env.backendInt)
42
+ missing.push("BACKEND_URL_INT");
43
+ if (!Env.backendExt)
44
+ missing.push("BACKEND_URL_EXT");
45
+ if (missing.length) {
46
+ throw new Error(`[@econneq/gql-auth] Missing required env variables: ${missing.join(", ")}`);
47
+ }
48
+ }
49
+ // ─── URL builders ─────────────────────────────────────────────
50
+ export const isServer = () => typeof window === "undefined";
51
+ /**
52
+ * GraphQL endpoint used by server-side code (internal Docker network).
53
+ * e.g. http://api:8000/graphql/
54
+ */
55
+ export const internalGraphQLUrl = () => `http://${Env.backendInt}/graphql/`;
56
+ /**
57
+ * GraphQL endpoint used by browser code (proxied Next.js API route).
58
+ */
59
+ export const externalGraphQLUrl = () => `/api/graphql`;
60
+ /**
61
+ * Full external base URL.
62
+ * e.g. https://admin.e-conneq.com
63
+ */
64
+ export const externalBaseUrl = () => `${Env.protocol}${Env.backendExt}`;
65
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,2CAA2C;AAC3C,+DAA+D;AAC/D,EAAE;AACF,yDAAyD;AACzD,+CAA+C;AAC/C,gEAAgE;AAEhE,MAAM,GAAG,GAAG,CAAC,IAAc,EAAU,EAAE;IACrC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,GAAG,GACP,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAE,OAAO,CAAC,GAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,0BAA0B;IAC1B,SAAS,EAAE,GAAG,CAAC,CAAC,wBAAwB,EAAE,YAAY,CAAC,CAAC;IAExD,sBAAsB;IACtB,QAAQ,EAAE,GAAG,CAAC,CAAC,sBAAsB,EAAE,UAAU,CAAC,CAAC;IAEnD;;;OAGG;IACH,UAAU,EAAE,GAAG,CAAC,CAAC,iBAAiB,EAAE,6BAA6B,CAAC,CAAC;IAEnE;;;OAGG;IACH,UAAU,EAAE,GAAG,CAAC,CAAC,6BAA6B,EAAE,iBAAiB,CAAC,CAAC;IAEnE,2CAA2C;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;CACvC,CAAC;AAEX,iEAAiE;AAEjE,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC/C,IAAI,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,CAAC,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACrD,IAAI,CAAC,GAAG,CAAC,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,uDAAuD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5E,CAAC;IACJ,CAAC;AACH,CAAC;AAED,iEAAiE;AAEjE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAY,EAAE,CAAC,OAAO,MAAM,KAAK,WAAW,CAAC;AAErE;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAW,EAAE,CAC7C,UAAU,GAAG,CAAC,UAAU,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAW,EAAE,CAAC,cAAc,CAAC;AAE/D;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAW,EAAE,CAC1C,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type ParsedError = {
2
+ message: string;
3
+ code?: string;
4
+ };
5
+ /**
6
+ * Convert raw GraphQL errors into user-friendly strings.
7
+ * Extend the switch/map here to handle more backend error codes.
8
+ */
9
+ export declare function parseGraphQLErrors(errors: any[]): string[];
10
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAY1D"}
package/dist/errors.js ADDED
@@ -0,0 +1,24 @@
1
+ // ============================================================
2
+ // @econneq/gql-auth — GraphQL error parser
3
+ // ============================================================
4
+ /**
5
+ * Convert raw GraphQL errors into user-friendly strings.
6
+ * Extend the switch/map here to handle more backend error codes.
7
+ */
8
+ export function parseGraphQLErrors(errors) {
9
+ return errors.map((err) => {
10
+ const msg = err?.message ?? "Unknown error";
11
+ if (/duplicate/i.test(msg))
12
+ return "Record already exists ❌";
13
+ if (/authentication/i.test(msg))
14
+ return "Login required ❌";
15
+ if (/permission/i.test(msg))
16
+ return "Permission denied ❌";
17
+ if (/not found/i.test(msg))
18
+ return "Record not found ❌";
19
+ if (/unique constraint/i.test(msg))
20
+ return "Duplicate value ❌";
21
+ return msg;
22
+ });
23
+ }
24
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,2CAA2C;AAC3C,+DAA+D;AAO/D;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAa;IAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAU,EAAE;QAChC,MAAM,GAAG,GAAW,GAAG,EAAE,OAAO,IAAI,eAAe,CAAC;QAEpD,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,yBAAyB,CAAC;QAC7D,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,kBAAkB,CAAC;QAC3D,IAAI,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,qBAAqB,CAAC;QAC1D,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,oBAAoB,CAAC;QACxD,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,mBAAmB,CAAC;QAE/D,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1,6 +1,24 @@
1
- import { JwtPayload } from "./index.js";
2
- export declare const logout: () => void;
1
+ import type { JwtPayload } from "./types";
2
+ /**
3
+ * Read the JWT from cookies first, then localStorage.
4
+ * Returns null on the server (window is undefined).
5
+ */
3
6
  export declare const getToken: () => string | null;
7
+ /**
8
+ * Decode the JWT and return the payload.
9
+ * Returns null when no token is present or decoding fails.
10
+ */
4
11
  export declare const getUser: () => JwtPayload | null;
5
- export declare const removeEmptyFields: (obj: any) => any;
12
+ /**
13
+ * Clear all session state client-side.
14
+ * Does NOT call any server endpoint — combine with a Server Action
15
+ * or API route if you need to invalidate the session server-side.
16
+ */
17
+ export declare const logout: () => void;
18
+ /**
19
+ * Strip null / undefined / empty-string fields from an object
20
+ * before sending it as GraphQL variables.
21
+ * File objects are always preserved.
22
+ */
23
+ export declare const removeEmptyFields: <T extends Record<string, any>>(obj: T) => Partial<T>;
6
24
  //# sourceMappingURL=functions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,eAAO,MAAM,MAAM,YAclB,CAAC;AAEF,eAAO,MAAM,QAAQ,qBAKpB,CAAC;AAEF,eAAO,MAAM,OAAO,yBAInB,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,KAAK,GAAG,QAUzC,CAAC"}
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C;;;GAGG;AACH,eAAO,MAAM,QAAQ,QAAO,MAAM,GAAG,IAgBpC,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,OAAO,QAAO,UAAU,GAAG,IAavC,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,MAAM,QAAO,IAezB,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC7D,KAAK,CAAC,KACL,OAAO,CAAC,CAAC,CAuBX,CAAC"}
package/dist/functions.js CHANGED
@@ -1,38 +1,86 @@
1
- import Cookies from "js-cookie";
2
- import { jwtDecode } from "jwt-decode";
3
- export const logout = () => {
4
- // 1. Clear Local Storage
5
- localStorage.removeItem("token");
6
- const tokenDeleteString = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;";
7
- document.cookie = tokenDeleteString;
8
- // 3. Fallback: Clear ALL cookies (your original loop)
9
- const cookies = document.cookie.split(";");
10
- for (let i = 0; i < cookies.length; i++) {
11
- const cookie = cookies[i];
12
- const eqPos = cookie.indexOf("=");
13
- const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();
14
- document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`;
15
- }
16
- };
1
+ // ============================================================
2
+ // @econneq/gql-auth Client utilities
3
+ // ============================================================
4
+ // ─── Token ───────────────────────────────────────────────────
5
+ /**
6
+ * Read the JWT from cookies first, then localStorage.
7
+ * Returns null on the server (window is undefined).
8
+ */
17
9
  export const getToken = () => {
18
- if (typeof window === "undefined") {
10
+ if (typeof window === "undefined")
19
11
  return null;
12
+ try {
13
+ // Prefer cookie (set by server on login)
14
+ const fromCookie = document.cookie
15
+ .split("; ")
16
+ .find((row) => row.startsWith("token="))
17
+ ?.split("=")?.[1];
18
+ if (fromCookie)
19
+ return fromCookie;
20
20
  }
21
- return Cookies.get("token") || localStorage.getItem("token");
21
+ catch {
22
+ // Cookies blocked (e.g. incognito with strict settings)
23
+ }
24
+ return localStorage.getItem("token");
22
25
  };
26
+ // ─── User ────────────────────────────────────────────────────
27
+ /**
28
+ * Decode the JWT and return the payload.
29
+ * Returns null when no token is present or decoding fails.
30
+ */
23
31
  export const getUser = () => {
24
32
  const token = getToken();
25
- const user = token ? jwtDecode(token) : null;
26
- return user;
33
+ if (!token)
34
+ return null;
35
+ try {
36
+ // jwtDecode is a peer dependency — lazy-required to keep SSR safe
37
+ const { jwtDecode } = require("jwt-decode");
38
+ return jwtDecode(token);
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ };
44
+ // ─── Logout ──────────────────────────────────────────────────
45
+ /**
46
+ * Clear all session state client-side.
47
+ * Does NOT call any server endpoint — combine with a Server Action
48
+ * or API route if you need to invalidate the session server-side.
49
+ */
50
+ export const logout = () => {
51
+ if (typeof window === "undefined")
52
+ return;
53
+ localStorage.removeItem("token");
54
+ // Expire the token cookie
55
+ document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;";
56
+ // Expire every other cookie for this origin
57
+ document.cookie.split(";").forEach((c) => {
58
+ const name = c.trim().split("=")?.[0];
59
+ if (name) {
60
+ document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`;
61
+ }
62
+ });
27
63
  };
64
+ // ─── Data helpers ─────────────────────────────────────────────
65
+ /**
66
+ * Strip null / undefined / empty-string fields from an object
67
+ * before sending it as GraphQL variables.
68
+ * File objects are always preserved.
69
+ */
28
70
  export const removeEmptyFields = (obj) => {
29
- const newObj = {};
71
+ const result = {};
30
72
  for (const key in obj) {
31
- // Keep File objects and non-empty values
32
- if (obj[key] instanceof File ||
33
- (obj[key] !== null && obj[key] !== undefined && obj[key] !== '')) {
34
- newObj[key] = obj[key];
73
+ const value = obj[key];
74
+ const v = value;
75
+ const isFile = typeof File !== "undefined" &&
76
+ typeof v === "object" &&
77
+ v !== null &&
78
+ v instanceof File;
79
+ if (isFile ||
80
+ (value !== null && value !== undefined && value !== "")) {
81
+ result[key] = value;
35
82
  }
36
83
  }
37
- return newObj;
84
+ return result;
38
85
  };
86
+ //# sourceMappingURL=functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.js","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,uCAAuC;AACvC,+DAA+D;AAI/D,gEAAgE;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAkB,EAAE;IAC1C,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAE/C,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;aAC/B,KAAK,CAAC,IAAI,CAAC;aACX,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACxC,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAEpB,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IAED,OAAO,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF,gEAAgE;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,GAAsB,EAAE;IAC7C,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,IAAI,CAAC;QACH,kEAAkE;QAClE,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,YAAY,CAEzC,CAAC;QACF,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,gEAAgE;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAS,EAAE;IAC/B,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO;IAE1C,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAEjC,0BAA0B;IAC1B,QAAQ,CAAC,MAAM,GAAG,wDAAwD,CAAC;IAE3E,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,IAAI,EAAE,CAAC;YACT,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,mDAAmD,CAAC;QAC/E,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,iEAAiE;AAEjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,GAAM,EACM,EAAE;IACd,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QAExB,MAAM,CAAC,GAAG,KAAgB,CAAC;QAE9B,MAAM,MAAM,GACV,OAAO,IAAI,KAAK,WAAW;YAC3B,OAAO,CAAC,KAAK,QAAQ;YACrB,CAAC,KAAK,IAAI;YACV,CAAC,YAAY,IAAI,CAAC;QAEhB,IACE,MAAM;YACN,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,EACvD,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}