@burdenoff/microfe-ecoimpacthub 2026.1030.4 → 2026.1031.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.
- package/dist/ecoimpacthub/pages/carbon/AiQuotaBanner.d.ts.map +1 -1
- package/dist/ecoimpacthub/pages/carbon/AiQuotaBanner.js +7 -4
- package/dist/ecoimpacthub/pages/carbon/AiQuotaBanner.js.map +1 -1
- package/dist/ecoimpacthub/utils/graphqlErrors.d.ts +16 -1
- package/dist/ecoimpacthub/utils/graphqlErrors.d.ts.map +1 -1
- package/dist/ecoimpacthub/utils/graphqlErrors.js +21 -7
- package/dist/ecoimpacthub/utils/graphqlErrors.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiQuotaBanner.d.ts","sourceRoot":"","sources":["../../../../src/ecoimpacthub/pages/carbon/AiQuotaBanner.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"AiQuotaBanner.d.ts","sourceRoot":"","sources":["../../../../src/ecoimpacthub/pages/carbon/AiQuotaBanner.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE,kBAAkB,2CA0CzD"}
|
|
@@ -5,17 +5,20 @@ import { jsx as r } from "react/jsx-runtime";
|
|
|
5
5
|
import { UpgradeInlineBanner as i, dispatchUpgradePrompt as a } from "@burdenoff/fe-libs/shared/components";
|
|
6
6
|
function o({ wall: o }) {
|
|
7
7
|
let s = e(), c = o.quotaName ?? "ecoimpacthub.ai.credits";
|
|
8
|
-
|
|
8
|
+
t(() => {
|
|
9
9
|
a({ extensions: {
|
|
10
10
|
code: "QUOTA_EXHAUSTED",
|
|
11
11
|
quotaName: c
|
|
12
12
|
} });
|
|
13
|
-
}, [c])
|
|
13
|
+
}, [c]);
|
|
14
|
+
let l = o.kind === "not-provisioned";
|
|
15
|
+
return /* @__PURE__ */ r("div", {
|
|
14
16
|
"data-testid": "eco-ai-quota-banner",
|
|
17
|
+
"data-quota-block": o.kind,
|
|
15
18
|
children: /* @__PURE__ */ r(i, {
|
|
16
19
|
severity: "critical",
|
|
17
|
-
title: s("ecoCarbon.ai.quota.title", "AI credits used up"),
|
|
18
|
-
message: s("ecoCarbon.ai.quota.message", "Your plan has no AI credits left for EcoImpactHub this period. Upgrade to keep drafting ledger entries with AI, or record entries by hand."),
|
|
20
|
+
title: l ? s("ecoCarbon.ai.quota.notProvisionedTitle", "AI credits are not in your plan") : s("ecoCarbon.ai.quota.title", "AI credits used up"),
|
|
21
|
+
message: l ? s("ecoCarbon.ai.quota.notProvisionedMessage", "Your workspace's plan does not include EcoImpactHub AI credits. Choose a plan that includes them to use AI drafting and factor suggestions, or record entries by hand.") : s("ecoCarbon.ai.quota.message", "Your plan has no AI credits left for EcoImpactHub this period. Upgrade to keep drafting ledger entries with AI, or record entries by hand."),
|
|
19
22
|
upgradeHref: "/billing/plans",
|
|
20
23
|
renderCta: ({ href: e }) => /* @__PURE__ */ r(n, {
|
|
21
24
|
to: e,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiQuotaBanner.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/carbon/AiQuotaBanner.tsx"],"sourcesContent":["/**\n * AI-credit quota wall for the carbon-ledger AI actions.\n * @module ecoimpacthub/pages/carbon/AiQuotaBanner\n *\n * Shown when `ecoAiDraftCarbonEntries` / `ecoAiSuggestEmissionFactor`
|
|
1
|
+
{"version":3,"file":"AiQuotaBanner.js","names":[],"sources":["../../../../src/ecoimpacthub/pages/carbon/AiQuotaBanner.tsx"],"sourcesContent":["/**\n * AI-credit quota wall for the carbon-ledger AI actions.\n * @module ecoimpacthub/pages/carbon/AiQuotaBanner\n *\n * Shown when `ecoAiDraftCarbonEntries` / `ecoAiSuggestEmissionFactor` are\n * refused by the gateway `@usage` gate on `ecoimpacthub.ai.credits`, either\n * because the credits are used up (`QUOTA_EXHAUSTED`) or because the\n * workspace's plan does not include them at all (`QUOTA_NOT_PROVISIONED`).\n * The copy differs between the two: telling someone with no plan that their\n * credits are \"used up\" is wrong. It renders the fe-libs\n * `UpgradeInlineBanner` (semantic tokens, upgrade CTA to `/billing/plans`) and\n * also dispatches the fe-libs global upgrade prompt once per wall, so a host\n * shell that mounts `UpgradePromptModal` opens its dialog as well. The global\n * backend-error toast deliberately skips QUOTA_EXHAUSTED, so without this the\n * refusal would be silent. The global prompt is dispatched as QUOTA_EXHAUSTED\n * for both kinds because that is the upgrade code the fe-libs modal accepts;\n * the inline banner carries the kind-specific wording.\n */\n\nimport { useEffect } from 'react';\nimport { Link } from 'react-router';\nimport { UpgradeInlineBanner, dispatchUpgradePrompt } from '@burdenoff/fe-libs/shared/components';\nimport { useTr } from '../../hooks/useTr';\nimport type { EcoQuotaWall } from '../../utils/graphqlErrors';\n\nexport const AI_CREDITS_QUOTA = 'ecoimpacthub.ai.credits';\n\ninterface AiQuotaBannerProps {\n wall: EcoQuotaWall;\n}\n\nexport function AiQuotaBanner({ wall }: AiQuotaBannerProps) {\n const tr = useTr();\n const quotaName = wall.quotaName ?? AI_CREDITS_QUOTA;\n\n useEffect(() => {\n dispatchUpgradePrompt({ extensions: { code: 'QUOTA_EXHAUSTED', quotaName } });\n }, [quotaName]);\n\n const notProvisioned = wall.kind === 'not-provisioned';\n\n return (\n <div data-testid=\"eco-ai-quota-banner\" data-quota-block={wall.kind}>\n <UpgradeInlineBanner\n severity=\"critical\"\n title={\n notProvisioned\n ? tr('ecoCarbon.ai.quota.notProvisionedTitle', 'AI credits are not in your plan')\n : tr('ecoCarbon.ai.quota.title', 'AI credits used up')\n }\n message={\n notProvisioned\n ? tr(\n 'ecoCarbon.ai.quota.notProvisionedMessage',\n \"Your workspace's plan does not include EcoImpactHub AI credits. Choose a plan that includes them to use AI drafting and factor suggestions, or record entries by hand.\"\n )\n : tr(\n 'ecoCarbon.ai.quota.message',\n 'Your plan has no AI credits left for EcoImpactHub this period. Upgrade to keep drafting ledger entries with AI, or record entries by hand.'\n )\n }\n upgradeHref=\"/billing/plans\"\n renderCta={({ href }) => (\n <Link\n to={href}\n className=\"rounded-md bg-action-primary-bg px-2.5 py-1 text-xs font-medium text-action-primary-text hover:bg-action-primary-bg-hover\"\n >\n {tr('ecoCarbon.ai.quota.upgrade', 'View plans')}\n </Link>\n )}\n />\n </div>\n );\n}\n"],"mappings":";;;;;AA+BA,SAAgB,EAAc,EAAE,WAA4B;CAC1D,IAAM,IAAK,EAAM,GACX,IAAY,EAAK,aAAA;CAEvB,QAAgB;EACd,EAAsB,EAAE,YAAY;GAAE,MAAM;GAAmB;EAAU,EAAE,CAAC;CAC9E,GAAG,CAAC,CAAS,CAAC;CAEd,IAAM,IAAiB,EAAK,SAAS;CAErC,OACE,kBAAC,OAAD;EAAK,eAAY;EAAsB,oBAAkB,EAAK;YAC5D,kBAAC,GAAD;GACE,UAAS;GACT,OACE,IACI,EAAG,0CAA0C,iCAAiC,IAC9E,EAAG,4BAA4B,oBAAoB;GAEzD,SACE,IACI,EACE,4CACA,wKACF,IACA,EACE,8BACA,4IACF;GAEN,aAAY;GACZ,YAAY,EAAE,cACZ,kBAAC,GAAD;IACE,IAAI;IACJ,WAAU;cAET,EAAG,8BAA8B,YAAY;GAC1C,CAAA;EAET,CAAA;CACE,CAAA;AAET"}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* `graphqlFetch` hands back the raw GraphQL `errors` array (or rejects with an
|
|
6
6
|
* Error that carries it on `.errors` when the request was batched). Throwing a
|
|
7
7
|
* plain `Error(message)` from there loses `extensions.code`, which is the only
|
|
8
|
-
* reliable way to tell a quota wall (`QUOTA_EXHAUSTED`
|
|
8
|
+
* reliable way to tell a quota wall (`QUOTA_EXHAUSTED` /
|
|
9
|
+
* `QUOTA_NOT_PROVISIONED`) or a lifecycle conflict
|
|
9
10
|
* (`CONFLICT`) apart from any other failure. `EcoGraphQLError` keeps the
|
|
10
11
|
* original errors on `graphQLErrors` — the same property name Apollo uses — so
|
|
11
12
|
* the fe-libs quota helpers (`extractQuotaExhaustedExtensions`,
|
|
@@ -34,7 +35,21 @@ export declare class EcoGraphQLError extends Error {
|
|
|
34
35
|
export declare function graphQLErrorsOf(err: unknown): EcoGraphQLErrorEntry[];
|
|
35
36
|
/** `extensions.code` of the first coded error, or undefined. */
|
|
36
37
|
export declare function graphQLErrorCode(err: unknown): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Why the gateway's `@usage` gate refused the call.
|
|
40
|
+
*
|
|
41
|
+
* - `exhausted` (`QUOTA_EXHAUSTED`): the plan covers the quota and it is used
|
|
42
|
+
* up for this period.
|
|
43
|
+
* - `not-provisioned` (`QUOTA_NOT_PROVISIONED`): the workspace has no plan
|
|
44
|
+
* that covers the quota at all. Nothing was used up; the user has to pick a
|
|
45
|
+
* plan that includes it.
|
|
46
|
+
*
|
|
47
|
+
* Both are upgrade walls, so both render the upgrade banner rather than a
|
|
48
|
+
* raw error line.
|
|
49
|
+
*/
|
|
50
|
+
export type EcoQuotaWallKind = 'exhausted' | 'not-provisioned';
|
|
37
51
|
export interface EcoQuotaWall {
|
|
52
|
+
kind: EcoQuotaWallKind;
|
|
38
53
|
quotaName?: string;
|
|
39
54
|
}
|
|
40
55
|
/** The quota wall an error describes, or null when it is not a quota error. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphqlErrors.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/utils/graphqlErrors.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graphqlErrors.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/utils/graphqlErrors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC;gBAEnC,MAAM,EAAE,oBAAoB,EAAE;CAY3C;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,EAAE,CASpE;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAMjE;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,iBAAiB,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAgB7D;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIrE"}
|
|
@@ -18,19 +18,33 @@ function r(e) {
|
|
|
18
18
|
if (typeof e == "string" && e) return e;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
var i = {
|
|
22
|
+
QUOTA_EXHAUSTED: "exhausted",
|
|
23
|
+
QUOTA_NOT_PROVISIONED: "not-provisioned"
|
|
24
|
+
};
|
|
25
|
+
function a(e) {
|
|
26
|
+
for (let t of n(e)) {
|
|
27
|
+
let e = t.extensions?.code, n = typeof e == "string" ? i[e] : void 0;
|
|
28
|
+
if (n) {
|
|
29
|
+
let e = t.extensions?.quotaName;
|
|
30
|
+
return typeof e == "string" && e ? {
|
|
31
|
+
kind: n,
|
|
32
|
+
quotaName: e
|
|
33
|
+
} : { kind: n };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (e instanceof Error) {
|
|
37
|
+
if (e.message.includes("QUOTA_NOT_PROVISIONED")) return { kind: "not-provisioned" };
|
|
38
|
+
if (e.message.includes("QUOTA_EXHAUSTED")) return { kind: "exhausted" };
|
|
25
39
|
}
|
|
26
|
-
return
|
|
40
|
+
return null;
|
|
27
41
|
}
|
|
28
|
-
function
|
|
42
|
+
function o(e, t) {
|
|
29
43
|
if (e instanceof Error && e.message.trim()) return e.message;
|
|
30
44
|
let r = n(e)[0];
|
|
31
45
|
return r?.message?.trim() ? r.message : t;
|
|
32
46
|
}
|
|
33
47
|
//#endregion
|
|
34
|
-
export { e as EcoGraphQLError,
|
|
48
|
+
export { e as EcoGraphQLError, o as errorMessageOf, r as graphQLErrorCode, n as graphQLErrorsOf, a as quotaWallOf };
|
|
35
49
|
|
|
36
50
|
//# sourceMappingURL=graphqlErrors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphqlErrors.js","names":[],"sources":["../../../src/ecoimpacthub/utils/graphqlErrors.ts"],"sourcesContent":["/**\n * Structured GraphQL errors for the EcoImpactHub transport.\n * @module ecoimpacthub/utils/graphqlErrors\n *\n * `graphqlFetch` hands back the raw GraphQL `errors` array (or rejects with an\n * Error that carries it on `.errors` when the request was batched). Throwing a\n * plain `Error(message)` from there loses `extensions.code`, which is the only\n * reliable way to tell a quota wall (`QUOTA_EXHAUSTED`) or a lifecycle conflict\n * (`CONFLICT`) apart from any other failure. `EcoGraphQLError` keeps the\n * original errors on `graphQLErrors` — the same property name Apollo uses — so\n * the fe-libs quota helpers (`extractQuotaExhaustedExtensions`,\n * `isUpgradeError`) recognise it without any adapter.\n */\n\n/** The subset of a GraphQL error the MFE reads. */\nexport interface EcoGraphQLErrorEntry {\n message: string;\n path?: ReadonlyArray<string | number>;\n extensions?: Record<string, unknown> & { code?: string };\n}\n\nexport class EcoGraphQLError extends Error {\n /** `extensions.code` of the first error, when the server set one. */\n readonly code: string | undefined;\n /** Every error the server returned, unmodified. */\n readonly graphQLErrors: EcoGraphQLErrorEntry[];\n\n constructor(errors: EcoGraphQLErrorEntry[]) {\n const first = errors[0];\n const userMessage = first?.extensions?.userMessage;\n super(\n typeof userMessage === 'string' && userMessage.trim()\n ? userMessage\n : (first?.message ?? 'GraphQL request failed')\n );\n this.name = 'EcoGraphQLError';\n this.code = typeof first?.extensions?.code === 'string' ? first.extensions.code : undefined;\n this.graphQLErrors = errors;\n }\n}\n\nconst isErrorEntry = (value: unknown): value is EcoGraphQLErrorEntry =>\n typeof value === 'object' &&\n value !== null &&\n 'message' in value &&\n typeof (value as { message: unknown }).message === 'string';\n\n/**\n * Read GraphQL errors off anything a transport may reject with: an\n * `EcoGraphQLError`, a batched-fetch Error carrying `.errors`, or an\n * Apollo-shaped error carrying `.graphQLErrors`. Returns [] for anything else.\n */\nexport function graphQLErrorsOf(err: unknown): EcoGraphQLErrorEntry[] {\n if (typeof err !== 'object' || err === null) return [];\n const candidate = err as { graphQLErrors?: unknown; errors?: unknown };\n const list = Array.isArray(candidate.graphQLErrors)\n ? candidate.graphQLErrors\n : Array.isArray(candidate.errors)\n ? candidate.errors\n : [];\n return list.filter(isErrorEntry);\n}\n\n/** `extensions.code` of the first coded error, or undefined. */\nexport function graphQLErrorCode(err: unknown): string | undefined {\n for (const entry of graphQLErrorsOf(err)) {\n const code = entry.extensions?.code;\n if (typeof code === 'string' && code) return code;\n }\n return undefined;\n}\n\nexport interface EcoQuotaWall {\n quotaName?: string;\n}\n\n/** The quota wall an error describes, or null when it is not a quota error. */\nexport function quotaWallOf(err: unknown): EcoQuotaWall | null {\n for (const entry of graphQLErrorsOf(err)) {\n
|
|
1
|
+
{"version":3,"file":"graphqlErrors.js","names":[],"sources":["../../../src/ecoimpacthub/utils/graphqlErrors.ts"],"sourcesContent":["/**\n * Structured GraphQL errors for the EcoImpactHub transport.\n * @module ecoimpacthub/utils/graphqlErrors\n *\n * `graphqlFetch` hands back the raw GraphQL `errors` array (or rejects with an\n * Error that carries it on `.errors` when the request was batched). Throwing a\n * plain `Error(message)` from there loses `extensions.code`, which is the only\n * reliable way to tell a quota wall (`QUOTA_EXHAUSTED` /\n * `QUOTA_NOT_PROVISIONED`) or a lifecycle conflict\n * (`CONFLICT`) apart from any other failure. `EcoGraphQLError` keeps the\n * original errors on `graphQLErrors` — the same property name Apollo uses — so\n * the fe-libs quota helpers (`extractQuotaExhaustedExtensions`,\n * `isUpgradeError`) recognise it without any adapter.\n */\n\n/** The subset of a GraphQL error the MFE reads. */\nexport interface EcoGraphQLErrorEntry {\n message: string;\n path?: ReadonlyArray<string | number>;\n extensions?: Record<string, unknown> & { code?: string };\n}\n\nexport class EcoGraphQLError extends Error {\n /** `extensions.code` of the first error, when the server set one. */\n readonly code: string | undefined;\n /** Every error the server returned, unmodified. */\n readonly graphQLErrors: EcoGraphQLErrorEntry[];\n\n constructor(errors: EcoGraphQLErrorEntry[]) {\n const first = errors[0];\n const userMessage = first?.extensions?.userMessage;\n super(\n typeof userMessage === 'string' && userMessage.trim()\n ? userMessage\n : (first?.message ?? 'GraphQL request failed')\n );\n this.name = 'EcoGraphQLError';\n this.code = typeof first?.extensions?.code === 'string' ? first.extensions.code : undefined;\n this.graphQLErrors = errors;\n }\n}\n\nconst isErrorEntry = (value: unknown): value is EcoGraphQLErrorEntry =>\n typeof value === 'object' &&\n value !== null &&\n 'message' in value &&\n typeof (value as { message: unknown }).message === 'string';\n\n/**\n * Read GraphQL errors off anything a transport may reject with: an\n * `EcoGraphQLError`, a batched-fetch Error carrying `.errors`, or an\n * Apollo-shaped error carrying `.graphQLErrors`. Returns [] for anything else.\n */\nexport function graphQLErrorsOf(err: unknown): EcoGraphQLErrorEntry[] {\n if (typeof err !== 'object' || err === null) return [];\n const candidate = err as { graphQLErrors?: unknown; errors?: unknown };\n const list = Array.isArray(candidate.graphQLErrors)\n ? candidate.graphQLErrors\n : Array.isArray(candidate.errors)\n ? candidate.errors\n : [];\n return list.filter(isErrorEntry);\n}\n\n/** `extensions.code` of the first coded error, or undefined. */\nexport function graphQLErrorCode(err: unknown): string | undefined {\n for (const entry of graphQLErrorsOf(err)) {\n const code = entry.extensions?.code;\n if (typeof code === 'string' && code) return code;\n }\n return undefined;\n}\n\n/**\n * Why the gateway's `@usage` gate refused the call.\n *\n * - `exhausted` (`QUOTA_EXHAUSTED`): the plan covers the quota and it is used\n * up for this period.\n * - `not-provisioned` (`QUOTA_NOT_PROVISIONED`): the workspace has no plan\n * that covers the quota at all. Nothing was used up; the user has to pick a\n * plan that includes it.\n *\n * Both are upgrade walls, so both render the upgrade banner rather than a\n * raw error line.\n */\nexport type EcoQuotaWallKind = 'exhausted' | 'not-provisioned';\n\nexport interface EcoQuotaWall {\n kind: EcoQuotaWallKind;\n quotaName?: string;\n}\n\nconst QUOTA_WALL_CODES: Readonly<Record<string, EcoQuotaWallKind>> = {\n QUOTA_EXHAUSTED: 'exhausted',\n QUOTA_NOT_PROVISIONED: 'not-provisioned',\n};\n\n/** The quota wall an error describes, or null when it is not a quota error. */\nexport function quotaWallOf(err: unknown): EcoQuotaWall | null {\n for (const entry of graphQLErrorsOf(err)) {\n const code = entry.extensions?.code;\n const kind = typeof code === 'string' ? QUOTA_WALL_CODES[code] : undefined;\n if (kind) {\n const quotaName = entry.extensions?.quotaName;\n return typeof quotaName === 'string' && quotaName ? { kind, quotaName } : { kind };\n }\n }\n if (err instanceof Error) {\n // Check the more specific code first: the not-provisioned message never\n // contains QUOTA_EXHAUSTED, but keep the order explicit anyway.\n if (err.message.includes('QUOTA_NOT_PROVISIONED')) return { kind: 'not-provisioned' };\n if (err.message.includes('QUOTA_EXHAUSTED')) return { kind: 'exhausted' };\n }\n return null;\n}\n\n/** Human-readable message for any thrown value, with a caller fallback. */\nexport function errorMessageOf(err: unknown, fallback: string): string {\n if (err instanceof Error && err.message.trim()) return err.message;\n const first = graphQLErrorsOf(err)[0];\n return first?.message?.trim() ? first.message : fallback;\n}\n"],"mappings":";AAsBA,IAAa,IAAb,cAAqC,MAAM;CAEzC;CAEA;CAEA,YAAY,GAAgC;EAC1C,IAAM,IAAQ,EAAO,IACf,IAAc,GAAO,YAAY;EAQvC,AAPA,MACE,OAAO,KAAgB,YAAY,EAAY,KAAK,IAChD,IACC,GAAO,WAAW,wBACzB,GACA,KAAK,OAAO,mBACZ,KAAK,OAAO,OAAO,GAAO,YAAY,QAAS,WAAW,EAAM,WAAW,OAAO,KAAA,GAClF,KAAK,gBAAgB;CACvB;AACF,GAEM,KAAgB,MACpB,OAAO,KAAU,cACjB,KACA,aAAa,KACb,OAAQ,EAA+B,WAAY;AAOrD,SAAgB,EAAgB,GAAsC;CACpE,IAAI,OAAO,KAAQ,aAAY,GAAc,OAAO,CAAC;CACrD,IAAM,IAAY;CAMlB,QALa,MAAM,QAAQ,EAAU,aAAa,IAC9C,EAAU,gBACV,MAAM,QAAQ,EAAU,MAAM,IAC5B,EAAU,SACV,CAAC,GACK,OAAO,CAAY;AACjC;AAGA,SAAgB,EAAiB,GAAkC;CACjE,KAAK,IAAM,KAAS,EAAgB,CAAG,GAAG;EACxC,IAAM,IAAO,EAAM,YAAY;EAC/B,IAAI,OAAO,KAAS,YAAY,GAAM,OAAO;CAC/C;AAEF;AAqBA,IAAM,IAA+D;CACnE,iBAAiB;CACjB,uBAAuB;AACzB;AAGA,SAAgB,EAAY,GAAmC;CAC7D,KAAK,IAAM,KAAS,EAAgB,CAAG,GAAG;EACxC,IAAM,IAAO,EAAM,YAAY,MACzB,IAAO,OAAO,KAAS,WAAW,EAAiB,KAAQ,KAAA;EACjE,IAAI,GAAM;GACR,IAAM,IAAY,EAAM,YAAY;GACpC,OAAO,OAAO,KAAc,YAAY,IAAY;IAAE;IAAM;GAAU,IAAI,EAAE,QAAK;EACnF;CACF;CACA,IAAI,aAAe,OAAO;EAGxB,IAAI,EAAI,QAAQ,SAAS,uBAAuB,GAAG,OAAO,EAAE,MAAM,kBAAkB;EACpF,IAAI,EAAI,QAAQ,SAAS,iBAAiB,GAAG,OAAO,EAAE,MAAM,YAAY;CAC1E;CACA,OAAO;AACT;AAGA,SAAgB,EAAe,GAAc,GAA0B;CACrE,IAAI,aAAe,SAAS,EAAI,QAAQ,KAAK,GAAG,OAAO,EAAI;CAC3D,IAAM,IAAQ,EAAgB,CAAG,EAAE;CACnC,OAAO,GAAO,SAAS,KAAK,IAAI,EAAM,UAAU;AAClD"}
|