asma-core-helpers 0.10.0 → 0.12.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.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * createTadaBrowserClient — shared urql client factory for ASMA frontend apps.
3
+ *
4
+ * Wraps the urql core (fetchExchange + optional service-specific exchanges) with
5
+ * an authExchange that attaches a JWT Bearer token and refreshes on 401.
6
+ *
7
+ * URL resolution stays in the app (imports EnvConfigs from asma-helpers);
8
+ * this factory accepts the resolved URL so it has zero dependency on asma-helpers.
9
+ *
10
+ * @see asma-modules/_docs/frontend/operations/2026-07-11-23-00-runbook-graphql-schema-generation-secrets.md
11
+ */
12
+ import { type Client, type ClientOptions, type Exchange } from '@urql/core';
13
+ /**
14
+ * Contributes service-specific exchanges (e.g. the Adopus per-tenant namespace
15
+ * rewrite) without baking that knowledge into the generic factory. Called once
16
+ * per client build with the resolved endpoint; returned exchanges are inserted
17
+ * just before `fetchExchange` (and after `authExchange`).
18
+ */
19
+ export type ResolveExchanges = (ctx: {
20
+ /** The fully-resolved GraphQL endpoint URL. */
21
+ url: string;
22
+ /** Resolves the current JWT (may be stale — the auth exchange handles refresh). */
23
+ getJwt: () => Promise<string | undefined>;
24
+ }) => Exchange[] | Promise<Exchange[]>;
25
+ export interface CreateTadaBrowserClientOptions {
26
+ /** Fully-resolved GraphQL endpoint URL (caller resolves via EnvConfigs / srv_urls). */
27
+ url: string;
28
+ /** Resolves the current JWT. Typically `getCachedJwt` from asma-core-react. */
29
+ getJwt: () => Promise<string | undefined>;
30
+ /** Returns true when the cached JWT is still valid. Typically `isJwtValid` from asma-core-react. */
31
+ isJwtValid: () => boolean;
32
+ /** Optional service-specific exchanges injected before fetchExchange. */
33
+ resolveExchanges?: ResolveExchanges;
34
+ /** Passthrough to urql ClientOptions (url is overridden by the `url` param above). */
35
+ clientOptions?: Partial<ClientOptions>;
36
+ }
37
+ /**
38
+ * Creates a configured, authenticated urql Client for an ASMA frontend app.
39
+ *
40
+ * Exchange order (first = outermost):
41
+ * 1. authExchange — attach Bearer token, refresh on 401
42
+ * 2. resolveExchanges — optional service-specific transforms (e.g. namespace)
43
+ * 3. fetchExchange — standard HTTP fetch
44
+ * 4. caller-provided — appended via clientOptions.exchanges (end of pipeline)
45
+ */
46
+ export declare function createTadaBrowserClient({ url, getJwt, isJwtValid, resolveExchanges, clientOptions, }: CreateTadaBrowserClientOptions): {
47
+ getClient: () => Promise<Client>;
48
+ createClient: (opts?: {
49
+ clientOptions?: Partial<ClientOptions>;
50
+ anonymous?: boolean;
51
+ }) => Promise<Client>;
52
+ };
53
+ //# sourceMappingURL=createTadaBrowserClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTadaBrowserClient.d.ts","sourceRoot":"","sources":["../../src/helpers/createTadaBrowserClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EACH,KAAK,MAAM,EACX,KAAK,aAAa,EAElB,KAAK,QAAQ,EAEhB,MAAM,YAAY,CAAA;AAGnB;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE;IACjC,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAA;IACX,mFAAmF;IACnF,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAC5C,KAAK,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;AAEtC,MAAM,WAAW,8BAA8B;IAC3C,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAA;IACX,+EAA+E;IAC/E,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzC,oGAAoG;IACpG,UAAU,EAAE,MAAM,OAAO,CAAA;IACzB,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,sFAAsF;IACtF,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;CACzC;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,EACpC,GAAG,EACH,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,aAAa,GAChB,EAAE,8BAA8B,GAAG;IAAE,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAiElL"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * createTadaBrowserClient — shared urql client factory for ASMA frontend apps.
3
+ *
4
+ * Wraps the urql core (fetchExchange + optional service-specific exchanges) with
5
+ * an authExchange that attaches a JWT Bearer token and refreshes on 401.
6
+ *
7
+ * URL resolution stays in the app (imports EnvConfigs from asma-helpers);
8
+ * this factory accepts the resolved URL so it has zero dependency on asma-helpers.
9
+ *
10
+ * @see asma-modules/_docs/frontend/operations/2026-07-11-23-00-runbook-graphql-schema-generation-secrets.md
11
+ */
12
+ import { createClient, fetchExchange, } from '@urql/core';
13
+ import { authExchange } from '@urql/exchange-auth';
14
+ /**
15
+ * Creates a configured, authenticated urql Client for an ASMA frontend app.
16
+ *
17
+ * Exchange order (first = outermost):
18
+ * 1. authExchange — attach Bearer token, refresh on 401
19
+ * 2. resolveExchanges — optional service-specific transforms (e.g. namespace)
20
+ * 3. fetchExchange — standard HTTP fetch
21
+ * 4. caller-provided — appended via clientOptions.exchanges (end of pipeline)
22
+ */
23
+ export function createTadaBrowserClient({ url, getJwt, isJwtValid, resolveExchanges, clientOptions, }) {
24
+ let tadaClient;
25
+ const getClient = async () => {
26
+ tadaClient = await buildClient({ clientOptions });
27
+ return tadaClient;
28
+ };
29
+ async function buildClient(opts) {
30
+ const _clientOptions = { ...(opts?.clientOptions ?? {}) };
31
+ const anonymous = opts?.anonymous;
32
+ _clientOptions.url = url;
33
+ _clientOptions.preferGetMethod = false;
34
+ _clientOptions.requestPolicy = 'cache-and-network';
35
+ // Start with fetchExchange + caller-provided exchanges
36
+ _clientOptions.exchanges = [
37
+ fetchExchange,
38
+ ...(_clientOptions.exchanges || []),
39
+ ];
40
+ // Inject service-specific exchanges before fetchExchange
41
+ if (resolveExchanges) {
42
+ const extra = await resolveExchanges({
43
+ getJwt,
44
+ url,
45
+ });
46
+ if (extra.length) {
47
+ _clientOptions.exchanges.unshift(...extra);
48
+ }
49
+ }
50
+ // authExchange is outermost (first to receive the operation)
51
+ if (!anonymous) {
52
+ _clientOptions.exchanges.unshift(authExchange(async (utils) => {
53
+ const token = await getJwt();
54
+ return {
55
+ addAuthToOperation(operation) {
56
+ return utils.appendHeaders(operation, {
57
+ Authorization: `Bearer ${token}`,
58
+ });
59
+ },
60
+ didAuthError(error) {
61
+ return error.response.status === 401;
62
+ },
63
+ async refreshAuth() {
64
+ tadaClient = await buildClient({ clientOptions: opts?.clientOptions });
65
+ },
66
+ willAuthError() {
67
+ return !isJwtValid();
68
+ },
69
+ };
70
+ }));
71
+ }
72
+ return createClient(_clientOptions);
73
+ }
74
+ return { getClient, createClient: buildClient };
75
+ }
76
+ //# sourceMappingURL=createTadaBrowserClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTadaBrowserClient.js","sourceRoot":"","sources":["../../src/helpers/createTadaBrowserClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAGH,YAAY,EAEZ,aAAa,GAChB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AA4BlD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACpC,GAAG,EACH,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,aAAa,GACgB;IAC7B,IAAI,UAA8B,CAAA;IAElC,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;QACzB,UAAU,GAAG,MAAM,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC,CAAA;QACjD,OAAO,UAAU,CAAA;IACrB,CAAC,CAAA;IAED,KAAK,UAAU,WAAW,CAAC,IAG1B;QACG,MAAM,cAAc,GAA2B,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,IAAI,EAAE,CAAC,EAAE,CAAA;QACjF,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,CAAA;QAEjC,cAAc,CAAC,GAAG,GAAG,GAAG,CAAA;QACxB,cAAc,CAAC,eAAe,GAAG,KAAK,CAAA;QACtC,cAAc,CAAC,aAAa,GAAG,mBAAmB,CAAA;QAElD,uDAAuD;QACvD,cAAc,CAAC,SAAS,GAAG;YACvB,aAAa;YACb,GAAG,CAAC,cAAc,CAAC,SAAS,IAAI,EAAE,CAAC;SACtC,CAAA;QAED,yDAAyD;QACzD,IAAI,gBAAgB,EAAE,CAAC;YACnB,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC;gBACjC,MAAM;gBACN,GAAG;aACN,CAAC,CAAA;YACF,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACf,cAAc,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,CAAA;YAC9C,CAAC;QACL,CAAC;QAED,6DAA6D;QAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,cAAc,CAAC,SAAS,CAAC,OAAO,CAC5B,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACzB,MAAM,KAAK,GAAG,MAAM,MAAM,EAAE,CAAA;gBAC5B,OAAO;oBACH,kBAAkB,CAAC,SAAS;wBACxB,OAAO,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE;4BAClC,aAAa,EAAE,UAAU,KAAK,EAAE;yBACnC,CAAC,CAAA;oBACN,CAAC;oBACD,YAAY,CAAC,KAAK;wBACd,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAA;oBACxC,CAAC;oBACD,KAAK,CAAC,WAAW;wBACb,UAAU,GAAG,MAAM,WAAW,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAA;oBAC1E,CAAC;oBACD,aAAa;wBACT,OAAO,CAAC,UAAU,EAAE,CAAA;oBACxB,CAAC;iBACJ,CAAA;YACL,CAAC,CAAC,CACL,CAAA;QACL,CAAC;QAED,OAAO,YAAY,CAAC,cAA+B,CAAC,CAAA;IACxD,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA;AACnD,CAAC"}
@@ -15,7 +15,7 @@ type IEnvironmentUrls = ReturnType<typeof EnvironmentsUrls1>;
15
15
  export type IKeyEnvironmentUrls = keyof IEnvironmentUrls;
