@keboola/api-client 47.0.0 → 48.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -3
- package/API-SURFACE.md +4 -2
- package/CHANGELOG.md +31 -0
- package/README.md +1 -1
- package/dist/{adminRoles-DGM8SuuF.d.cts → adminRoles-BgpaBE7h.d.cts} +2 -2
- package/dist/{adminRoles-CvdIUkiC.d.ts → adminRoles-DsoGQipO.d.ts} +2 -2
- package/dist/ai/index.cjs +0 -5
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +2 -3
- package/dist/ai/index.d.ts +2 -3
- package/dist/ai/index.js +0 -5
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/types.d.cts +2 -2
- package/dist/ai/types.d.ts +2 -2
- package/dist/{appLogs-xW0-JQXg.d.ts → appLogs-DpcqeOe5.d.ts} +2 -2
- package/dist/{appLogs-Cxhm2Rkn.d.cts → appLogs-SjrflOHk.d.cts} +2 -2
- package/dist/apps/index.cjs +2 -2
- package/dist/apps/index.cjs.map +1 -1
- package/dist/apps/index.d.cts +3 -3
- package/dist/apps/index.d.ts +3 -3
- package/dist/apps/index.js +2 -2
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/types.d.cts +2 -2
- package/dist/apps/types.d.ts +2 -2
- package/dist/assets/index.d.cts +1 -1
- package/dist/assets/index.d.ts +1 -1
- package/dist/auth/index.d.cts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/types.d.cts +1 -1
- package/dist/auth/types.d.ts +1 -1
- package/dist/{authClient-Bso5UaXS.d.ts → authClient-BYIGzL_u.d.ts} +4 -4
- package/dist/{authClient-aud2dUZd.d.cts → authClient-D06srBQE.d.cts} +4 -4
- package/dist/billing/index.d.cts +1 -1
- package/dist/billing/index.d.ts +1 -1
- package/dist/billing/types.d.cts +1 -1
- package/dist/billing/types.d.ts +1 -1
- package/dist/chat/index.d.cts +2 -2
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat/types.d.cts +1 -1
- package/dist/chat/types.d.ts +1 -1
- package/dist/componentsMcp/index.d.cts +1 -1
- package/dist/componentsMcp/index.d.ts +1 -1
- package/dist/componentsMcp/types.d.cts +1 -1
- package/dist/componentsMcp/types.d.ts +1 -1
- package/dist/{configurations-D_Rbs0Wl.cjs → configurations-B2O8AAy0.cjs} +2 -2
- package/dist/{configurations-D_Rbs0Wl.cjs.map → configurations-B2O8AAy0.cjs.map} +1 -1
- package/dist/{configurations-Chg_JwJ1.js → configurations-CL0ouUMa.js} +3 -3
- package/dist/configurations-CL0ouUMa.js.map +1 -0
- package/dist/{configurations-BTRHVSRq.cjs → configurations-D9J3jh3g.cjs} +3 -3
- package/dist/configurations-D9J3jh3g.cjs.map +1 -0
- package/dist/{configurations-DcpUlC8I.js → configurations-DKINmjA3.js} +2 -2
- package/dist/{configurations-DcpUlC8I.js.map → configurations-DKINmjA3.js.map} +1 -1
- package/dist/constants/index.d.cts +2 -2
- package/dist/constants/index.d.ts +2 -2
- package/dist/dataScience/index.d.cts +2 -2
- package/dist/dataScience/index.d.ts +2 -2
- package/dist/dataScience/types.d.cts +2 -2
- package/dist/dataScience/types.d.ts +2 -2
- package/dist/developerPortal/index.d.cts +2 -2
- package/dist/developerPortal/index.d.ts +2 -2
- package/dist/developerPortal/types.d.cts +1 -1
- package/dist/developerPortal/types.d.ts +1 -1
- package/dist/domain/permissions/index.cjs +1 -1
- package/dist/domain/permissions/index.d.cts +2 -2
- package/dist/domain/permissions/index.d.ts +2 -2
- package/dist/domain/permissions/index.js +1 -1
- package/dist/editor/index.d.cts +2 -2
- package/dist/editor/index.d.ts +2 -2
- package/dist/editor/types.d.cts +1 -1
- package/dist/editor/types.d.ts +1 -1
- package/dist/encryption/index.d.cts +1 -1
- package/dist/encryption/index.d.ts +1 -1
- package/dist/encryption/types.d.cts +1 -1
- package/dist/encryption/types.d.ts +1 -1
- package/dist/import/index.d.cts +3 -3
- package/dist/import/index.d.ts +3 -3
- package/dist/{index-CAWy1qjR.d.ts → index-B3QTeqfL.d.ts} +300 -140
- package/dist/{index-Ds0tViQS.d.cts → index-BCjU-g9t.d.cts} +3 -3
- package/dist/{index-BGEuaZqI.d.cts → index-BHiJu8LF.d.cts} +9 -4
- package/dist/{index-BeOd45XE.d.ts → index-BIldED4N.d.ts} +4 -4
- package/dist/{index-B_MzjCeE.d.ts → index-BLvmyehw.d.ts} +3 -3
- package/dist/{index-DloFSSj3.d.ts → index-BTrxCk90.d.ts} +3 -3
- package/dist/{index-x_kS_5x_.d.cts → index-ByLCYBaw.d.cts} +4 -4
- package/dist/{index-CkwZ5x7E.d.cts → index-C40Fbj-6.d.cts} +300 -140
- package/dist/{index-Dp-a2DdI.d.ts → index-CIqWOEWD.d.ts} +4 -4
- package/dist/{index-DTysQ_yn.d.cts → index-Cc5wSIRJ.d.cts} +5 -5
- package/dist/{index-XaPb6unB.d.cts → index-ChDl6ig5.d.cts} +256 -33
- package/dist/{index-URgNfi5L.d.cts → index-Co2Cd-nw.d.cts} +3 -3
- package/dist/{index-DUB0BwQv.d.cts → index-CpGmmJbt.d.cts} +4 -4
- package/dist/{index-ZYvgoqgW.d.cts → index-CpUYVB-d.d.cts} +4 -4
- package/dist/{index-BnPmXDVP.d.ts → index-CzHrIfZS.d.ts} +2 -2
- package/dist/{index-XG5cO-4H.d.cts → index-D91RxB_S.d.cts} +18 -13
- package/dist/{index-_Va9wynk.d.ts → index-DlZiWfQb.d.ts} +9 -4
- package/dist/{index-HSkjm3QW.d.ts → index-DzLXtE4Q.d.ts} +5 -5
- package/dist/{index-8ZjY7YD8.d.cts → index-VlzlOBkc.d.cts} +2 -2
- package/dist/{index-BIP0PoMW.d.ts → index-avzO5sLa.d.ts} +18 -13
- package/dist/{index-C2OAOK0s.d.ts → index-m7fX76x3.d.ts} +4 -4
- package/dist/{index-r6YSe8B-.d.ts → index-sDHBkJhU.d.ts} +256 -33
- package/dist/index.cjs +451 -256
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +451 -257
- package/dist/index.js.map +1 -1
- package/dist/kaiAgent/index.cjs +1 -1
- package/dist/kaiAgent/index.d.cts +3 -3
- package/dist/kaiAgent/index.d.ts +3 -3
- package/dist/kaiAgent/index.js +1 -1
- package/dist/kaiAgent/types.d.cts +1 -1
- package/dist/kaiAgent/types.d.ts +1 -1
- package/dist/{kaiAgent-CBPbMwBh.js → kaiAgent-CYvrS8oZ.js} +12 -3
- package/dist/kaiAgent-CYvrS8oZ.js.map +1 -0
- package/dist/{kaiAgent-BmfUG8bB.cjs → kaiAgent-N2qbUFZm.cjs} +12 -3
- package/dist/kaiAgent-N2qbUFZm.cjs.map +1 -0
- package/dist/management/index.cjs +1 -1
- package/dist/management/index.d.cts +1 -1
- package/dist/management/index.d.ts +1 -1
- package/dist/management/index.js +1 -1
- package/dist/management/types.d.cts +2 -2
- package/dist/management/types.d.ts +2 -2
- package/dist/{management-BUGPJ1Bu.cjs → management-CXHnxVaZ.cjs} +12 -5
- package/dist/management-CXHnxVaZ.cjs.map +1 -0
- package/dist/{management-DAg2obYt.js → management-NYAD6ej4.js} +12 -5
- package/dist/management-NYAD6ej4.js.map +1 -0
- package/dist/metastore/index.d.cts +1 -1
- package/dist/metastore/index.d.ts +1 -1
- package/dist/metastore/types.d.cts +1 -1
- package/dist/metastore/types.d.ts +1 -1
- package/dist/microsoftGraph/index.d.cts +2 -2
- package/dist/microsoftGraph/index.d.ts +2 -2
- package/dist/microsoftGraph/types.d.cts +1 -1
- package/dist/microsoftGraph/types.d.ts +1 -1
- package/dist/{middleware-DU_5pFDW.cjs → middleware-CEP6uu_D.cjs} +4 -4
- package/dist/middleware-CEP6uu_D.cjs.map +1 -0
- package/dist/{middleware-CWaLMlG1.js → middleware-GOfx8Apu.js} +4 -4
- package/dist/middleware-GOfx8Apu.js.map +1 -0
- package/dist/notifications/index.d.cts +2 -2
- package/dist/notifications/index.d.ts +2 -2
- package/dist/notifications/types.d.cts +1 -1
- package/dist/notifications/types.d.ts +1 -1
- package/dist/oauth/index.d.cts +2 -2
- package/dist/oauth/index.d.ts +2 -2
- package/dist/oauth/types.d.cts +1 -1
- package/dist/oauth/types.d.ts +1 -1
- package/dist/omnisearch/index.d.cts +2 -2
- package/dist/omnisearch/index.d.ts +2 -2
- package/dist/omnisearch/types.d.cts +1 -1
- package/dist/omnisearch/types.d.ts +1 -1
- package/dist/{project-dxCJbFay.d.cts → project-Dzu85cqr.d.cts} +3 -3
- package/dist/{project-BMmfPhXg.d.ts → project-nbv9yjpl.d.ts} +3 -3
- package/dist/queryService/index.d.cts +1 -1
- package/dist/queryService/index.d.ts +1 -1
- package/dist/queryService/types.d.cts +1 -1
- package/dist/queryService/types.d.ts +1 -1
- package/dist/queue/index.d.cts +3 -3
- package/dist/queue/index.d.ts +3 -3
- package/dist/queue/types.d.cts +1 -1
- package/dist/queue/types.d.ts +1 -1
- package/dist/scheduler/index.d.cts +2 -2
- package/dist/scheduler/index.d.ts +2 -2
- package/dist/scheduler/types.d.cts +1 -1
- package/dist/scheduler/types.d.ts +1 -1
- package/dist/sdk/configurations/index.cjs +1 -1
- package/dist/sdk/configurations/index.d.cts +2 -2
- package/dist/sdk/configurations/index.d.ts +2 -2
- package/dist/sdk/configurations/index.js +1 -1
- package/dist/sdk/developerPortal/index.cjs +1 -1
- package/dist/sdk/developerPortal/index.d.cts +3 -3
- package/dist/sdk/developerPortal/index.d.ts +3 -3
- package/dist/sdk/developerPortal/index.js +1 -1
- package/dist/sdk/kaiMemory/index.d.cts +1 -1
- package/dist/sdk/kaiMemory/index.d.ts +1 -1
- package/dist/sdk/kaiMemory/types.d.cts +1 -1
- package/dist/sdk/kaiMemory/types.d.ts +1 -1
- package/dist/sdk/queryService/index.d.cts +1 -1
- package/dist/sdk/queryService/index.d.ts +1 -1
- package/dist/sdk/semanticLayer/index.d.cts +1 -1
- package/dist/sdk/semanticLayer/index.d.ts +1 -1
- package/dist/sdk/semanticLayer/types.d.cts +1 -1
- package/dist/sdk/semanticLayer/types.d.ts +1 -1
- package/dist/sdk/tag/index.d.cts +2 -2
- package/dist/sdk/tag/index.d.ts +2 -2
- package/dist/sdk/tag/types.d.cts +1 -1
- package/dist/sdk/tag/types.d.ts +1 -1
- package/dist/sdk/vault/index.d.cts +1 -1
- package/dist/sdk/vault/index.d.ts +1 -1
- package/dist/status/index.d.cts +1 -1
- package/dist/status/index.d.ts +1 -1
- package/dist/storage/index.cjs +1 -1
- package/dist/storage/index.d.cts +2 -2
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +1 -1
- package/dist/storage/types.d.cts +6 -6
- package/dist/storage/types.d.ts +6 -6
- package/dist/{storage-DyR7hDdv.js → storage-BR-Kgi-6.js} +7 -2
- package/dist/storage-BR-Kgi-6.js.map +1 -0
- package/dist/{storage-yovv11k6.cjs → storage-CVBXivpB.cjs} +7 -2
- package/dist/storage-CVBXivpB.cjs.map +1 -0
- package/dist/stream/index.d.cts +2 -2
- package/dist/stream/index.d.ts +2 -2
- package/dist/stream/types.d.cts +1 -1
- package/dist/stream/types.d.ts +1 -1
- package/dist/syncActions/index.d.cts +2 -2
- package/dist/syncActions/index.d.ts +2 -2
- package/dist/syncActions/types.d.cts +1 -1
- package/dist/syncActions/types.d.ts +1 -1
- package/dist/telemetry/index.d.cts +2 -2
- package/dist/telemetry/index.d.ts +2 -2
- package/dist/telemetry/types.d.cts +1 -1
- package/dist/telemetry/types.d.ts +1 -1
- package/dist/{types-L50Y6ATu.d.cts → types-0ZAMQhva.d.cts} +3 -3
- package/dist/{types-BoH7NFCh.d.ts → types-1LENlL5h.d.ts} +3 -3
- package/dist/{types-kbyIaA7p.d.cts → types-6KabdIyO.d.cts} +3 -3
- package/dist/{types-Bx0TSdwF.d.cts → types-9d8ihjZh.d.cts} +2 -2
- package/dist/{types-COQOzyac.d.ts → types-B7L6uSYb.d.ts} +7 -3
- package/dist/{types-DWJVbskE.d.ts → types-BTy_FFSu.d.ts} +2 -2
- package/dist/{types-4HmtNuJf.d.ts → types-BWYtQkHu.d.ts} +2 -2
- package/dist/{types-BIDKSQdc.d.ts → types-BXHZQvGy.d.ts} +169 -31
- package/dist/{types-B2ZLjagf.d.ts → types-BYFU_6Iz.d.ts} +2 -2
- package/dist/{types-BNPvFLgC.d.ts → types-BaqdM92a.d.ts} +3 -4
- package/dist/{types-BKIcow3B.d.cts → types-BbwrMl0Q.d.cts} +2 -2
- package/dist/{types-Dg8a7m7f.d.ts → types-Bt8CEZ6K.d.ts} +2 -2
- package/dist/{types-4bSZLxq3.d.cts → types-BtS3DhGu.d.cts} +169 -31
- package/dist/{types-C2j6Jsie.d.ts → types-C-GSYDTN.d.ts} +3 -3
- package/dist/{types-BwsE-pFo.d.cts → types-C4eQ-Zcx.d.cts} +2 -2
- package/dist/{types-ij6BpTzR.d.ts → types-C9VaQSqV.d.ts} +2 -2
- package/dist/{types-BZBU3mwz.d.cts → types-CNkQuWnO.d.cts} +3 -3
- package/dist/{types-TRJiPqJr.d.cts → types-CXv_e6xC.d.cts} +2 -2
- package/dist/{types-CMKIdreQ.d.cts → types-C_raqbl-.d.cts} +3 -3
- package/dist/{types-BjEiUOL6.d.ts → types-Cc4yTEdK.d.ts} +2 -2
- package/dist/{types-ituiCs8g.d.ts → types-Ce5Blzhg.d.ts} +2 -2
- package/dist/{types-CBrNIgEy.d.ts → types-CfZLdfAL.d.ts} +3 -3
- package/dist/{types-4CjbcUdD.d.cts → types-Cfc-fYbq.d.cts} +2 -2
- package/dist/{types-DHlXKVEM.d.ts → types-Cn8I0vcr.d.ts} +3 -3
- package/dist/{types-C7t_6FLh.d.ts → types-CpWE6Yg2.d.ts} +2 -2
- package/dist/{types-DBJ8c3hN.d.cts → types-CrJIILXf.d.cts} +2 -2
- package/dist/{types-B_3zoXA1.d.cts → types-CwGbiMF-.d.cts} +3 -3
- package/dist/{types-BiTn_JVW.d.cts → types-CwQ8_n8q.d.ts} +94 -13
- package/dist/{types-Cw9UISvM.d.ts → types-D3H3EAre.d.ts} +2 -2
- package/dist/{types-BG0oWq8u.d.cts → types-D3mj56iq.d.cts} +2 -2
- package/dist/{types-D51g4h9w.d.cts → types-D8d5tyGi.d.cts} +2 -2
- package/dist/{types-CZCPdPqv.d.cts → types-DMpiG2q4.d.cts} +3 -3
- package/dist/{types-DPDq8C4q.d.cts → types-DSBrhK_K.d.cts} +2 -2
- package/dist/{types--qQPfxWt.d.cts → types-DXF6faow.d.cts} +2 -2
- package/dist/{types-BXgINefw.d.ts → types-DfJP6Dti.d.ts} +2 -2
- package/dist/{types-C3IQu1gV.d.ts → types-DgOLSRiy.d.ts} +3 -3
- package/dist/{types-BdF6NDvo.d.cts → types-DlgqPU_4.d.cts} +2 -2
- package/dist/{types-C2JMisvL.d.ts → types-Dn1G-qv4.d.cts} +94 -13
- package/dist/{types-B6ozaDkl.d.cts → types-EkyQ0_10.d.cts} +2 -2
- package/dist/{types-B_1plf0y.d.cts → types-EmIcG-8K.d.cts} +2 -2
- package/dist/{types-D8w9lyb8.d.cts → types-NSxpnYW5.d.cts} +7 -3
- package/dist/{types-CEw2IzWk.d.ts → types-QPW-7dPm.d.ts} +2 -2
- package/dist/{types-BcQ3j8xK.d.ts → types-UySfduQo.d.ts} +2 -2
- package/dist/{types-7DBpH7Rf.d.ts → types-VehpPOQX.d.ts} +2 -2
- package/dist/{types-BiBBKcin.d.ts → types-Vu09EUZs.d.ts} +3 -3
- package/dist/{types-DgIzXY-Y.d.ts → types-c4h2YDMC.d.ts} +2 -2
- package/dist/{types-OkQWmonU.d.cts → types-sOM2_KPc.d.cts} +2 -2
- package/dist/{types-BBbzWczQ.d.cts → types-wNuJUhco.d.cts} +3 -4
- package/dist/vault/index.d.cts +1 -1
- package/dist/vault/index.d.ts +1 -1
- package/dist/vault/types.d.cts +1 -1
- package/dist/vault/types.d.ts +1 -1
- package/package.json +1 -1
- package/surface/ai.md +0 -1
- package/surface/kaiAgent.md +5 -4
- package/surface/management.md +1 -0
- package/surface/storage.md +3 -2
- package/dist/configurations-BTRHVSRq.cjs.map +0 -1
- package/dist/configurations-Chg_JwJ1.js.map +0 -1
- package/dist/kaiAgent-BmfUG8bB.cjs.map +0 -1
- package/dist/kaiAgent-CBPbMwBh.js.map +0 -1
- package/dist/management-BUGPJ1Bu.cjs.map +0 -1
- package/dist/management-DAg2obYt.js.map +0 -1
- package/dist/middleware-CWaLMlG1.js.map +0 -1
- package/dist/middleware-DU_5pFDW.cjs.map +0 -1
- package/dist/storage-DyR7hDdv.js.map +0 -1
- package/dist/storage-yovv11k6.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -5,11 +5,11 @@ import { t as concurrent } from "./concurrent-BacWxPwi.js";
|
|
|
5
5
|
import { t as dedupe } from "./dedupe-Cky1gSUu.js";
|
|
6
6
|
import { a as poller, c as Result, d as delay, i as failureOf, l as asError, n as jobStatus, o as clamp, r as emitter, s as finiteOr, u as lazy } from "./transientRetries-B4iusp69.js";
|
|
7
7
|
import { n as createEmitter, t as createStore } from "./store-C9FQCHGe.js";
|
|
8
|
-
import { a as StorageJobError, c as readableReason, l as series, o as isStorageJobError, s as ServiceUnavailableError, t as createStorageClient } from "./storage-
|
|
8
|
+
import { a as StorageJobError, c as readableReason, l as series, o as isStorageJobError, s as ServiceUnavailableError, t as createStorageClient } from "./storage-BR-Kgi-6.js";
|
|
9
9
|
import { n as keboolaUID, t as createTagSdk } from "./tag-hh-1nhNr.js";
|
|
10
10
|
import { t as generateUUID } from "./generateUUID-Dr8l-aoc.js";
|
|
11
11
|
import { t as isPlainObject } from "./isPlainObject-LYW-03uB.js";
|
|
12
|
-
import { n as schemaGuidedMerge, r as isEmptyDeep, t as createConfigurationSdk } from "./configurations-
|
|
12
|
+
import { n as schemaGuidedMerge, r as isEmptyDeep, t as createConfigurationSdk } from "./configurations-DKINmjA3.js";
|
|
13
13
|
import { t as UserError } from "./UserError-By_Zckmc.js";
|
|
14
14
|
import { _ as KeboolaHttpHeader, a as isTimeoutError, d as normalizeBaseUrl, g as HttpStatus, i as isFetchClientError, m as CREDENTIAL_HEADERS, n as isAbortError, o as HttpContentType, p as ApiError, r as isApiError, s as HttpHeader, v as REDACTED, y as redactHeaders } from "./createFetchClient-CkHdS_IG.js";
|
|
15
15
|
import { n as HtmlResponseError, r as isHtmlResponseError } from "./validateConnectionStatus-DyrYpn0G.js";
|
|
@@ -20,7 +20,7 @@ import { n as isSyncActionError, t as SyncActionError } from "./SyncActionError-
|
|
|
20
20
|
import { i as parseOrThrow, n as formatValidationIssues, r as isValidationError, t as ValidationError } from "./ValidationError-DjhtNMfZ.js";
|
|
21
21
|
import { t as createGenericFetchClient } from "./createGenericFetchClient-CQdNcPC3.js";
|
|
22
22
|
import { t as createImportClient } from "./import-FWy_wQZ1.js";
|
|
23
|
-
import { n as isManagementClientAuthError, r as isManagementSessionMintError, t as createManagementClient } from "./management-
|
|
23
|
+
import { n as isManagementClientAuthError, r as isManagementSessionMintError, t as createManagementClient } from "./management-NYAD6ej4.js";
|
|
24
24
|
import { o as ServiceId, s as ProjectFeature } from "./constants-CA4UN2Xv.js";
|
|
25
25
|
import { t as createStorageTable } from "./storageTable-BldTNyEk.js";
|
|
26
26
|
import { i as createKaiMemorySdk } from "./kaiMemory-C9di17bd.js";
|
|
@@ -35,7 +35,7 @@ import { t as createComponentsMcpClient } from "./componentsMcp-CHobIsuU.js";
|
|
|
35
35
|
import { t as createDataScienceClient } from "./dataScience-AwPMeGfz.js";
|
|
36
36
|
import { createEditorClient } from "./editor/index.js";
|
|
37
37
|
import { createEncryptionClient } from "./encryption/index.js";
|
|
38
|
-
import { t as createKaiAgentClient } from "./kaiAgent-
|
|
38
|
+
import { t as createKaiAgentClient } from "./kaiAgent-CYvrS8oZ.js";
|
|
39
39
|
import { t as createMetastoreClient } from "./metastore-Ywq08DBz.js";
|
|
40
40
|
import { createNotificationsClient } from "./notifications/index.js";
|
|
41
41
|
import { t as createOauthClient } from "./oauth-GXmZ9agP.js";
|
|
@@ -47,7 +47,7 @@ import { createStreamClient } from "./stream/index.js";
|
|
|
47
47
|
import { t as createSyncActionsClient } from "./syncActions-DM8vP7p3.js";
|
|
48
48
|
import { createTelemetryClient } from "./telemetry/index.js";
|
|
49
49
|
import { createVaultClient } from "./vault/index.js";
|
|
50
|
-
import { n as isUnauthorized, t as createBearerAuthMiddleware } from "./middleware-
|
|
50
|
+
import { n as isUnauthorized, t as createBearerAuthMiddleware } from "./middleware-GOfx8Apu.js";
|
|
51
51
|
import { createQueryServiceSdk } from "./sdk/queryService/index.js";
|
|
52
52
|
import * as z$1 from "zod";
|
|
53
53
|
//#region src/utils/assert.ts
|
|
@@ -260,6 +260,47 @@ const createPollRegistry = ({ limit = DEFAULT_LIMIT } = {}) => {
|
|
|
260
260
|
};
|
|
261
261
|
};
|
|
262
262
|
//#endregion
|
|
263
|
+
//#region src/utils/async/queueSeries.ts
|
|
264
|
+
const isPromiseLike = (value) => (typeof value === "object" && value !== null || typeof value === "function") && "then" in value && typeof value.then === "function";
|
|
265
|
+
/**
|
|
266
|
+
* Queues tasks added over time so a slower earlier task cannot finish after and overwrite a later one.
|
|
267
|
+
* Each `add` returns its task's result; a rejection does not stop the remaining queue.
|
|
268
|
+
*/
|
|
269
|
+
const queueSeries = () => {
|
|
270
|
+
let tail = null;
|
|
271
|
+
const add = (task) => {
|
|
272
|
+
if (tail !== null) {
|
|
273
|
+
const result = tail.then(task);
|
|
274
|
+
tail = result.then(() => void 0, () => void 0);
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
277
|
+
let value;
|
|
278
|
+
try {
|
|
279
|
+
value = task();
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return Promise.reject(error);
|
|
282
|
+
}
|
|
283
|
+
if (!isPromiseLike(value)) return Promise.resolve(value);
|
|
284
|
+
const result = Promise.resolve(value);
|
|
285
|
+
tail = result.then(() => void 0, () => void 0);
|
|
286
|
+
return result;
|
|
287
|
+
};
|
|
288
|
+
const onIdle = async () => {
|
|
289
|
+
while (tail !== null) {
|
|
290
|
+
const current = tail;
|
|
291
|
+
await current;
|
|
292
|
+
if (tail === current) {
|
|
293
|
+
tail = null;
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
return {
|
|
299
|
+
add,
|
|
300
|
+
onIdle
|
|
301
|
+
};
|
|
302
|
+
};
|
|
303
|
+
//#endregion
|
|
263
304
|
//#region src/utils/deepMerge.ts
|
|
264
305
|
/**
|
|
265
306
|
* Recursively merge `patch` into `base`. Plain-object values are merged key-by-key; every
|
|
@@ -317,6 +358,10 @@ const createWebStorage = (pick) => {
|
|
|
317
358
|
},
|
|
318
359
|
removeItem: (key) => {
|
|
319
360
|
storage.removeItem(key);
|
|
361
|
+
},
|
|
362
|
+
withLock: async (name, task) => {
|
|
363
|
+
if (typeof navigator === "undefined" || !("locks" in navigator)) return task();
|
|
364
|
+
return navigator.locks.request(`keboola:${name}`, { mode: "exclusive" }, task);
|
|
320
365
|
}
|
|
321
366
|
};
|
|
322
367
|
};
|
|
@@ -325,62 +370,56 @@ const createSessionStorage = () => createWebStorage(() => "sessionStorage" in gl
|
|
|
325
370
|
//#endregion
|
|
326
371
|
//#region src/utils/persistor/persistor.ts
|
|
327
372
|
const createPersistor = ({ storage = createNullStorage(), key, schema, defaultValue, encode = JSON.stringify, decode = JSON.parse }) => {
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const hasPersistedValue = () => {
|
|
336
|
-
try {
|
|
337
|
-
return !!storage.getItem(key);
|
|
338
|
-
} catch (err) {
|
|
339
|
-
console.warn(`createPersistor: failed to read "${key}", assuming empty`, err);
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
const hydrate = () => {
|
|
344
|
-
let raw;
|
|
345
|
-
try {
|
|
346
|
-
raw = storage.getItem(key);
|
|
347
|
-
} catch (err) {
|
|
348
|
-
console.warn(`createPersistor: failed to read "${key}", using default`, err);
|
|
349
|
-
return defaultValue;
|
|
350
|
-
}
|
|
351
|
-
if (raw === null) return defaultValue;
|
|
373
|
+
const writes = queueSeries();
|
|
374
|
+
const _load = async () => {
|
|
375
|
+
const raw = await storage.getItem(key);
|
|
376
|
+
if (raw === null) return {
|
|
377
|
+
value: defaultValue,
|
|
378
|
+
corrupt: false
|
|
379
|
+
};
|
|
352
380
|
let decoded;
|
|
353
381
|
try {
|
|
354
382
|
decoded = decode(raw);
|
|
355
383
|
} catch (err) {
|
|
356
|
-
console.warn(`createPersistor: failed to decode "${key}"
|
|
357
|
-
|
|
358
|
-
|
|
384
|
+
console.warn(`createPersistor: failed to decode "${key}"`, err);
|
|
385
|
+
return {
|
|
386
|
+
value: defaultValue,
|
|
387
|
+
corrupt: true
|
|
388
|
+
};
|
|
359
389
|
}
|
|
360
390
|
const parsed = schema.safeParse(decoded);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
391
|
+
return parsed.success ? {
|
|
392
|
+
value: parsed.data,
|
|
393
|
+
corrupt: false
|
|
394
|
+
} : {
|
|
395
|
+
value: defaultValue,
|
|
396
|
+
corrupt: true
|
|
397
|
+
};
|
|
364
398
|
};
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
storage.setItem(key, raw);
|
|
375
|
-
} catch (err) {
|
|
376
|
-
console.warn(`createPersistor: failed to write "${key}"`, err);
|
|
377
|
-
}
|
|
399
|
+
const remove = () => writes.add(() => storage.removeItem(key));
|
|
400
|
+
const write = (value) => writes.add(() => storage.setItem(key, encode(value)));
|
|
401
|
+
const read = async () => {
|
|
402
|
+
await writes.onIdle();
|
|
403
|
+
const parsed = await _load();
|
|
404
|
+
if (parsed.corrupt) remove().catch((err) => {
|
|
405
|
+
console.warn(`createPersistor: failed to drop the corrupt "${key}"`, err);
|
|
406
|
+
});
|
|
407
|
+
return parsed.value;
|
|
378
408
|
};
|
|
409
|
+
const modify = (change) => writes.add(async () => {
|
|
410
|
+
const next = change((await _load()).value);
|
|
411
|
+
await storage.setItem(key, encode(next));
|
|
412
|
+
});
|
|
413
|
+
const cell = {
|
|
414
|
+
read,
|
|
415
|
+
write,
|
|
416
|
+
modify,
|
|
417
|
+
remove
|
|
418
|
+
};
|
|
419
|
+
const locked = (task) => storage.withLock ? storage.withLock(key, () => task(cell)) : task(cell);
|
|
379
420
|
return {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
clear,
|
|
383
|
-
hasPersistedValue
|
|
421
|
+
...cell,
|
|
422
|
+
locked
|
|
384
423
|
};
|
|
385
424
|
};
|
|
386
425
|
//#endregion
|
|
@@ -1072,159 +1111,6 @@ const createLegacyKeboola = (options = {}) => {
|
|
|
1072
1111
|
};
|
|
1073
1112
|
};
|
|
1074
1113
|
//#endregion
|
|
1075
|
-
//#region src/keboola/bearer/credentials/renewal.ts
|
|
1076
|
-
const renewalGrant = (credential) => credential.type === "token" ? {
|
|
1077
|
-
type: "token",
|
|
1078
|
-
refreshToken: credential.refreshToken
|
|
1079
|
-
} : {
|
|
1080
|
-
type: "cookie",
|
|
1081
|
-
sessionId: credential.sessionId
|
|
1082
|
-
};
|
|
1083
|
-
const renew = async (client, grant) => {
|
|
1084
|
-
if (grant.type === "cookie") {
|
|
1085
|
-
const { accessToken, expiresIn, sessionId } = await client.token.refreshWithSession({ sessionId: grant.sessionId });
|
|
1086
|
-
return {
|
|
1087
|
-
type: "cookie",
|
|
1088
|
-
accessToken,
|
|
1089
|
-
expiresIn,
|
|
1090
|
-
sessionId
|
|
1091
|
-
};
|
|
1092
|
-
}
|
|
1093
|
-
const { accessToken, expiresIn, refreshToken } = await client.token.refreshWithToken({ refreshToken: grant.refreshToken });
|
|
1094
|
-
if (!refreshToken) throw new KeboolaError(KeboolaErrorType.NotAuthenticated);
|
|
1095
|
-
return {
|
|
1096
|
-
type: "token",
|
|
1097
|
-
accessToken,
|
|
1098
|
-
expiresIn,
|
|
1099
|
-
refreshToken
|
|
1100
|
-
};
|
|
1101
|
-
};
|
|
1102
|
-
//#endregion
|
|
1103
|
-
//#region src/keboola/bearer/credentials/credentials.ts
|
|
1104
|
-
const DEFAULT_REFRESH_THRESHOLD = .9;
|
|
1105
|
-
const signInEnded = () => new KeboolaError(KeboolaErrorType.SignInEnded);
|
|
1106
|
-
const toRestoreStatus = (outcome) => {
|
|
1107
|
-
if (outcome === void 0 || outcome === "skipped") return "empty";
|
|
1108
|
-
if (outcome === "refused") return "expired";
|
|
1109
|
-
return outcome;
|
|
1110
|
-
};
|
|
1111
|
-
const createCredentials = ({ state, persistor, middlewares, refreshThreshold = DEFAULT_REFRESH_THRESHOLD, onSignedOut, onExpired }) => {
|
|
1112
|
-
const rotationMap = /* @__PURE__ */ new Map();
|
|
1113
|
-
const generations = /* @__PURE__ */ new Map();
|
|
1114
|
-
const generationOf = (baseUrl) => generations.get(baseUrl) ?? 0;
|
|
1115
|
-
const refresh = async (baseUrl, grant) => {
|
|
1116
|
-
const client = createAuthClient({
|
|
1117
|
-
baseUrl,
|
|
1118
|
-
middlewares
|
|
1119
|
-
});
|
|
1120
|
-
const epochBefore = Result.unwrap(state.auth.getEpoch(baseUrl));
|
|
1121
|
-
const generationBefore = generationOf(baseUrl);
|
|
1122
|
-
const refreshed = await Result.tryCatchAsync(() => renew(client, grant));
|
|
1123
|
-
return Result.unwrapOr(state.auth.getEpoch(baseUrl), -1) === epochBefore && generationOf(baseUrl) === generationBefore ? refreshed : Result.failure(signInEnded());
|
|
1124
|
-
};
|
|
1125
|
-
/**
|
|
1126
|
-
* A stack's teardown, from the credential's side.
|
|
1127
|
-
*
|
|
1128
|
-
* - Bumps the generation, so an in-flight rotation can no longer write.
|
|
1129
|
-
* - Drops the deduped entry, so nothing joins that rotation.
|
|
1130
|
-
*/
|
|
1131
|
-
const forget = (baseUrl) => {
|
|
1132
|
-
generations.set(baseUrl, generationOf(baseUrl) + 1);
|
|
1133
|
-
rotationMap.delete(baseUrl);
|
|
1134
|
-
};
|
|
1135
|
-
/**
|
|
1136
|
-
* The rotation, and the one place a credential is declared dead.
|
|
1137
|
-
*
|
|
1138
|
-
* - Renews by the credential's own kind: the refresh token, or the session id with the cookie.
|
|
1139
|
-
* - A refused refresh token or session is unambiguous.
|
|
1140
|
-
* - The triggering 401 is not (an unreachable project answers the same), so never sign out on a replay.
|
|
1141
|
-
*/
|
|
1142
|
-
const rotateOnce = async (baseUrl) => {
|
|
1143
|
-
const credential = state.auth.requireCredential(baseUrl);
|
|
1144
|
-
if (!credential.success) return credential;
|
|
1145
|
-
const refreshed = await refresh(baseUrl, renewalGrant(credential.data));
|
|
1146
|
-
if (!refreshed.success) {
|
|
1147
|
-
if (isUnauthorized(refreshed.error)) expire(baseUrl);
|
|
1148
|
-
return refreshed;
|
|
1149
|
-
}
|
|
1150
|
-
return Result.map(state.auth.applyRefresh(baseUrl, refreshed.data), () => refreshed.data.accessToken);
|
|
1151
|
-
};
|
|
1152
|
-
const rotate = (baseUrl) => ensure(rotationMap, baseUrl, () => dedupe(() => rotateOnce(baseUrl)))();
|
|
1153
|
-
const restoreStack = async (baseUrl, grant) => {
|
|
1154
|
-
if (!state.auth.startRestore(baseUrl).success) return "unreachable";
|
|
1155
|
-
const refreshed = await refresh(baseUrl, grant);
|
|
1156
|
-
if (!refreshed.success) {
|
|
1157
|
-
state.auth.cancelRestore(baseUrl);
|
|
1158
|
-
return isUnauthorized(refreshed.error) ? "refused" : "unreachable";
|
|
1159
|
-
}
|
|
1160
|
-
state.auth.authenticate(baseUrl, refreshed.data);
|
|
1161
|
-
return "restored";
|
|
1162
|
-
};
|
|
1163
|
-
const restoreProjects = (baseUrl, projects) => {
|
|
1164
|
-
for (const { projectId } of projects) state.projects.open(baseUrl, projectId);
|
|
1165
|
-
};
|
|
1166
|
-
/**
|
|
1167
|
-
* Every persisted stack back into the table, with whatever credential it can hand back.
|
|
1168
|
-
*
|
|
1169
|
-
* - Never writes the scope. `lastActive` is what was scoped when the session was stored, for the
|
|
1170
|
-
* caller to select.
|
|
1171
|
-
* - `status` reports what became of `lastActive`'s credential; the client reads it to decide
|
|
1172
|
-
* when persistence may start.
|
|
1173
|
-
*/
|
|
1174
|
-
const restore = async () => {
|
|
1175
|
-
const { stacks, current } = persistor.hydrate();
|
|
1176
|
-
const scoped = stacks.find(({ baseUrl }) => baseUrl === current?.baseUrl);
|
|
1177
|
-
const restored = stacks.map(async ({ baseUrl, credential, projects }) => {
|
|
1178
|
-
state.stacks.ensure(baseUrl);
|
|
1179
|
-
if (!credential) return "unreachable";
|
|
1180
|
-
if (Result.unwrapOr(state.auth.getEpoch(baseUrl), 0) > 0) return "skipped";
|
|
1181
|
-
const outcome = await restoreStack(baseUrl, credential);
|
|
1182
|
-
if (outcome === "restored") restoreProjects(baseUrl, projects);
|
|
1183
|
-
return outcome;
|
|
1184
|
-
});
|
|
1185
|
-
const results = await Promise.all(restored);
|
|
1186
|
-
const scopedOutcome = scoped?.credential ? results[stacks.indexOf(scoped)] : void 0;
|
|
1187
|
-
return {
|
|
1188
|
-
lastActive: current,
|
|
1189
|
-
status: toRestoreStatus(scopedOutcome)
|
|
1190
|
-
};
|
|
1191
|
-
};
|
|
1192
|
-
const isStale = (baseUrl) => {
|
|
1193
|
-
const ageing = Result.map(state.auth.requireCredential(baseUrl), ({ issuedAt, expiresIn }) => Date.now() >= issuedAt + expiresIn * 1e3 * refreshThreshold);
|
|
1194
|
-
return Result.unwrapOr(ageing, false);
|
|
1195
|
-
};
|
|
1196
|
-
const signOut = (baseUrl) => {
|
|
1197
|
-
rotationMap.delete(baseUrl);
|
|
1198
|
-
const signedOut = state.auth.signOut(baseUrl);
|
|
1199
|
-
onSignedOut?.(baseUrl);
|
|
1200
|
-
return signedOut;
|
|
1201
|
-
};
|
|
1202
|
-
const expire = (baseUrl) => {
|
|
1203
|
-
if (!state.auth.notifyExpired(baseUrl)) return;
|
|
1204
|
-
signOut(baseUrl);
|
|
1205
|
-
onExpired?.(baseUrl);
|
|
1206
|
-
};
|
|
1207
|
-
const renewIfStale = async (baseUrl) => {
|
|
1208
|
-
if (isStale(baseUrl)) await rotate(baseUrl);
|
|
1209
|
-
};
|
|
1210
|
-
const middleware = (baseUrl) => createBearerAuthMiddleware({ getAccessToken: async ({ forceRefresh = false } = {}) => {
|
|
1211
|
-
if (forceRefresh) {
|
|
1212
|
-
if (!state.auth.requireCredential(baseUrl).success) return null;
|
|
1213
|
-
return Result.unwrap(await rotate(baseUrl));
|
|
1214
|
-
}
|
|
1215
|
-
await renewIfStale(baseUrl);
|
|
1216
|
-
return state.auth.getAccessToken(baseUrl);
|
|
1217
|
-
} });
|
|
1218
|
-
return {
|
|
1219
|
-
middleware,
|
|
1220
|
-
rotate,
|
|
1221
|
-
renewIfStale,
|
|
1222
|
-
restore,
|
|
1223
|
-
signOut,
|
|
1224
|
-
forget
|
|
1225
|
-
};
|
|
1226
|
-
};
|
|
1227
|
-
//#endregion
|
|
1228
1114
|
//#region src/keboola/bearer/state/factories.ts
|
|
1229
1115
|
/**
|
|
1230
1116
|
* Everything the table constructs: the entries themselves, and the failures reading them produces.
|
|
@@ -1242,10 +1128,17 @@ const authenticatedAuth = (credential) => ({
|
|
|
1242
1128
|
status: "authenticated",
|
|
1243
1129
|
credential
|
|
1244
1130
|
});
|
|
1245
|
-
const
|
|
1131
|
+
const credential = (input) => ({
|
|
1246
1132
|
...input,
|
|
1247
1133
|
issuedAt: Date.now()
|
|
1248
1134
|
});
|
|
1135
|
+
const grant = (credential) => credential.type === "token" ? {
|
|
1136
|
+
type: "token",
|
|
1137
|
+
refreshToken: credential.refreshToken
|
|
1138
|
+
} : {
|
|
1139
|
+
type: "cookie",
|
|
1140
|
+
sessionId: credential.sessionId
|
|
1141
|
+
};
|
|
1249
1142
|
const expiredCredential = (credential) => ({
|
|
1250
1143
|
...credential,
|
|
1251
1144
|
issuedAt: Date.now() - credential.expiresIn * 1e3
|
|
@@ -1254,7 +1147,8 @@ const stack = (baseUrl) => ({
|
|
|
1254
1147
|
baseUrl,
|
|
1255
1148
|
context: "idle",
|
|
1256
1149
|
epoch: 0,
|
|
1257
|
-
auth: anonymousAuth()
|
|
1150
|
+
auth: anonymousAuth(),
|
|
1151
|
+
retained: null
|
|
1258
1152
|
});
|
|
1259
1153
|
const project = (baseUrl, projectId) => ({
|
|
1260
1154
|
id: projectEntryId(baseUrl, projectId),
|
|
@@ -1286,7 +1180,8 @@ const Entry = {
|
|
|
1286
1180
|
anonymousAuth,
|
|
1287
1181
|
restoringAuth,
|
|
1288
1182
|
authenticatedAuth,
|
|
1289
|
-
|
|
1183
|
+
credential,
|
|
1184
|
+
grant,
|
|
1290
1185
|
expiredCredential
|
|
1291
1186
|
};
|
|
1292
1187
|
/**
|
|
@@ -1304,7 +1199,8 @@ const Errors = {
|
|
|
1304
1199
|
notReady: () => new KeboolaError(KeboolaErrorType.NotReady),
|
|
1305
1200
|
alreadyRestoring: (baseUrl) => /* @__PURE__ */ new Error(`Stack "${baseUrl}" is already being restored`),
|
|
1306
1201
|
notRestoring: (baseUrl) => /* @__PURE__ */ new Error(`Stack "${baseUrl}" is not being restored`),
|
|
1307
|
-
|
|
1202
|
+
grantTypeChanged: (from, to) => /* @__PURE__ */ new Error(`A ${from} grant cannot become ${to}`),
|
|
1203
|
+
nothingRetained: (baseUrl) => /* @__PURE__ */ new Error(`Stack "${baseUrl}" retains no credential`),
|
|
1308
1204
|
missingProject: (id) => /* @__PURE__ */ new Error(`No project "${id}"`)
|
|
1309
1205
|
};
|
|
1310
1206
|
const authenticated = (auth) => auth.status === "authenticated" ? Result.success(auth.credential) : Result.failure(Errors.notAuthenticated());
|
|
@@ -1349,25 +1245,37 @@ const createAuth = ({ stacks, projects, expiry }) => {
|
|
|
1349
1245
|
return stacks.set({
|
|
1350
1246
|
...stack,
|
|
1351
1247
|
epoch: stack.epoch + 1,
|
|
1352
|
-
auth: Entry.authenticatedAuth(Entry.
|
|
1248
|
+
auth: Entry.authenticatedAuth(Entry.credential(input)),
|
|
1249
|
+
retained: null
|
|
1353
1250
|
});
|
|
1354
1251
|
});
|
|
1355
|
-
const applyRefresh = (baseUrl, input) => Result.andThen(stacks.requireCredential(baseUrl), (credential) => credential.type !== input.type ? Result.failure(Errors.
|
|
1252
|
+
const applyRefresh = (baseUrl, input) => Result.andThen(stacks.requireCredential(baseUrl), (credential) => credential.type !== input.type ? Result.failure(Errors.grantTypeChanged(credential.type, input.type)) : Result.map(stacks.get(baseUrl), (stack) => stacks.set({
|
|
1356
1253
|
...stack,
|
|
1357
|
-
auth: Entry.authenticatedAuth(Entry.
|
|
1254
|
+
auth: Entry.authenticatedAuth(Entry.credential(input))
|
|
1358
1255
|
})));
|
|
1359
1256
|
const forceExpire = (baseUrl) => Result.andThen(stacks.requireCredential(baseUrl), (credential) => Result.map(stacks.get(baseUrl), (stack) => stacks.set({
|
|
1360
1257
|
...stack,
|
|
1361
1258
|
auth: Entry.authenticatedAuth(Entry.expiredCredential(credential))
|
|
1362
1259
|
})));
|
|
1363
|
-
const signOut = (baseUrl) => Result.map(stacks.get(baseUrl), (stack) => {
|
|
1260
|
+
const signOut = (baseUrl, { retain = false } = {}) => Result.map(stacks.get(baseUrl), (stack) => {
|
|
1364
1261
|
projects.closeAll(baseUrl);
|
|
1262
|
+
const retained = retain ? Result.unwrapOr(Result.map(authenticated(stack.auth), (credential) => ({ grant: Entry.grant(credential) })), stack.retained) : null;
|
|
1365
1263
|
return stacks.set({
|
|
1366
1264
|
...stack,
|
|
1367
1265
|
epoch: stack.epoch + 1,
|
|
1368
|
-
auth: Entry.anonymousAuth()
|
|
1266
|
+
auth: Entry.anonymousAuth(),
|
|
1267
|
+
retained
|
|
1369
1268
|
});
|
|
1370
1269
|
});
|
|
1270
|
+
const retain = (baseUrl, retained) => Result.map(stacks.get(baseUrl), (stack) => stacks.set({
|
|
1271
|
+
...stack,
|
|
1272
|
+
retained
|
|
1273
|
+
}));
|
|
1274
|
+
const dropRetained = (baseUrl) => Result.map(stacks.get(baseUrl), (stack) => stacks.set({
|
|
1275
|
+
...stack,
|
|
1276
|
+
retained: null
|
|
1277
|
+
}));
|
|
1278
|
+
const requireRetained = (baseUrl) => Result.andThen(stacks.get(baseUrl), (stack) => stack.retained ? Result.success(stack.retained) : Result.failure(Errors.nothingRetained(baseUrl)));
|
|
1371
1279
|
const getEpoch = (baseUrl) => Result.map(stacks.get(baseUrl), (stack) => stack.epoch);
|
|
1372
1280
|
const getAccessToken = (baseUrl) => Result.unwrapOr(Result.map(stacks.requireCredential(baseUrl), ({ accessToken }) => accessToken), null);
|
|
1373
1281
|
return {
|
|
@@ -1377,6 +1285,9 @@ const createAuth = ({ stacks, projects, expiry }) => {
|
|
|
1377
1285
|
applyRefresh,
|
|
1378
1286
|
forceExpire,
|
|
1379
1287
|
signOut,
|
|
1288
|
+
retain,
|
|
1289
|
+
dropRetained,
|
|
1290
|
+
requireRetained,
|
|
1380
1291
|
notifyExpired: expiry.report,
|
|
1381
1292
|
requireCredential: stacks.requireCredential,
|
|
1382
1293
|
getEpoch,
|
|
@@ -1630,6 +1541,204 @@ const createState = (defaultBaseUrl) => {
|
|
|
1630
1541
|
};
|
|
1631
1542
|
};
|
|
1632
1543
|
//#endregion
|
|
1544
|
+
//#region src/keboola/bearer/credentials/renewal.ts
|
|
1545
|
+
const renew = async (client, grant) => {
|
|
1546
|
+
if (grant.type === "cookie") {
|
|
1547
|
+
const { accessToken, expiresIn, sessionId } = await client.token.refreshWithSession({ sessionId: grant.sessionId });
|
|
1548
|
+
return {
|
|
1549
|
+
type: "cookie",
|
|
1550
|
+
accessToken,
|
|
1551
|
+
expiresIn,
|
|
1552
|
+
sessionId
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
const { accessToken, expiresIn, refreshToken } = await client.token.refreshWithToken({ refreshToken: grant.refreshToken });
|
|
1556
|
+
if (!refreshToken) throw new KeboolaError(KeboolaErrorType.NotAuthenticated);
|
|
1557
|
+
return {
|
|
1558
|
+
type: "token",
|
|
1559
|
+
accessToken,
|
|
1560
|
+
expiresIn,
|
|
1561
|
+
refreshToken
|
|
1562
|
+
};
|
|
1563
|
+
};
|
|
1564
|
+
//#endregion
|
|
1565
|
+
//#region src/keboola/bearer/credentials/credentials.ts
|
|
1566
|
+
const DEFAULT_REFRESH_THRESHOLD = .9;
|
|
1567
|
+
const signInEnded = () => new KeboolaError(KeboolaErrorType.SignInEnded);
|
|
1568
|
+
const toRestoreStatus = (outcome) => {
|
|
1569
|
+
if (outcome === void 0 || outcome === "skipped") return "empty";
|
|
1570
|
+
if (outcome === "refused") return "expired";
|
|
1571
|
+
return outcome;
|
|
1572
|
+
};
|
|
1573
|
+
const createCredentials = ({ state, persistor, middlewares, refreshThreshold = DEFAULT_REFRESH_THRESHOLD, onSignedOut, onExpired }) => {
|
|
1574
|
+
const rotationMap = /* @__PURE__ */ new Map();
|
|
1575
|
+
const generations = /* @__PURE__ */ new Map();
|
|
1576
|
+
const generationOf = (baseUrl) => generations.get(baseUrl) ?? 0;
|
|
1577
|
+
const refresh = async (baseUrl, grant) => {
|
|
1578
|
+
const client = createAuthClient({
|
|
1579
|
+
baseUrl,
|
|
1580
|
+
middlewares
|
|
1581
|
+
});
|
|
1582
|
+
const epochBefore = Result.unwrap(state.auth.getEpoch(baseUrl));
|
|
1583
|
+
const generationBefore = generationOf(baseUrl);
|
|
1584
|
+
const refreshed = await Result.tryCatchAsync(() => renew(client, grant));
|
|
1585
|
+
return Result.unwrapOr(state.auth.getEpoch(baseUrl), -1) === epochBefore && generationOf(baseUrl) === generationBefore ? refreshed : Result.failure(signInEnded());
|
|
1586
|
+
};
|
|
1587
|
+
/**
|
|
1588
|
+
* A stack's teardown, from the credential's side.
|
|
1589
|
+
*
|
|
1590
|
+
* - Bumps the generation, so an in-flight rotation can no longer write.
|
|
1591
|
+
* - Drops the deduped entry, so nothing joins that rotation.
|
|
1592
|
+
*/
|
|
1593
|
+
const forget = (baseUrl) => {
|
|
1594
|
+
generations.set(baseUrl, generationOf(baseUrl) + 1);
|
|
1595
|
+
rotationMap.delete(baseUrl);
|
|
1596
|
+
};
|
|
1597
|
+
/**
|
|
1598
|
+
* The rotation, and the one place a credential is declared dead.
|
|
1599
|
+
*
|
|
1600
|
+
* - Renews by the credential's grant: the refresh token, or the session id with the cookie.
|
|
1601
|
+
* - A refused refresh token or session is unambiguous.
|
|
1602
|
+
* - The triggering 401 is not (an unreachable project answers the same), so never sign out on a replay.
|
|
1603
|
+
*/
|
|
1604
|
+
const getGrantForRotation = async (store, baseUrl, credential) => {
|
|
1605
|
+
const epochBefore = Result.unwrap(state.auth.getEpoch(baseUrl));
|
|
1606
|
+
const generationBefore = generationOf(baseUrl);
|
|
1607
|
+
const hydrated = await Result.tryCatchAsync(() => store.read());
|
|
1608
|
+
if (!hydrated.success) return hydrated;
|
|
1609
|
+
if (Result.unwrapOr(state.auth.getEpoch(baseUrl), -1) !== epochBefore || generationOf(baseUrl) !== generationBefore) return Result.failure(signInEnded());
|
|
1610
|
+
const persistedStack = hydrated.data.stacks.find((stack) => stack.baseUrl === baseUrl);
|
|
1611
|
+
if (persistedStack && persistedStack.credential === null) return Result.failure(signInEnded());
|
|
1612
|
+
return Result.success(persistedStack?.credential ?? Entry.grant(credential));
|
|
1613
|
+
};
|
|
1614
|
+
const rotateOnce = async (baseUrl) => persistor.locked(async (store) => {
|
|
1615
|
+
const credential = state.auth.requireCredential(baseUrl);
|
|
1616
|
+
if (!credential.success) return credential;
|
|
1617
|
+
const grant = await getGrantForRotation(store, baseUrl, credential.data);
|
|
1618
|
+
if (!grant.success) return grant;
|
|
1619
|
+
const refreshed = await refresh(baseUrl, grant.data);
|
|
1620
|
+
if (!refreshed.success) {
|
|
1621
|
+
if (isUnauthorized(refreshed.error)) await expire(baseUrl, store);
|
|
1622
|
+
return refreshed;
|
|
1623
|
+
}
|
|
1624
|
+
const accessToken = Result.map(state.auth.applyRefresh(baseUrl, refreshed.data), () => refreshed.data.accessToken);
|
|
1625
|
+
await store.persistStack(baseUrl, state.store.get());
|
|
1626
|
+
return accessToken;
|
|
1627
|
+
});
|
|
1628
|
+
const rotate = (baseUrl) => ensure(rotationMap, baseUrl, () => dedupe(() => rotateOnce(baseUrl)))();
|
|
1629
|
+
const restoreStack = async (baseUrl, grant, retained = false) => persistor.locked(async (store) => {
|
|
1630
|
+
const storedStack = (await store.read()).stacks.find((stack) => stack.baseUrl === baseUrl);
|
|
1631
|
+
const latestGrant = retained ? storedStack?.retained?.grant : storedStack?.credential;
|
|
1632
|
+
if (storedStack && !latestGrant) return "skipped";
|
|
1633
|
+
if (!state.auth.startRestore(baseUrl).success) return "unreachable";
|
|
1634
|
+
const refreshed = await refresh(baseUrl, latestGrant ?? grant);
|
|
1635
|
+
if (!refreshed.success) {
|
|
1636
|
+
state.auth.cancelRestore(baseUrl);
|
|
1637
|
+
if (isUnauthorized(refreshed.error)) {
|
|
1638
|
+
if (retained) state.auth.dropRetained(baseUrl);
|
|
1639
|
+
await store.persistStack(baseUrl, state.store.get());
|
|
1640
|
+
return "refused";
|
|
1641
|
+
}
|
|
1642
|
+
return "unreachable";
|
|
1643
|
+
}
|
|
1644
|
+
state.auth.authenticate(baseUrl, refreshed.data);
|
|
1645
|
+
if (!state.auth.requireCredential(baseUrl).success) return "unreachable";
|
|
1646
|
+
if (retained) state.auth.dropRetained(baseUrl);
|
|
1647
|
+
await store.persistStack(baseUrl, state.store.get());
|
|
1648
|
+
return "restored";
|
|
1649
|
+
});
|
|
1650
|
+
const restoreProjects = (baseUrl, projects) => {
|
|
1651
|
+
for (const { projectId } of projects) state.projects.open(baseUrl, projectId);
|
|
1652
|
+
};
|
|
1653
|
+
/**
|
|
1654
|
+
* Every persisted stack back into the table, with whatever credential it can hand back.
|
|
1655
|
+
*
|
|
1656
|
+
* - Never writes the scope. `lastActive` is what was scoped when the session was stored, for the
|
|
1657
|
+
* caller to select.
|
|
1658
|
+
* - `status` reports what became of `lastActive`'s credential; the client reads it to decide
|
|
1659
|
+
* when persistence may start.
|
|
1660
|
+
*/
|
|
1661
|
+
const restore = async () => {
|
|
1662
|
+
const hydrated = await persistor.locked((store) => store.read()).catch((error) => {
|
|
1663
|
+
console.warn("createCredentials: the stored session could not be read", error);
|
|
1664
|
+
return null;
|
|
1665
|
+
});
|
|
1666
|
+
if (hydrated === null) return {
|
|
1667
|
+
lastActive: null,
|
|
1668
|
+
status: "unreachable"
|
|
1669
|
+
};
|
|
1670
|
+
const { stacks, current } = hydrated;
|
|
1671
|
+
const scoped = stacks.find(({ baseUrl }) => baseUrl === current?.baseUrl);
|
|
1672
|
+
const restored = stacks.map(async ({ baseUrl, credential, retained, projects }) => {
|
|
1673
|
+
state.stacks.ensure(baseUrl);
|
|
1674
|
+
if (!credential && !retained) return "unreachable";
|
|
1675
|
+
if (Result.unwrapOr(state.auth.getEpoch(baseUrl), 0) > 0) return "skipped";
|
|
1676
|
+
if (retained) state.auth.retain(baseUrl, retained);
|
|
1677
|
+
if (!credential) return "unreachable";
|
|
1678
|
+
const outcome = await restoreStack(baseUrl, credential);
|
|
1679
|
+
if (outcome === "restored") restoreProjects(baseUrl, projects);
|
|
1680
|
+
return outcome;
|
|
1681
|
+
});
|
|
1682
|
+
const results = await Promise.all(restored);
|
|
1683
|
+
const scopedOutcome = scoped?.credential ? results[stacks.indexOf(scoped)] : void 0;
|
|
1684
|
+
return {
|
|
1685
|
+
lastActive: current,
|
|
1686
|
+
status: toRestoreStatus(scopedOutcome)
|
|
1687
|
+
};
|
|
1688
|
+
};
|
|
1689
|
+
/**
|
|
1690
|
+
* Signs a retained stack back in from the grant it kept.
|
|
1691
|
+
*
|
|
1692
|
+
* - `restored` and `refused` empty the slot; `unreachable` keeps it for another try.
|
|
1693
|
+
* - Throws when the stack retains nothing.
|
|
1694
|
+
*/
|
|
1695
|
+
const restoreRetained = async (baseUrl) => {
|
|
1696
|
+
const { grant } = Result.unwrap(state.auth.requireRetained(baseUrl));
|
|
1697
|
+
return restoreStack(baseUrl, grant, true);
|
|
1698
|
+
};
|
|
1699
|
+
const isStale = (baseUrl) => {
|
|
1700
|
+
const ageing = Result.map(state.auth.requireCredential(baseUrl), ({ issuedAt, expiresIn }) => Date.now() >= issuedAt + expiresIn * 1e3 * refreshThreshold);
|
|
1701
|
+
return Result.unwrapOr(ageing, false);
|
|
1702
|
+
};
|
|
1703
|
+
/**
|
|
1704
|
+
* Drops the slot so the next sign-in's requests don't join the dying rotation.
|
|
1705
|
+
*
|
|
1706
|
+
* - Writes nothing: the caller persists the stack, under the lock it holds or takes.
|
|
1707
|
+
*/
|
|
1708
|
+
const signOut = (baseUrl, options) => {
|
|
1709
|
+
rotationMap.delete(baseUrl);
|
|
1710
|
+
const signedOut = state.auth.signOut(baseUrl, options);
|
|
1711
|
+
onSignedOut?.(baseUrl);
|
|
1712
|
+
return signedOut;
|
|
1713
|
+
};
|
|
1714
|
+
const expire = async (baseUrl, store) => {
|
|
1715
|
+
if (!state.auth.notifyExpired(baseUrl)) return;
|
|
1716
|
+
signOut(baseUrl);
|
|
1717
|
+
await store.persistStack(baseUrl, state.store.get());
|
|
1718
|
+
onExpired?.(baseUrl);
|
|
1719
|
+
};
|
|
1720
|
+
const renewIfStale = async (baseUrl) => {
|
|
1721
|
+
if (isStale(baseUrl)) await rotate(baseUrl);
|
|
1722
|
+
};
|
|
1723
|
+
const middleware = (baseUrl) => createBearerAuthMiddleware({ getAccessToken: async ({ forceRefresh = false } = {}) => {
|
|
1724
|
+
if (forceRefresh) {
|
|
1725
|
+
if (!state.auth.requireCredential(baseUrl).success) return null;
|
|
1726
|
+
return Result.unwrap(await rotate(baseUrl));
|
|
1727
|
+
}
|
|
1728
|
+
await renewIfStale(baseUrl);
|
|
1729
|
+
return state.auth.getAccessToken(baseUrl);
|
|
1730
|
+
} });
|
|
1731
|
+
return {
|
|
1732
|
+
middleware,
|
|
1733
|
+
rotate,
|
|
1734
|
+
renewIfStale,
|
|
1735
|
+
restore,
|
|
1736
|
+
restoreRetained,
|
|
1737
|
+
signOut,
|
|
1738
|
+
forget
|
|
1739
|
+
};
|
|
1740
|
+
};
|
|
1741
|
+
//#endregion
|
|
1633
1742
|
//#region src/keboola/bearer/context/resource.ts
|
|
1634
1743
|
/**
|
|
1635
1744
|
* Owns fetching one async value per key — a caller names what it needs and never orchestrates the
|
|
@@ -1946,14 +2055,16 @@ const createPerProject = ({ state, credentials, middlewareFor, stack, clientServ
|
|
|
1946
2055
|
*/
|
|
1947
2056
|
const SESSION_STORAGE_KEY = "keboola:session";
|
|
1948
2057
|
/**
|
|
1949
|
-
* What survives a reload, per
|
|
2058
|
+
* What survives a reload, per grant type.
|
|
2059
|
+
*
|
|
2060
|
+
* - Written under `credential`: the key every blob already stored carries.
|
|
1950
2061
|
*
|
|
1951
2062
|
* - `token`: the refresh token. It rotates, is single-use and is server-revocable, so a leaked
|
|
1952
2063
|
* snapshot has limited and revocable value. The access token is never written.
|
|
1953
2064
|
* - `cookie`: the session id. The session cookie is the durable half and the browser keeps it;
|
|
1954
2065
|
* the id alone renews nothing.
|
|
1955
2066
|
*/
|
|
1956
|
-
const
|
|
2067
|
+
const persistedGrantSchema = z$1.discriminatedUnion("type", [z$1.object({
|
|
1957
2068
|
type: z$1.literal("token"),
|
|
1958
2069
|
refreshToken: z$1.string()
|
|
1959
2070
|
}), z$1.object({
|
|
@@ -1962,32 +2073,68 @@ const persistedCredentialSchema = z$1.discriminatedUnion("type", [z$1.object({
|
|
|
1962
2073
|
})]);
|
|
1963
2074
|
/** A record per project rather than a bare id, so a project can grow a field without a migration. */
|
|
1964
2075
|
const persistedProjectSchema = z$1.object({ projectId: z$1.number() });
|
|
2076
|
+
const persistedStackSchema = z$1.object({
|
|
2077
|
+
baseUrl: z$1.string(),
|
|
2078
|
+
credential: persistedGrantSchema.nullable().catch(null),
|
|
2079
|
+
retained: z$1.object({ grant: persistedGrantSchema }).nullable().default(null).catch(null),
|
|
2080
|
+
projects: z$1.array(persistedProjectSchema)
|
|
2081
|
+
});
|
|
1965
2082
|
const persistedSessionSchema = z$1.object({
|
|
1966
2083
|
current: z$1.object({
|
|
1967
2084
|
baseUrl: z$1.string(),
|
|
1968
2085
|
projectId: z$1.number().nullable()
|
|
1969
2086
|
}).nullable(),
|
|
1970
|
-
stacks: z$1.array(
|
|
1971
|
-
baseUrl: z$1.string(),
|
|
1972
|
-
credential: persistedCredentialSchema.nullable().catch(null),
|
|
1973
|
-
projects: z$1.array(persistedProjectSchema)
|
|
1974
|
-
}))
|
|
2087
|
+
stacks: z$1.array(persistedStackSchema)
|
|
1975
2088
|
});
|
|
1976
2089
|
const EMPTY_PERSISTED_SESSION = {
|
|
1977
2090
|
current: null,
|
|
1978
2091
|
stacks: []
|
|
1979
2092
|
};
|
|
1980
|
-
const
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2093
|
+
const projectsOf = (projects, baseUrl) => Object.values(projects).filter((project) => project.baseUrl === baseUrl).map(({ projectId }) => ({ projectId }));
|
|
2094
|
+
const grantsOf = (stack) => ({
|
|
2095
|
+
credential: stack.auth.status === "authenticated" ? Entry.grant(stack.auth.credential) : null,
|
|
2096
|
+
retained: stack.retained
|
|
2097
|
+
});
|
|
2098
|
+
/**
|
|
2099
|
+
* The stored session, rewritten from the table except for the grants.
|
|
2100
|
+
*
|
|
2101
|
+
* - Scope, stack list and open projects come from memory.
|
|
2102
|
+
* - `credential` and `retained` stay as stored: a grant another document rotated must not be put
|
|
2103
|
+
* back by a snapshot of this one's older table.
|
|
2104
|
+
*/
|
|
2105
|
+
const mergeSnapshot = (stored, { active, stacks, projects }) => ({
|
|
2106
|
+
current: {
|
|
2107
|
+
baseUrl: active.baseUrl,
|
|
2108
|
+
projectId: active.projectId
|
|
2109
|
+
},
|
|
2110
|
+
stacks: Object.values(stacks).map(({ baseUrl }) => {
|
|
2111
|
+
const kept = stored.stacks.find((stack) => stack.baseUrl === baseUrl);
|
|
2112
|
+
return {
|
|
2113
|
+
baseUrl,
|
|
2114
|
+
credential: kept?.credential ?? null,
|
|
2115
|
+
retained: kept?.retained ?? null,
|
|
2116
|
+
projects: projectsOf(projects, baseUrl)
|
|
2117
|
+
};
|
|
2118
|
+
})
|
|
2119
|
+
});
|
|
2120
|
+
const upsertStack = (stored, baseUrl, update) => {
|
|
2121
|
+
const index = stored.stacks.findIndex((stack) => stack.baseUrl === baseUrl);
|
|
2122
|
+
const stacks = [...stored.stacks];
|
|
2123
|
+
if (index < 0) stacks.push(update(void 0));
|
|
2124
|
+
else stacks[index] = update(stacks[index]);
|
|
2125
|
+
return {
|
|
2126
|
+
...stored,
|
|
2127
|
+
stacks
|
|
1989
2128
|
};
|
|
1990
2129
|
};
|
|
2130
|
+
/**
|
|
2131
|
+
* The stored session, reached in two ways.
|
|
2132
|
+
*
|
|
2133
|
+
* - `locked`: the only way to read, and the only way to a grant write. Rotation and restore hold
|
|
2134
|
+
* it across the refresh; sign-in, sign-out and the boot restore open it for one step.
|
|
2135
|
+
* - `snapshot`: the table minus its grants, under the lock, coalesced; what the store subscription
|
|
2136
|
+
* feeds, and what a scope change awaits before the document leaves.
|
|
2137
|
+
*/
|
|
1991
2138
|
const createSessionPersistor = (storage) => {
|
|
1992
2139
|
const persistor = createPersistor({
|
|
1993
2140
|
storage,
|
|
@@ -1995,20 +2142,35 @@ const createSessionPersistor = (storage) => {
|
|
|
1995
2142
|
schema: persistedSessionSchema,
|
|
1996
2143
|
defaultValue: EMPTY_PERSISTED_SESSION
|
|
1997
2144
|
});
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2145
|
+
const persistStack = (cell, baseUrl, { stacks, projects }) => {
|
|
2146
|
+
const stack = stacks[baseUrl];
|
|
2147
|
+
if (stack === void 0) return Promise.resolve();
|
|
2148
|
+
return cell.modify((stored) => upsertStack(stored, baseUrl, (existing) => ({
|
|
2149
|
+
baseUrl,
|
|
2150
|
+
...grantsOf(stack),
|
|
2151
|
+
projects: existing?.projects ?? projectsOf(projects, baseUrl)
|
|
2152
|
+
})));
|
|
2153
|
+
};
|
|
2154
|
+
const locked = (task) => persistor.locked((cell) => task({
|
|
2155
|
+
read: cell.read,
|
|
2156
|
+
persistStack: (baseUrl, state) => persistStack(cell, baseUrl, state)
|
|
2157
|
+
}));
|
|
2158
|
+
let latest = null;
|
|
2159
|
+
let pending = null;
|
|
2160
|
+
const snapshot = (state) => {
|
|
2161
|
+
latest = state;
|
|
2162
|
+
if (pending) return pending;
|
|
2163
|
+
const write = persistor.locked((cell) => {
|
|
2164
|
+
pending = null;
|
|
2165
|
+
const table = latest ?? state;
|
|
2166
|
+
return cell.modify((stored) => mergeSnapshot(stored, table));
|
|
2167
|
+
});
|
|
2168
|
+
pending = write;
|
|
2169
|
+
return write;
|
|
2170
|
+
};
|
|
2009
2171
|
return {
|
|
2010
|
-
|
|
2011
|
-
|
|
2172
|
+
locked,
|
|
2173
|
+
snapshot
|
|
2012
2174
|
};
|
|
2013
2175
|
};
|
|
2014
2176
|
//#endregion
|
|
@@ -2126,15 +2288,22 @@ const createKeboola = ({ defaultBaseUrl, storage, middlewares, clientServiceUrls
|
|
|
2126
2288
|
await credentials.renewIfStale(project.baseUrl);
|
|
2127
2289
|
return headersFor(Result.unwrap(state.projects.get(project.id)));
|
|
2128
2290
|
};
|
|
2129
|
-
const
|
|
2130
|
-
|
|
2131
|
-
if (input.type !== "token") return Result.unwrap(state.auth.authenticate(stack.baseUrl, input));
|
|
2291
|
+
const toCredential = (input) => {
|
|
2292
|
+
if (input.type !== "token") return input;
|
|
2132
2293
|
const { refreshToken } = input;
|
|
2133
2294
|
if (!refreshToken) throw new KeboolaError(KeboolaErrorType.NotAuthenticated);
|
|
2134
|
-
return
|
|
2295
|
+
return {
|
|
2135
2296
|
...input,
|
|
2136
2297
|
refreshToken
|
|
2137
|
-
}
|
|
2298
|
+
};
|
|
2299
|
+
};
|
|
2300
|
+
const authenticate = (input) => {
|
|
2301
|
+
const { baseUrl } = state.scope.getActiveStack();
|
|
2302
|
+
const signedIn = Result.unwrap(state.auth.authenticate(baseUrl, toCredential(input)));
|
|
2303
|
+
persistor.locked((store) => store.persistStack(baseUrl, state.store.get())).catch((error) => {
|
|
2304
|
+
console.warn("createKeboola: the sign-in could not be stored", error);
|
|
2305
|
+
});
|
|
2306
|
+
return signedIn;
|
|
2138
2307
|
};
|
|
2139
2308
|
/**
|
|
2140
2309
|
* The flat product surface: `auth` and `management` per stack, the rest per project.
|
|
@@ -2174,11 +2343,21 @@ const createKeboola = ({ defaultBaseUrl, storage, middlewares, clientServiceUrls
|
|
|
2174
2343
|
Result.unwrapOr(state.projects.open(baseUrl, projectId), null);
|
|
2175
2344
|
return perProject.get(project).api;
|
|
2176
2345
|
};
|
|
2177
|
-
/**
|
|
2178
|
-
|
|
2346
|
+
/**
|
|
2347
|
+
* The scope's sign-in, or a named stack's — and everything that sign-in derived.
|
|
2348
|
+
*
|
|
2349
|
+
* - `retain` keeps the grant on the stack, persisted beside the sign-in it ended, for
|
|
2350
|
+
* `restoreRetained`; the next sign-in on the stack replaces it.
|
|
2351
|
+
* - The table is signed out on return; the promise resolves once that is stored, so a caller
|
|
2352
|
+
* leaving the document waits for it.
|
|
2353
|
+
*/
|
|
2354
|
+
const signOut = ({ baseUrl, ...options } = {}) => {
|
|
2179
2355
|
const target = requireStackUrl(baseUrl);
|
|
2180
|
-
|
|
2356
|
+
const signedOut = Result.unwrap(credentials.signOut(target, options));
|
|
2357
|
+
return persistor.locked((store) => store.persistStack(target, state.store.get())).then(() => signedOut);
|
|
2181
2358
|
};
|
|
2359
|
+
/** Signs a stack back in from what a retained sign-out kept; `unreachable` leaves it to retry. */
|
|
2360
|
+
const restoreRetained = (baseUrl) => credentials.restoreRetained(normalizeBaseUrl(baseUrl));
|
|
2182
2361
|
/**
|
|
2183
2362
|
* `input` replaces the active stack's sign-in, whatever it holds.
|
|
2184
2363
|
*
|
|
@@ -2215,16 +2394,22 @@ const createKeboola = ({ defaultBaseUrl, storage, middlewares, clientServiceUrls
|
|
|
2215
2394
|
/**
|
|
2216
2395
|
* Persistence starts only once the restore has settled.
|
|
2217
2396
|
*
|
|
2218
|
-
* - Mid-hydration an unexchanged stack is `anonymous`;
|
|
2397
|
+
* - Mid-hydration an unexchanged stack is `anonymous`; the persistor would erase the
|
|
2219
2398
|
* refresh token the exchange is about to spend.
|
|
2220
2399
|
* - Writes the settled table once: the subscription fires only on the next change.
|
|
2221
2400
|
*/
|
|
2222
2401
|
const enablePersistence = () => {
|
|
2223
2402
|
if (persisting) return;
|
|
2224
2403
|
persisting = true;
|
|
2225
|
-
|
|
2226
|
-
state.store.subscribe(
|
|
2404
|
+
snapshot(state.store.get());
|
|
2405
|
+
state.store.subscribe(snapshot);
|
|
2406
|
+
};
|
|
2407
|
+
const snapshot = (table) => {
|
|
2408
|
+
persistor.snapshot(table).catch((error) => {
|
|
2409
|
+
console.warn("createKeboola: the session could not be stored", error);
|
|
2410
|
+
});
|
|
2227
2411
|
};
|
|
2412
|
+
const persistScope = () => persisting ? persistor.snapshot(state.store.get()) : Promise.resolve();
|
|
2228
2413
|
/**
|
|
2229
2414
|
* The same, deferred until a sign-in.
|
|
2230
2415
|
*
|
|
@@ -2278,14 +2463,22 @@ const createKeboola = ({ defaultBaseUrl, storage, middlewares, clientServiceUrls
|
|
|
2278
2463
|
resume,
|
|
2279
2464
|
stack: {
|
|
2280
2465
|
getActive: getActiveStack,
|
|
2281
|
-
|
|
2466
|
+
/** Scoped on return; resolves once that is stored, for a caller leaving the document. */
|
|
2467
|
+
select: byCaller((baseUrl) => {
|
|
2468
|
+
const stack = selectStack(baseUrl);
|
|
2469
|
+
return persistScope().then(() => stack);
|
|
2470
|
+
}),
|
|
2282
2471
|
close: closeStack,
|
|
2283
2472
|
retryContext: perStack.context.retry,
|
|
2284
2473
|
getContext: (baseUrl) => perStack.context.get(requireStackUrl(baseUrl)),
|
|
2285
2474
|
getContextAsync: (baseUrl) => perStack.context.getAsync(requireStackUrl(baseUrl))
|
|
2286
2475
|
},
|
|
2287
2476
|
project: {
|
|
2288
|
-
|
|
2477
|
+
/** Scoped on return; resolves once that is stored, for a caller leaving the document. */
|
|
2478
|
+
select: byCaller((projectId) => {
|
|
2479
|
+
const project = selectProject(projectId);
|
|
2480
|
+
return persistScope().then(() => project);
|
|
2481
|
+
}),
|
|
2289
2482
|
close: closeProject,
|
|
2290
2483
|
deactivate: state.scope.deactivate,
|
|
2291
2484
|
retryContext: perProject.context.retry,
|
|
@@ -2296,6 +2489,7 @@ const createKeboola = ({ defaultBaseUrl, storage, middlewares, clientServiceUrls
|
|
|
2296
2489
|
authenticate: byCaller(authenticate),
|
|
2297
2490
|
replace: byCaller(replace),
|
|
2298
2491
|
signOut: byCaller(signOut),
|
|
2492
|
+
restoreRetained: byCaller(restoreRetained),
|
|
2299
2493
|
/** Whether the active stack holds a credential — `restoring` is not one yet. */
|
|
2300
2494
|
isAuthenticated,
|
|
2301
2495
|
isAuthenticatedAsync: () => resume().then(isAuthenticated),
|
|
@@ -2489,6 +2683,6 @@ const createAdminAccount = ({ managementToken }) => {
|
|
|
2489
2683
|
};
|
|
2490
2684
|
};
|
|
2491
2685
|
//#endregion
|
|
2492
|
-
export { ApiError, HtmlResponseError, HttpContentType, HttpHeader, KeboolaError, KeboolaErrorType, KeboolaHttpHeader, ManagementClientAuthError, ManagementSessionMintError, QueryJobError, QueueJobError, Result, SESSION_STORAGE_KEY, ServiceUnavailableError, StorageJobError, SyncActionError, UserError, ValidationError, asError, assert, coalesce, collectByCursor, collectByOffset, concurrent, createAdminAccount, createDerivedAsyncStore, createDerivedStore, createEmitter, createGenericFetchClient, createKeboola, createLegacyKeboola, createLocalStorage, createLoggingMiddleware, createMemoryStorage, createNullStorage, createPersistor, createPollRegistry, createQueryServiceSdk, createRetryMiddleware, createSessionStorage, createStore, createUiVersionMiddleware, dedupe, deepMerge, delay, emitter, ensure, failureOf, formatValidationIssues, generateUUID, isAbortError, isApiError, isEmptyDeep, isFetchClientError, isHtmlResponseError, isKeboolaError, isManagementClientAuthError, isManagementSessionMintError, isPlainObject, isQueryJobError, isQueueJobError, isStorageJobError, isStorageTokenMutatingRequest, isSyncActionError, isTimeoutError, isValidationError, jobStatus, keboolaUID, lazy, nextCursorOf, parseLogLines, parseOrThrow, poller, readableReason, schemaGuidedMerge, series, shallowEqual };
|
|
2686
|
+
export { ApiError, HtmlResponseError, HttpContentType, HttpHeader, KeboolaError, KeboolaErrorType, KeboolaHttpHeader, ManagementClientAuthError, ManagementSessionMintError, QueryJobError, QueueJobError, Result, SESSION_STORAGE_KEY, ServiceUnavailableError, StorageJobError, SyncActionError, UserError, ValidationError, asError, assert, coalesce, collectByCursor, collectByOffset, concurrent, createAdminAccount, createDerivedAsyncStore, createDerivedStore, createEmitter, createGenericFetchClient, createKeboola, createLegacyKeboola, createLocalStorage, createLoggingMiddleware, createMemoryStorage, createNullStorage, createPersistor, createPollRegistry, createQueryServiceSdk, createRetryMiddleware, createSessionStorage, createStore, createUiVersionMiddleware, dedupe, deepMerge, delay, emitter, ensure, failureOf, formatValidationIssues, generateUUID, isAbortError, isApiError, isEmptyDeep, isFetchClientError, isHtmlResponseError, isKeboolaError, isManagementClientAuthError, isManagementSessionMintError, isPlainObject, isQueryJobError, isQueueJobError, isStorageJobError, isStorageTokenMutatingRequest, isSyncActionError, isTimeoutError, isValidationError, jobStatus, keboolaUID, lazy, nextCursorOf, parseLogLines, parseOrThrow, poller, queueSeries, readableReason, schemaGuidedMerge, series, shallowEqual };
|
|
2493
2687
|
|
|
2494
2688
|
//# sourceMappingURL=index.js.map
|