@burdenoff/fluidgrids-fe-sdk 2026.1113.1 → 2026.1113.2
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/{AiStudioPage-D3MAk-bs.js → AiStudioPage-5KYZ8r8-.js} +464 -7
- package/dist/{ApprovalInboxPage-Bb8H9ruw.js → ApprovalInboxPage-BsJX4osU.js} +4 -3
- package/dist/{ConnectionFormDialog-Bg9_OdHX.js → ConnectionFormDialog-Dr1-CTan.js} +2 -1
- package/dist/CreateFluidgridsTagDocument-Dtp9KPLJ.js +1055 -0
- package/dist/{DataSinkDashboardPage-Dc2QuJbL.js → DataSinkDashboardPage-8ZDn85e2.js} +1 -1
- package/dist/{DataTablesPage-Cv4veaKK.js → DataTablesPage-BBvABuxE.js} +5 -4
- package/dist/{EntityTagPicker-D8ws706D.js → EntityTagPicker-BppBSEJk.js} +2 -2
- package/dist/{ExecutionDetailPage-CTVGE-d-.js → ExecutionDetailPage-BXDF2eoT.js} +1444 -18
- package/dist/ExecutionsListDocument-CzdLPpj5.js +1259 -0
- package/dist/{ExecutionsListPage-J0sJPuoM.js → ExecutionsListPage--4BthM8L.js} +285 -11
- package/dist/FailureTriagePanel-B5WCSRFo.js +1252 -0
- package/dist/{FluidGridsProvider-C4FVNz0n.js → FluidGridsProvider-Dc_Jhtch.js} +8666 -8734
- package/dist/{HistoryPage-B9XcTPrO.js → HistoryPage-BvFk2m1m.js} +4 -3
- package/dist/{InsightsPage-DFOltjyj.js → InsightsPage-Dwmb02F6.js} +2682 -5
- package/dist/{MissingNodesInstallModal-D8H-YNCJ.js → MissingNodesInstallModal-Cze674hp.js} +2 -2
- package/dist/{NodesPage-YQ-hP60x.js → NodesPage-C5Dq-ru-.js} +3 -2
- package/dist/{OpenTemplateAsCodeButton-hH26HQCk.js → OpenTemplateAsCodeButton-8MZHih6I.js} +2 -2
- package/dist/{PaidTemplateConfirm-DoKWMBtR.js → PaidTemplateConfirm-0G-gv29n.js} +1 -1
- package/dist/{PublishCustomNodeAction-5XXnSA3H.js → PublishCustomNodeAction-OOY35dUv.js} +1 -1
- package/dist/QuotaExhaustedDialog-wvu_-WJ-.js +55 -0
- package/dist/{RunnerStatusPill-Ctg4TJcP.js → RunnerStatusPill-Bh7mEsPh.js} +2 -1
- package/dist/{RunnersPage-CAt4YDhB.js → RunnersPage-DHeuUDil.js} +2 -2
- package/dist/{SettingsPage-DEKPCVVP.js → SettingsPage-CfjXiGpb.js} +694 -14
- package/dist/{TagFilterSelect-CwM2-DU6.js → TagFilterSelect-CAShgvbS.js} +1 -1
- package/dist/{TaskQueuesPage-Dhi6SIT4.js → TaskQueuesPage--Mmn36b-.js} +3 -3
- package/dist/{TemplateCard-DVSd_4zJ.js → TemplateCard-BA_9em22.js} +644 -352
- package/dist/{TemplateConfigurationModal-BKi1z7z7.js → TemplateConfigurationModal-BT3PaR0O.js} +4 -3
- package/dist/{TemplateDetailPanel-DK1gF7P5.js → TemplateDetailPanel-BxFNnlXm.js} +2 -1
- package/dist/{TemplatePreview-DuSX2Q7H.js → TemplatePreview-Bagja6WN.js} +7 -7
- package/dist/{TemplatesPage-CAWHh61l.js → TemplatesPage-CAajpJ5w.js} +711 -6
- package/dist/{VariablesPage-D7CoatWf.js → VariablesPage-CgUBKhAe.js} +3 -3
- package/dist/{VersionDiffDialog-DGwysiyE.js → VersionDiffDialog-D9W5Fm56.js} +233 -129
- package/dist/VersionLifecycleBar-DuphLOT0.js +131 -0
- package/dist/{WorkflowBuilder-DAeoQi5E.js → WorkflowBuilder-DMpSPElu.js} +16 -13
- package/dist/{WorkflowBuilder-BJgqDboZ.js → WorkflowBuilder-v8h8skwG.js} +5 -5
- package/dist/WorkflowDefinitionDocument-DZLbTPUZ.js +321 -0
- package/dist/WorkflowEditLeaseStatusDocument-Dp62med3.js +627 -0
- package/dist/WorkflowProposalCard-zCdUpCk8.js +249 -0
- package/dist/WorkflowProposalDocument-BdUbsrd0.js +620 -0
- package/dist/{WorkflowSearchRedirect-CMEvd_AR.js → WorkflowSearchRedirect-G78lINAE.js} +1 -1
- package/dist/{WorkflowShareDialog-BgHRsDP0.js → WorkflowShareDialog-B7VOgr4-.js} +304 -3
- package/dist/WorkflowVersionsDocument-CfPMloRW.js +3195 -0
- package/dist/{WorkflowsList-CcQPxWKL.js → WorkflowsList-CPYzfE4K.js} +11 -9
- package/dist/agent-form-D0uLvzx4.js +718 -0
- package/dist/{agentTools-DKpNKztf.js → agentTools-DTXUqtfu.js} +4 -4
- package/dist/api-BZVyX5d2.js +2286 -0
- package/dist/api-BqA-f-AD.js +8064 -0
- package/dist/app-BJUvugPM.js +3813 -0
- package/dist/assert-rules-CPNrO44K.js +318 -0
- package/dist/attach-node-helpers-CNsYtLOR.js +32 -0
- package/dist/badge-CXfPhoMH.js +26 -0
- package/dist/{canvasNoteTools-C_AN79m0.js → canvasNoteTools-DmfZwtnL.js} +3 -3
- package/dist/{channel-CZ70oI81.js → channel-DtF1n_ab.js} +1 -1
- package/dist/client-Ctl4jmY3.js +127 -0
- package/dist/code-editor-diagnostics-Zr0cIcx1.js +46 -0
- package/dist/{code-editor-field-Dt6KNWwN.js → code-editor-field-Cv907s3W.js} +2 -2
- package/dist/{codec-client-CJ95Rmqo.js → codec-client-CAYl6j46.js} +2 -1
- package/dist/conditionBuilder-D8aLGL1w.js +1134 -0
- package/dist/config-X97zrIvn.js +600 -0
- package/dist/{definition-canvas-Bshn_dSP.js → definition-canvas-DL25_6NH.js} +1 -1
- package/dist/{dialog-Cjb4lB4D.js → dialog-BVd152GS.js} +3 -14
- package/dist/durable-nodes-DXCCQYWD.js +81 -0
- package/dist/errors-xPZ-IbQd.js +142 -0
- package/dist/executions.js +2 -2
- package/dist/{flow-builder-D3Hl2AFk.js → flow-builder-Dv5fWJ6F.js} +9301 -8189
- package/dist/{node-registry-refresh-Dy0uRg9f.js → global-client-DP_Wxe5t.js} +2 -27
- package/dist/global-operations-7pvXw_j9.js +145 -0
- package/dist/history.js +1 -1
- package/dist/{index-CWcP-tG1.d.ts → index-DtMUtXNq.d.ts} +247 -247
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4403 -46
- package/dist/input-ChT6Q-Pr.js +17 -0
- package/dist/logs-panel-DtG93ocy.js +342 -0
- package/dist/mapping-colors-BIX_YeCQ.js +48 -0
- package/dist/{node-detail-view-bVLeYarT.js → node-detail-view-BKI_2kM6.js} +12 -11
- package/dist/{node-editor-tab-body-JHHVtQgR.js → node-editor-tab-body-Cc1MWEFR.js} +3 -3
- package/dist/{node-operation-selection-DAbS6jSY.js → node-operation-selection-Czeeb2D4.js} +2 -139
- package/dist/node-registry-refresh-s3okf83X.js +27 -0
- package/dist/nodes.js +1 -1
- package/dist/notesKey-5EaREBGA.js +12 -0
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +2 -2
- package/dist/{popover-Xx3gN7vg.js → popover-DDv7J1Kl.js} +717 -6
- package/dist/{quick-config-panel-BvVQXuIL.js → quick-config-panel-BPCRfqWI.js} +4 -4
- package/dist/read-only-context-Dt9N9SIG.js +18 -0
- package/dist/{schedule-panel-DCb40TPN.js → schedule-panel-C1KwfLCE.js} +14 -12
- package/dist/settings.js +1 -1
- package/dist/{shared-CMfn30xT.js → shared-Ctl9ZHo1.js} +2 -1
- package/dist/{sidebar-node-editor-DxCWFZG2.js → sidebar-node-editor-d9Rlq5pU.js} +4 -4
- package/dist/sticky-notes-23j-wL6Q.js +96 -0
- package/dist/template-code-dqRunGOv.js +184 -0
- package/dist/template-preview-C01KV277.js +29 -0
- package/dist/templates.js +2 -2
- package/dist/token-refresh-link-BjN7H4qA.js +291 -0
- package/dist/useAgentDefinitions-ZKX2N9aP.js +3101 -0
- package/dist/useConnections-BlB0gbOB.js +931 -0
- package/dist/useDurableParity-BgLH_SCF.js +2088 -0
- package/dist/{useEntityTags-Db4Pc8_M.js → useEntityTags-4iW6UTly.js} +227 -3
- package/dist/{useExecutions-DOpG1pUQ.js → useExecutions-Bm7q_UwN.js} +6 -3
- package/dist/useGlobalStoreClient-DMTrywdX.js +24 -0
- package/dist/{useHumanRequests-ZiR0sSzS.js → useHumanRequests-DwG2tQ3f.js} +2 -1
- package/dist/{useObservability-rQmwhoZZ.js → useObservability-DPATdbw7.js} +4 -2
- package/dist/{useRunHistory-COn6dl7l.js → useRunHistory-CGfjCsJ3.js} +1122 -4
- package/dist/{useVariables-2ddyJX4a.js → useVariables-DFdZofLQ.js} +2 -1
- package/dist/{useWorkflowCodeExport-ZoUJKRSK.js → useWorkflowCodeExport-D_mCuhKP.js} +289 -4
- package/dist/useWorkflowOrganization-r5FWNBs6.js +1690 -0
- package/dist/useWorkflowProposal-Bh2_qjmM.js +7478 -0
- package/dist/{useWorkflows-jOW60YmD.js → useWorkflows-aqVD7kGa.js} +694 -4
- package/dist/workflow-builder.js +5 -5
- package/dist/{workflow-code-transfer-l9wO34S0.js → workflow-code-transfer-5C0HUzae.js} +1 -53
- package/dist/workflow-host.js +4 -2
- package/dist/workflow-pages.d.ts +1 -1
- package/dist/workflow-pages.js +19 -19
- package/dist/workflow-preview.js +3 -2
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
- package/dist/FailureTriagePanel-BbYFYeV_.js +0 -311
- package/dist/WorkflowProposalCard-DGMdZC4R.js +0 -1432
- package/dist/agent-form-Bfvm32j1.js +0 -83
- package/dist/api-DQtHXbIg.js +0 -224
- package/dist/api-MeAm6g7E.js +0 -55
- package/dist/client-C9XSzSXr.js +0 -1147
- package/dist/graphql-operation-types-C9qbvRa8.js +0 -53122
- package/dist/useAgentDefinitions-_hgNCK1A.js +0 -550
- package/dist/useConnections-Cs7LCWEM.js +0 -401
- package/dist/useDurableParity-CcLeCDfv.js +0 -504
- package/dist/useWorkflowOrganization-QxVePSkk.js +0 -282
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { c as setFluidGridsConfig, i as getFluidGridsTokenRevision, t as config } from "./config-X97zrIvn.js";
|
|
3
|
+
import { a as operationErrorCode, i as isUnauthenticatedError, n as hasUnauthenticatedGraphQLError, t as describeOperationError } from "./errors-xPZ-IbQd.js";
|
|
4
|
+
import { ApolloLink, Observable } from "@apollo/client/core";
|
|
5
|
+
|
|
6
|
+
// src/graphql/live-tokens.ts
|
|
7
|
+
/**
|
|
8
|
+
* Token reader for an SDK-created Apollo client (BOFF-9961).
|
|
9
|
+
*
|
|
10
|
+
* The client starts with the tokens it was created with. Once a token is set
|
|
11
|
+
* in the SDK config after that — a refresh through `auth.onTokenExpired`, or
|
|
12
|
+
* a host calling `setFluidGridsConfig({ authToken })` — every later request
|
|
13
|
+
* reads the configured value instead. Reading per request (never capturing
|
|
14
|
+
* the token in a closure) is what lets a refreshed token reach in-flight
|
|
15
|
+
* retries and websocket reconnects.
|
|
16
|
+
*/
|
|
17
|
+
function createLiveTokenReader(initial) {
|
|
18
|
+
const createdAt = getFluidGridsTokenRevision();
|
|
19
|
+
return () => {
|
|
20
|
+
if (getFluidGridsTokenRevision() === createdAt) return initial;
|
|
21
|
+
return {
|
|
22
|
+
authToken: config.authToken ?? initial.authToken,
|
|
23
|
+
workspaceToken: config.workspaceToken ?? initial.workspaceToken
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/events/eventBus.ts
|
|
29
|
+
/**
|
|
30
|
+
* Host event bus for embedders (BOFF-9961).
|
|
31
|
+
*
|
|
32
|
+
* The SDK reports what happens inside the embedded builder to the host page
|
|
33
|
+
* through one typed callback, `onEvent`, set on `FluidGridsConfig` (or the
|
|
34
|
+
* `onEvent` prop of `FluidGridsProvider`). Hosts use it to sync their own UI,
|
|
35
|
+
* analytics or backend: a workflow was saved or activated, a run started or
|
|
36
|
+
* finished, the user selected a node, something failed.
|
|
37
|
+
*
|
|
38
|
+
* This bus is separate from the product-analytics emitters in
|
|
39
|
+
* `analytics/fluidgridsEvents.ts`, which publish `fluidgrids.*` facts on the
|
|
40
|
+
* fe-libs shell bus for Rybbit/OTel. Those stay as they are; this one is the
|
|
41
|
+
* documented, versioned contract for third-party hosts.
|
|
42
|
+
*
|
|
43
|
+
* Versioning: {@link FLUIDGRIDS_EVENTS_VERSION} follows semver.
|
|
44
|
+
* - A new event name, or a new optional payload field, is a minor bump.
|
|
45
|
+
* - Removing or renaming an event, removing a payload field, or changing a
|
|
46
|
+
* field's type or meaning is a major bump (and a breaking SDK release).
|
|
47
|
+
*
|
|
48
|
+
* Delivery: events are synchronous and best effort. A handler that throws is
|
|
49
|
+
* caught and logged with a warning; it never breaks the SDK action that
|
|
50
|
+
* emitted the event.
|
|
51
|
+
*
|
|
52
|
+
* @module events/eventBus
|
|
53
|
+
*/
|
|
54
|
+
/** Version of the host event contract. See the module note for the rules. */
|
|
55
|
+
const FLUIDGRIDS_EVENTS_VERSION = "1.1.0";
|
|
56
|
+
/** Every host event name, in documentation order. */
|
|
57
|
+
const FLUIDGRIDS_EVENT_NAMES = [
|
|
58
|
+
"workflow:saved",
|
|
59
|
+
"workflow:activated",
|
|
60
|
+
"run:started",
|
|
61
|
+
"run:completed",
|
|
62
|
+
"node:selected",
|
|
63
|
+
"error",
|
|
64
|
+
"auth:failed",
|
|
65
|
+
"builder:fullscreen"
|
|
66
|
+
];
|
|
67
|
+
/** Drop undefined keys so hosts see only the fields that are known. */
|
|
68
|
+
function withoutUndefined(payload) {
|
|
69
|
+
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== void 0));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Deliver one host event. Never throws: a missing handler is a no-op and a
|
|
73
|
+
* handler that throws is logged, so SDK code can call this anywhere.
|
|
74
|
+
*/
|
|
75
|
+
function emitFluidGridsEvent(name, payload) {
|
|
76
|
+
let handler;
|
|
77
|
+
try {
|
|
78
|
+
handler = config.onEvent;
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (typeof handler !== "function") return;
|
|
83
|
+
try {
|
|
84
|
+
const args = [name, withoutUndefined(payload)];
|
|
85
|
+
handler(...args);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn(`[FluidGrids SDK] onEvent handler failed for ${name}`, error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Emit an `error` event for a failed SDK operation: the user-presentable
|
|
92
|
+
* message and, when the gateway sent one, its error code.
|
|
93
|
+
*/
|
|
94
|
+
function emitOperationErrorEvent(source, error) {
|
|
95
|
+
emitFluidGridsEvent("error", {
|
|
96
|
+
source,
|
|
97
|
+
message: describeOperationError(error),
|
|
98
|
+
code: operationErrorCode(error)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const MAX_COMPLETED_RUNS = 500;
|
|
102
|
+
const completedRuns = /* @__PURE__ */ new Set();
|
|
103
|
+
/**
|
|
104
|
+
* Emit `run:completed` once per run id. Later calls for the same run (a
|
|
105
|
+
* second poll that sees the terminal status, a remounted builder following
|
|
106
|
+
* the same run) are ignored.
|
|
107
|
+
*/
|
|
108
|
+
function emitRunCompletedOnce(payload) {
|
|
109
|
+
if (!payload.runId || completedRuns.has(payload.runId)) return;
|
|
110
|
+
completedRuns.add(payload.runId);
|
|
111
|
+
if (completedRuns.size > MAX_COMPLETED_RUNS) {
|
|
112
|
+
const oldest = completedRuns.values().next().value;
|
|
113
|
+
if (oldest !== void 0) completedRuns.delete(oldest);
|
|
114
|
+
}
|
|
115
|
+
emitFluidGridsEvent("run:completed", payload);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/graphql/token-refresh-link.ts
|
|
119
|
+
/**
|
|
120
|
+
* Token refresh on expiry (BOFF-9961).
|
|
121
|
+
*
|
|
122
|
+
* Workspace tokens are short-lived, so a builder left open outlives the token
|
|
123
|
+
* it was mounted with. The gateway then answers 401 with a GraphQL
|
|
124
|
+
* `UNAUTHENTICATED` error (category `CREDENTIAL_EXPIRED` / `_REVOKED`). This
|
|
125
|
+
* link catches that, asks the host for a fresh token through
|
|
126
|
+
* `auth.onTokenExpired`, stores it in the SDK config, and retries the failed
|
|
127
|
+
* operation once with the new headers.
|
|
128
|
+
*
|
|
129
|
+
* Rules:
|
|
130
|
+
* - one refresh at a time: operations that fail while a refresh is running
|
|
131
|
+
* wait for the same promise instead of calling the host again, and an
|
|
132
|
+
* operation that was sent before a refresh finished retries with the
|
|
133
|
+
* token that refresh produced;
|
|
134
|
+
* - each operation is retried at most once, so a token the gateway keeps
|
|
135
|
+
* refusing can never loop;
|
|
136
|
+
* - when the host cannot refresh (the callback rejects or returns no token),
|
|
137
|
+
* `auth:failed` is emitted and the operation fails with its ORIGINAL error;
|
|
138
|
+
* - an operation sent before a refresh attempt that has since FAILED does
|
|
139
|
+
* not start a new one: its 401 is the same expired session that attempt
|
|
140
|
+
* already reported, so it fails with its original error and no second
|
|
141
|
+
* `auth:failed`. Only an operation sent after the failure (the host may
|
|
142
|
+
* have recovered, e.g. the user signed in again) may try a fresh refresh.
|
|
143
|
+
*
|
|
144
|
+
* @module graphql/token-refresh-link
|
|
145
|
+
*/
|
|
146
|
+
let inFlight = null;
|
|
147
|
+
let refreshGeneration = 0;
|
|
148
|
+
let lastRefreshed = null;
|
|
149
|
+
let settledAttempts = 0;
|
|
150
|
+
let lastFailedAttempt = 0;
|
|
151
|
+
function normalizeTokens(value) {
|
|
152
|
+
if (typeof value === "string") return value.trim() ? { authToken: value } : null;
|
|
153
|
+
if (!value || typeof value !== "object") return null;
|
|
154
|
+
const tokens = {};
|
|
155
|
+
if (typeof value.authToken === "string" && value.authToken.trim()) tokens.authToken = value.authToken;
|
|
156
|
+
if (typeof value.workspaceToken === "string" && value.workspaceToken.trim()) tokens.workspaceToken = value.workspaceToken;
|
|
157
|
+
return tokens.authToken || tokens.workspaceToken ? tokens : null;
|
|
158
|
+
}
|
|
159
|
+
function storeInConfig(tokens) {
|
|
160
|
+
setFluidGridsConfig(tokens);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Run the host refresh callback, sharing one call between concurrent
|
|
164
|
+
* failures. Resolves with the fresh tokens, or null when the host could not
|
|
165
|
+
* provide any (after emitting `auth:failed`).
|
|
166
|
+
*/
|
|
167
|
+
function refreshTokens(callback, store) {
|
|
168
|
+
if (inFlight) return inFlight;
|
|
169
|
+
const fail = (message) => {
|
|
170
|
+
settledAttempts += 1;
|
|
171
|
+
lastFailedAttempt = settledAttempts;
|
|
172
|
+
emitFluidGridsEvent("auth:failed", { message });
|
|
173
|
+
return null;
|
|
174
|
+
};
|
|
175
|
+
const run = (async () => {
|
|
176
|
+
try {
|
|
177
|
+
const tokens = normalizeTokens(await callback());
|
|
178
|
+
if (!tokens) return fail("onTokenExpired returned no token.");
|
|
179
|
+
store(tokens);
|
|
180
|
+
settledAttempts += 1;
|
|
181
|
+
refreshGeneration += 1;
|
|
182
|
+
lastRefreshed = tokens;
|
|
183
|
+
return tokens;
|
|
184
|
+
} catch (error) {
|
|
185
|
+
return fail(describeOperationError(error, "Token refresh failed."));
|
|
186
|
+
}
|
|
187
|
+
})();
|
|
188
|
+
inFlight = run;
|
|
189
|
+
run.finally(() => {
|
|
190
|
+
if (inFlight === run) inFlight = null;
|
|
191
|
+
});
|
|
192
|
+
return run;
|
|
193
|
+
}
|
|
194
|
+
function withTokenHeaders(headers, tokens) {
|
|
195
|
+
return {
|
|
196
|
+
...headers,
|
|
197
|
+
...tokens.authToken && { authorization: `Bearer ${tokens.authToken}` },
|
|
198
|
+
...tokens.workspaceToken && { "x-workspace-authorization": `Bearer ${tokens.workspaceToken}` }
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function resultIsUnauthenticated(result) {
|
|
202
|
+
return hasUnauthenticatedGraphQLError(result.errors);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Apollo link that refreshes an expired token and retries once.
|
|
206
|
+
*
|
|
207
|
+
* The SDK adds it to the clients it creates (`createFluidGridsClient`,
|
|
208
|
+
* `createGlobalStoreClient`, `createFluidGridsClients`). Hosts that inject
|
|
209
|
+
* their own Apollo client add it to their chain, BEFORE the link that sets the
|
|
210
|
+
* `authorization` header, and either read the token from the SDK config in
|
|
211
|
+
* that link or pass `onTokenRefreshed`:
|
|
212
|
+
*
|
|
213
|
+
* ```ts
|
|
214
|
+
* const link = ApolloLink.from([
|
|
215
|
+
* createFluidGridsTokenRefreshLink(),
|
|
216
|
+
* authLink, // reads getFluidGridsConfig().authToken per request
|
|
217
|
+
* httpLink,
|
|
218
|
+
* ]);
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* The retried operation also carries the new token in its own headers, so it
|
|
222
|
+
* works when the host's auth link runs first, too — as long as that link
|
|
223
|
+
* does not overwrite an `authorization` header it finds.
|
|
224
|
+
*/
|
|
225
|
+
function createFluidGridsTokenRefreshLink(options = {}) {
|
|
226
|
+
return new ApolloLink((operation, forward) => {
|
|
227
|
+
const store = options.onTokenRefreshed ?? storeInConfig;
|
|
228
|
+
return new Observable((observer) => {
|
|
229
|
+
const sentInGeneration = refreshGeneration;
|
|
230
|
+
const sentAfterAttempts = settledAttempts;
|
|
231
|
+
let retried = false;
|
|
232
|
+
let closed = false;
|
|
233
|
+
let current = null;
|
|
234
|
+
const pickRefresh = (callback) => {
|
|
235
|
+
if (refreshGeneration !== sentInGeneration && lastRefreshed) return Promise.resolve(lastRefreshed);
|
|
236
|
+
if (lastFailedAttempt > sentAfterAttempts) return Promise.resolve(null);
|
|
237
|
+
return refreshTokens(callback, store);
|
|
238
|
+
};
|
|
239
|
+
const retryOrFail = (fail) => {
|
|
240
|
+
const callback = options.onTokenExpired ?? config.auth?.onTokenExpired;
|
|
241
|
+
if (!callback) return false;
|
|
242
|
+
retried = true;
|
|
243
|
+
current?.unsubscribe();
|
|
244
|
+
current = null;
|
|
245
|
+
pickRefresh(callback).then((tokens) => {
|
|
246
|
+
if (closed) return;
|
|
247
|
+
if (!tokens) {
|
|
248
|
+
fail();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const headers = operation.getContext().headers;
|
|
252
|
+
operation.setContext({ headers: withTokenHeaders(headers && typeof headers === "object" ? headers : void 0, tokens) });
|
|
253
|
+
subscribe();
|
|
254
|
+
});
|
|
255
|
+
return true;
|
|
256
|
+
};
|
|
257
|
+
const subscribe = () => {
|
|
258
|
+
let refreshing = false;
|
|
259
|
+
current = forward(operation).subscribe({
|
|
260
|
+
next: (result) => {
|
|
261
|
+
if (!retried && resultIsUnauthenticated(result) && retryOrFail(() => {
|
|
262
|
+
observer.next(result);
|
|
263
|
+
observer.complete();
|
|
264
|
+
})) {
|
|
265
|
+
refreshing = true;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
observer.next(result);
|
|
269
|
+
},
|
|
270
|
+
error: (error) => {
|
|
271
|
+
if (!retried && isUnauthenticatedError(error) && retryOrFail(() => observer.error(error))) {
|
|
272
|
+
refreshing = true;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
observer.error(error);
|
|
276
|
+
},
|
|
277
|
+
complete: () => {
|
|
278
|
+
if (!refreshing) observer.complete();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
subscribe();
|
|
283
|
+
return () => {
|
|
284
|
+
closed = true;
|
|
285
|
+
current?.unsubscribe();
|
|
286
|
+
};
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export { emitOperationErrorEvent as a, emitFluidGridsEvent as i, FLUIDGRIDS_EVENTS_VERSION as n, emitRunCompletedOnce as o, FLUIDGRIDS_EVENT_NAMES as r, createLiveTokenReader as s, createFluidGridsTokenRefreshLink as t };
|