16
16
  type StartsWith<T, U extends string> = T extends `${U}${infer _}` ? T : never;
17
17
  type SRVKeys<T> = {
18
- [K in keyof T as StartsWith<K & string, 'SRV_'>]: T[K];
18
+ [K in keyof T as StartsWith<K & string, 'SRV_'> | StartsWith<K & string, 'HSR_'>]: T[K];
19
19
  };
20
20
  export type IEnvironmentUrlsGenQLOnly = SRVKeys<IEnvironmentUrls>;
21
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"generateEnvConfigsBindings.d.ts","sourceRoot":"","sources":["../../src/helpers/generateEnvConfigsBindings.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAGzD,UAAU,SAAS;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAE/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1C;AAED,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE5D,MAAM,MAAM,mBAAmB,GAAG,MAAM,gBAAgB,CAAA;AAExD,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAA;AAE7E,KAAK,OAAO,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACzD,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;AAWjE;;;GAGG;AAEH,wBAAgB,oBAAoB,IAQP;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC7B,GAAG,gBAAgB,GAChB,SAAS,CAChB;AAED,wBAAgB,0BAA0B,CACtC,CAAC,SAAS,SAAS,EACnB,CAAC,SAAS,CACJ,MAAM,CAAC,GACP,OAAO,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CACnD,GACG,MAAM,EACV,CAAC,EACH,WAAW,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgE3F"}
1
+ {"version":3,"file":"generateEnvConfigsBindings.d.ts","sourceRoot":"","sources":["../../src/helpers/generateEnvConfigsBindings.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAGzD,UAAU,SAAS;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAE/B,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1C;AAED,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE5D,MAAM,MAAM,mBAAmB,GAAG,MAAM,gBAAgB,CAAA;AAExD,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAA;AAE7E,KAAK,OAAO,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC1F,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;AAWjE;;;GAGG;AAEH,wBAAgB,oBAAoB,IAQP;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC7B,GAAG,gBAAgB,GAChB,SAAS,CAChB;AAED,wBAAgB,0BAA0B,CACtC,CAAC,SAAS,SAAS,EACnB,CAAC,SAAS,CACJ,MAAM,CAAC,GACP,OAAO,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CACnD,GACG,MAAM,EACV,CAAC,EACH,WAAW,EAAE;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgE3F"}
@@ -0,0 +1,4 @@
1
+ export { adopusNamespaceExchange, adopusSlugFromJwt, denamespaceData, namespaceDocument } from './adopusNamespaceExchange.js';
2
+ export { createTadaBrowserClient } from './createTadaBrowserClient.js';
3
+ export type { CreateTadaBrowserClientOptions, ResolveExchanges } from './createTadaBrowserClient.js';
4
+ //# sourceMappingURL=urql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urql.d.ts","sourceRoot":"","sources":["../../src/helpers/urql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAC7H,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AACtE,YAAY,EAAE,8BAA8B,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { adopusNamespaceExchange, adopusSlugFromJwt, denamespaceData, namespaceDocument } from './adopusNamespaceExchange.js';
2
+ export { createTadaBrowserClient } from './createTadaBrowserClient.js';
3
+ //# sourceMappingURL=urql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urql.js","sourceRoot":"","sources":["../../src/helpers/urql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAC7H,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA"}
package/lib/index.d.ts CHANGED
@@ -39,4 +39,6 @@ export * from './helpers/isUUID.js';
39
39
  export * from './helpers/JSONToBase64EncodeDecode.js';
40
40
  export * from './helpers/getActivityStatus.js';
41
41
  export * from './helpers/stringToKeyValueMap.js';
42
+ export { createTadaBrowserClient } from './helpers/createTadaBrowserClient.js';
43
+ export type { CreateTadaBrowserClientOptions, ResolveExchanges } from './helpers/createTadaBrowserClient.js';
42
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mDAAmD,CAAA;AACjE,cAAc,iCAAiC,CAAA;AAE/C,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,2BAA2B,CAAA;AACzC,cAAc,2CAA2C,CAAA;AACzD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2CAA2C,CAAA;AACzD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,+BAA+B,CAAA;AAE7C,cAAc,qBAAqB,CAAA;AACnC,cAAc,kCAAkC,CAAA;AAEhD,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA;AAEpC,cAAc,uBAAuB,CAAA;AAErC,cAAc,oBAAoB,CAAA;AAElC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,mCAAmC,CAAA;AACjD,cAAc,qBAAqB,CAAA;AACnC,cAAc,uCAAuC,CAAA;AACrD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mDAAmD,CAAA;AACjE,cAAc,iCAAiC,CAAA;AAE/C,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,2BAA2B,CAAA;AACzC,cAAc,2CAA2C,CAAA;AACzD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2CAA2C,CAAA;AACzD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,+BAA+B,CAAA;AAE7C,cAAc,qBAAqB,CAAA;AACnC,cAAc,kCAAkC,CAAA;AAEhD,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA;AAEpC,cAAc,uBAAuB,CAAA;AAErC,cAAc,oBAAoB,CAAA;AAElC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,mCAAmC,CAAA;AACjD,cAAc,qBAAqB,CAAA;AACnC,cAAc,uCAAuC,CAAA;AACrD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAEhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,YAAY,EAAE,8BAA8B,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAA"}
package/lib/index.js CHANGED
@@ -40,4 +40,5 @@ export * from './helpers/isUUID.js';
40
40
  export * from './helpers/JSONToBase64EncodeDecode.js';
41
41
  export * from './helpers/getActivityStatus.js';
42
42
  export * from './helpers/stringToKeyValueMap.js';
43
+ export { createTadaBrowserClient } from './helpers/createTadaBrowserClient.js';
43
44
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mDAAmD,CAAA;AACjE,cAAc,iCAAiC,CAAA;AAE/C,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,2BAA2B,CAAA;AACzC,cAAc,2CAA2C,CAAA;AACzD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2CAA2C,CAAA;AACzD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,+BAA+B,CAAA;AAC7C,gDAAgD;AAChD,cAAc,qBAAqB,CAAA;AACnC,cAAc,kCAAkC,CAAA;AAEhD,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA;AAEpC,cAAc,uBAAuB,CAAA;AAErC,cAAc,oBAAoB,CAAA;AAElC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,mCAAmC,CAAA;AACjD,cAAc,qBAAqB,CAAA;AACnC,cAAc,uCAAuC,CAAA;AACrD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAA;AAChD,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA;AACjD,cAAc,mCAAmC,CAAA;AACjD,cAAc,wBAAwB,CAAA;AACtC,cAAc,uBAAuB,CAAA;AACrC,cAAc,yBAAyB,CAAA;AACvC,cAAc,qBAAqB,CAAA;AACnC,cAAc,mDAAmD,CAAA;AACjE,cAAc,iCAAiC,CAAA;AAE/C,cAAc,kCAAkC,CAAA;AAChD,cAAc,uBAAuB,CAAA;AACrC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,4CAA4C,CAAA;AAC1D,cAAc,2BAA2B,CAAA;AACzC,cAAc,2CAA2C,CAAA;AACzD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2CAA2C,CAAA;AACzD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,+BAA+B,CAAA;AAC7C,gDAAgD;AAChD,cAAc,qBAAqB,CAAA;AACnC,cAAc,kCAAkC,CAAA;AAEhD,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA;AAEpC,cAAc,uBAAuB,CAAA;AAErC,cAAc,oBAAoB,CAAA;AAElC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,mCAAmC,CAAA;AACjD,cAAc,qBAAqB,CAAA;AACnC,cAAc,uCAAuC,CAAA;AACrD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAEhD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asma-core-helpers",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Core helper utilities for ASMA applications",
5
5
  "files": [
6
6
  "lib/**/*",
@@ -12,8 +12,8 @@
12
12
  ".": "./lib/index.js",
13
13
  "./lib": "./lib/index.js",
14
14
  "./urql": {
15
- "types": "./lib/helpers/adopusNamespaceExchange.d.ts",
16
- "default": "./lib/helpers/adopusNamespaceExchange.js"
15
+ "types": "./lib/helpers/urql.d.ts",
16
+ "default": "./lib/helpers/urql.js"
17
17
  }
18
18
  },
19
19
  "scripts": {
@@ -29,12 +29,16 @@
29
29
  "license": "MIT",
30
30
  "peerDependencies": {
31
31
  "@urql/core": ">=4",
32
+ "@urql/exchange-auth": ">=3",
32
33
  "wonka": ">=6"
33
34
  },
34
35
  "peerDependenciesMeta": {
35
36
  "@urql/core": {
36
37
  "optional": true
37
38
  },
39
+ "@urql/exchange-auth": {
40
+ "optional": true
41
+ },
38
42
  "wonka": {
39
43
  "optional": true
40
44
  }
@@ -42,6 +46,7 @@
42
46
  "devDependencies": {
43
47
  "@openreplay/tracker": "^16.4.10",
44
48
  "@urql/core": "^6.0.3",
49
+ "@urql/exchange-auth": "^3.0.0",
45
50
  "asma-qiankun-react-loader": "^0.8.2",
46
51
  "asma-types": "^2.8.0",
47
52
  "history": "^5.3.0",
@@ -0,0 +1,127 @@
1
+ /**
2
+ * createTadaBrowserClient — shared urql client factory for ASMA frontend apps.
3
+ *
4
+ * Wraps the urql core (fetchExchange + optional service-specific exchanges) with
5
+ * an authExchange that attaches a JWT Bearer token and refreshes on 401.
6
+ *
7
+ * URL resolution stays in the app (imports EnvConfigs from asma-helpers);
8
+ * this factory accepts the resolved URL so it has zero dependency on asma-helpers.
9
+ *
10
+ * @see asma-modules/_docs/frontend/operations/2026-07-11-23-00-runbook-graphql-schema-generation-secrets.md
11
+ */
12
+ import {
13
+ type Client,
14
+ type ClientOptions,
15
+ createClient,
16
+ type Exchange,
17
+ fetchExchange,
18
+ } from '@urql/core'
19
+ import { authExchange } from '@urql/exchange-auth'
20
+
21
+ /**
22
+ * Contributes service-specific exchanges (e.g. the Adopus per-tenant namespace
23
+ * rewrite) without baking that knowledge into the generic factory. Called once
24
+ * per client build with the resolved endpoint; returned exchanges are inserted
25
+ * just before `fetchExchange` (and after `authExchange`).
26
+ */
27
+ export type ResolveExchanges = (ctx: {
28
+ /** The fully-resolved GraphQL endpoint URL. */
29
+ url: string
30
+ /** Resolves the current JWT (may be stale — the auth exchange handles refresh). */
31
+ getJwt: () => Promise<string | undefined>
32
+ }) => Exchange[] | Promise<Exchange[]>
33
+
34
+ export interface CreateTadaBrowserClientOptions {
35
+ /** Fully-resolved GraphQL endpoint URL (caller resolves via EnvConfigs / srv_urls). */
36
+ url: string
37
+ /** Resolves the current JWT. Typically `getCachedJwt` from asma-core-react. */
38
+ getJwt: () => Promise<string | undefined>
39
+ /** Returns true when the cached JWT is still valid. Typically `isJwtValid` from asma-core-react. */
40
+ isJwtValid: () => boolean
41
+ /** Optional service-specific exchanges injected before fetchExchange. */
42
+ resolveExchanges?: ResolveExchanges
43
+ /** Passthrough to urql ClientOptions (url is overridden by the `url` param above). */
44
+ clientOptions?: Partial<ClientOptions>
45
+ }
46
+
47
+ /**
48
+ * Creates a configured, authenticated urql Client for an ASMA frontend app.
49
+ *
50
+ * Exchange order (first = outermost):
51
+ * 1. authExchange — attach Bearer token, refresh on 401
52
+ * 2. resolveExchanges — optional service-specific transforms (e.g. namespace)
53
+ * 3. fetchExchange — standard HTTP fetch
54
+ * 4. caller-provided — appended via clientOptions.exchanges (end of pipeline)
55
+ */
56
+ export function createTadaBrowserClient({
57
+ url,
58
+ getJwt,
59
+ isJwtValid,
60
+ resolveExchanges,
61
+ clientOptions,
62
+ }: CreateTadaBrowserClientOptions): { getClient: () => Promise<Client>; createClient: (opts?: { clientOptions?: Partial<ClientOptions>; anonymous?: boolean }) => Promise<Client> } {
63
+ let tadaClient: Client | undefined
64
+
65
+ const getClient = async () => {
66
+ tadaClient = await buildClient({ clientOptions })
67
+ return tadaClient
68
+ }
69
+
70
+ async function buildClient(opts?: {
71
+ clientOptions?: Partial<ClientOptions>
72
+ anonymous?: boolean
73
+ }) {
74
+ const _clientOptions: Partial<ClientOptions> = { ...(opts?.clientOptions ?? {}) }
75
+ const anonymous = opts?.anonymous
76
+
77
+ _clientOptions.url = url
78
+ _clientOptions.preferGetMethod = false
79
+ _clientOptions.requestPolicy = 'cache-and-network'
80
+
81
+ // Start with fetchExchange + caller-provided exchanges
82
+ _clientOptions.exchanges = [
83
+ fetchExchange,
84
+ ...(_clientOptions.exchanges || []),
85
+ ]
86
+
87
+ // Inject service-specific exchanges before fetchExchange
88
+ if (resolveExchanges) {
89
+ const extra = await resolveExchanges({
90
+ getJwt,
91
+ url,
92
+ })
93
+ if (extra.length) {
94
+ _clientOptions.exchanges.unshift(...extra)
95
+ }
96
+ }
97
+
98
+ // authExchange is outermost (first to receive the operation)
99
+ if (!anonymous) {
100
+ _clientOptions.exchanges.unshift(
101
+ authExchange(async (utils) => {
102
+ const token = await getJwt()
103
+ return {
104
+ addAuthToOperation(operation) {
105
+ return utils.appendHeaders(operation, {
106
+ Authorization: `Bearer ${token}`,
107
+ })
108
+ },
109
+ didAuthError(error) {
110
+ return error.response.status === 401
111
+ },
112
+ async refreshAuth() {
113
+ tadaClient = await buildClient({ clientOptions: opts?.clientOptions })
114
+ },
115
+ willAuthError() {
116
+ return !isJwtValid()
117
+ },
118
+ }
119
+ }),
120
+ )
121
+ }
122
+
123
+ return createClient(_clientOptions as ClientOptions)
124
+ }
125
+
126
+ return { getClient, createClient: buildClient }
127
+ }
@@ -25,7 +25,7 @@ export type IKeyEnvironmentUrls = keyof IEnvironmentUrls
25
25
  type StartsWith<T, U extends string> = T extends `${U}${infer _}` ? T : never
26
26
 
27
27
  type SRVKeys<T> = {
28
- [K in keyof T as StartsWith<K & string, 'SRV_'>]: T[K]
28
+ [K in keyof T as StartsWith<K & string, 'SRV_'> | StartsWith<K & string, 'HSR_'>]: T[K]
29
29
  }
30
30
 
31
31
  export type IEnvironmentUrlsGenQLOnly = SRVKeys<IEnvironmentUrls> /* Omit<
@@ -0,0 +1,3 @@
1
+ export { adopusNamespaceExchange, adopusSlugFromJwt, denamespaceData, namespaceDocument } from './adopusNamespaceExchange.js'
2
+ export { createTadaBrowserClient } from './createTadaBrowserClient.js'
3
+ export type { CreateTadaBrowserClientOptions, ResolveExchanges } from './createTadaBrowserClient.js'
package/src/index.ts CHANGED
@@ -46,3 +46,6 @@ export * from './helpers/isUUID.js'
46
46
  export * from './helpers/JSONToBase64EncodeDecode.js'
47
47
  export * from './helpers/getActivityStatus.js'
48
48
  export * from './helpers/stringToKeyValueMap.js'
49
+
50
+ export { createTadaBrowserClient } from './helpers/createTadaBrowserClient.js'
51
+ export type { CreateTadaBrowserClientOptions, ResolveExchanges } from './helpers/createTadaBrowserClient.js'