@keboola/api-client-react 55.0.0 → 57.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 CHANGED
@@ -15,92 +15,42 @@ non-React surfaces. This package is the **only** place that knows about
15
15
 
16
16
  ```ts
17
17
  import {
18
- LegacyAuthProvider,
19
18
  ProjectApiProvider,
20
19
  StackApiProvider,
21
20
  useActiveStack,
22
- useLegacyAuth,
23
21
  useProjectApi,
24
22
  useSessionState,
25
23
  useStackApi,
26
24
  } from '@keboola/api-client-react';
27
25
  ```
28
26
 
29
- Two handles, one per scope, each with its provider and hook:
30
-
31
- - `StackApiProvider` / `useStackApi()` — a `StackApi`: `auth`, `management`, `baseUrl`, `stack`.
32
- What is there before a project — sign-in, the account, the project list.
33
- - `ProjectApiProvider` / `useProjectApi()` — a `ProjectApi`: a `StackApi` plus every project
34
- namespace. It provides its stack too, so `useStackApi()` answers inside a project.
35
- - The verified token and the default branch are the app's to fetch (`api.storage.tokens.verify()`,
36
- `api.storage.branches.getDevBranches()`) and derive with `createProject` / `createBranchRefs`.
37
- - `LegacyAuthProvider` — takes a **legacy** `session` (+ `baseUrl`, `storageToken`, optional
38
- `managementToken`). On mount it drives the session to ready (`setBaseUrl` →
39
- `authenticateManagement?` → `authenticateStorageAsync`) and renders `fallback` until
40
- `session.isStorageReady()`. Exposes the session via `useLegacyAuth()`.
41
- - `useSessionState(session)` / `useActiveStack(session)` — a bearer session's table, and its active
27
+ - `StackApiProvider` / `useStackApi()` — a `StackApi`, what is there before a project.
28
+ - `ProjectApiProvider` / `useProjectApi()` — one project's `ProjectApi`; it provides its stack too.
29
+ - `useSessionState(session)` / `useActiveStack(session)` — the session's table and its active
42
30
  stack, as re-rendering values.
43
31
 
44
- Every hook **throws** outside its provider. Providers are pure pass-throughs: no lifecycle, no
45
- fallback. Mount the stack where the app is signed in and the project where the URL names one:
46
-
47
32
  ```tsx
48
- <StackApiProvider api={keboola.getStackApi()}>
49
- <ProjectApiProvider api={keboola.getProjectApi(projectId)}>{children}</ProjectApiProvider>
33
+ <StackApiProvider api={keboola.stackApi}>
34
+ <ProjectApiProvider api={keboola.projectApi(projectId)}>{children}</ProjectApiProvider>
50
35
  </StackApiProvider>
51
36
  ```
52
37
 
53
- A legacy client is one project: its `api` is a `ProjectApi`, mounted inside `LegacyAuthProvider`:
54
-
55
- ```tsx
56
- <LegacyAuthProvider session={session} baseUrl={url} storageToken={token} fallback={<Loading />}>
57
- <ProjectApiProvider api={api}>{children}</ProjectApiProvider>
58
- </LegacyAuthProvider>
59
- ```
60
-
61
- For credential verification (dev login, project switching) there is no provider —
62
- construct the real per-service client with the candidate host + token and call its
63
- verify: `createStorageClient({ baseUrl, auth: { type: 'sapi-token', token } }).tokens.verify()`, or
64
- `createManagementClient({ baseUrl, auth: { type: 'management-token', token }, withAuthMiddleware: false }).verifyToken()`
65
- (the flag skips the session-managing auth middleware so it's a plain validity check).
38
+ What the handles are and how the client behaves:
39
+ [`@keboola/api-client` → Getting a client](../api-client/AGENTS.md#getting-a-client).
66
40
 
67
41
  ## Conventions
68
42
 
69
- - The context values are typed `StackApi | null` and `ProjectApi | null`, and the hooks throw on
70
- null — see [apps/AGENTS.md](../../apps/AGENTS.md) ("State Management" → "Tree-passing"). Don't
71
- soften this to optional types or `??` fallbacks; a missing provider is a programming error.
43
+ - Every hook **throws** outside its provider; providers are pure pass-throughs. Don't soften the
44
+ `null` contexts to optional types or `??` fallbacks — a missing provider is a programming error.
72
45
  - Reach for `useStackApi()` when the code only needs the stack: it then works before a project too.
73
- - React is a **peerDependency** (^19.0.0). Don't import React types from
74
- this package's own deps in consumers.
75
- - `LegacyAuthProvider` drives the session to ready exactly once on mount. Changing its props after
76
- mount is a no-op by design — if you need a new auth context, mount a fresh provider.
77
-
78
- ## Non-component access (loaders, services, module scope)
79
-
80
- `useStackApi()` and `useProjectApi()` are for React components only. A TanStack Router loader, a
81
- module instantiated at import time, or any code running outside the React tree
82
- can't call the hook. Don't reach for the context there — construct a client
83
- directly:
84
-
85
- ```ts
86
- // Single service — the common case
87
- import { createStorageClient } from '@keboola/api-client/storage';
88
-
89
- const storage = createStorageClient({ baseUrl, auth: { type: 'sapi-token', token } });
90
- const tables = await storage.tables.getTables();
91
- ```
92
-
93
- If you need several services from non-component code, create one client at app
94
- bootstrap (`createLegacyKeboola(...)` / `createKeboola(...)`, drive its session to
95
- ready, and export the `api`) and import that instance where needed — rather than
96
- re-creating clients per call. See
97
- [`@keboola/api-client` → Getting a client](../api-client/AGENTS.md#getting-a-client).
46
+ - Outside React (loaders, module scope), import the app's one client instead of a hook — never build
47
+ a second one.
48
+ - React is a **peerDependency** (^19.0.0).
98
49
 
99
50
  ## Canonical consumers
100
51
 
101
- - `apps/kbc-ui/src/scripts/react/layout/AppRouter/components/SessionProviders.tsx` — the
102
- production `StackApiProvider` mount; `login/pages/ProjectPage.tsx` mounts `ProjectApiProvider`
103
- from the URL's project
52
+ - `apps/kbc-ui/src/scripts/app.tsx` — the production `StackApiProvider` mount, around the whole
53
+ app; `login/pages/ProjectPage.tsx` mounts `ProjectApiProvider` from the URL's project
104
54
  - `apps/kbc-ui/src/scripts/modules/sandboxes/queries.ts` — `useProjectApi`
105
55
  inside a TanStack Query hook (the dominant pattern)
106
56
 
@@ -108,7 +58,5 @@ re-creating clients per call. See
108
58
 
109
59
  - **Never** create a parallel React context that wraps another client
110
60
  instance. One client per app, mounted once at the top.
111
- - **Never** drive a legacy `session` manually in a consumer — `LegacyAuthProvider` owns the
112
- drive-to-ready lifecycle.
113
61
  - **Never** import from a deep path (`@keboola/api-client-react/src/...`).
114
62
  The package only exports `src/index.ts`.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @keboola/api-client-react
2
2
 
3
+ ## 57.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - **Breaking:** `createLegacyKeboola` and its session are gone, with no replacement factory. `LegacySession`, `LegacyKeboolaOptions`, `LegacyAuthProvider` and `useLegacyAuth` go with it, as do the `NoManagementToken`, `NoStorageToken`, `MissingProject`, `NotBearer` and `InvalidBuildTransition` error types and the `all` key of `middlewares` — list a middleware under each client it belongs to. `createKeboola` returns `stackApi` in place of `getStackApi()` — the same object, whose reads follow the active stack — and `projectApi(projectId)` in place of `getProjectApi(projectId)`. The `BearerSession` type is `Session`. `createStorageClient` drops its `onRefreshToken` option, and `createDerivedStore`, `createDerivedAsyncStore`, `shallowEqual` and `AsyncState` go: the legacy client was their only user. `Store.dispose`, `Emitter.clear` and the `ReadableStore` type go with them. `ProjectApi.serviceMeta` goes: every entry was available, and a call to a missing service rejects instead. `ProjectFeature.FrontendLogin` goes: nothing reads it. A call to a service the stack does not run rejects with `ServiceUnavailableError` again, not `NotReady`; its `path` and `clientName` are optional. A Storage API token builds the per-service clients it calls (`createStorageClient`, `createOauthClient`, …), each service's URL from `storage.getStackInfo()`; a full `ProjectApi` comes from a `createKeboola` sign-in (UT-5193)
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies:
12
+ - @keboola/api-client@57.0.0
13
+
14
+ ## 56.0.0
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies:
19
+ - @keboola/api-client@56.0.0
20
+
3
21
  ## 55.0.0
4
22
 
5
23
  ### Patch Changes
package/README.md CHANGED
@@ -14,25 +14,18 @@ Peer dependencies: `react ^19.0.0`, `@keboola/api-client`.
14
14
 
15
15
  ## Quick Start
16
16
 
17
- Two handles: a `StackApi` (what is there before a project) and a `ProjectApi` (a stack plus every project namespace). Legacy (SAPI) shown here — its `api` is one project, mounted inside `LegacyAuthProvider`, which drives the `session` to ready and renders `fallback` until then. Bearer mounts `StackApiProvider` with `createKeboola(...).getStackApi()` and `ProjectApiProvider` with `getProjectApi(projectId)`.
18
-
19
17
  ```tsx
20
- import { createLegacyKeboola } from '@keboola/api-client';
21
- import { LegacyAuthProvider, ProjectApiProvider, useProjectApi } from '@keboola/api-client-react';
22
-
23
- const { api, session } = createLegacyKeboola();
24
-
25
- export const App = () => (
26
- <LegacyAuthProvider
27
- session={session}
28
- baseUrl="https://connection.keboola.com"
29
- storageToken="your-storage-token"
30
- fallback={<div>Loading…</div>}
31
- >
32
- <ProjectApiProvider api={api}>
18
+ import { createKeboola } from '@keboola/api-client';
19
+ import { ProjectApiProvider, StackApiProvider, useProjectApi } from '@keboola/api-client-react';
20
+
21
+ const keboola = createKeboola({ defaultBaseUrl: 'https://connection.keboola.com' });
22
+
23
+ export const App = ({ projectId }: { projectId: number }) => (
24
+ <StackApiProvider api={keboola.stackApi}>
25
+ <ProjectApiProvider api={keboola.projectApi(projectId)}>
33
26
  <Tables />
34
27
  </ProjectApiProvider>
35
- </LegacyAuthProvider>
28
+ </StackApiProvider>
36
29
  );
37
30
 
38
31
  const Tables = () => {
@@ -46,7 +39,8 @@ const Tables = () => {
46
39
 
47
40
  - `useProjectApi()` — the provided `ProjectApi` (`auth` + `management` + every project namespace).
48
41
  - `useStackApi()` — the provided `StackApi` (`auth`, `management`, `baseUrl`, `stack`); a `ProjectApiProvider` provides its stack too.
49
- - `useLegacyAuth()` — the legacy `session`; `useSessionState(session)` reads a bearer one.
42
+ - `useSessionState(session)` / `useActiveStack(session)` — a bearer `session`'s table and its
43
+ active stack, as re-rendering values.
50
44
 
51
45
  ## Ownership
52
46
 
package/dist/index.cjs CHANGED
@@ -4,7 +4,6 @@ let react_jsx_runtime = require("react/jsx-runtime");
4
4
  // src/context.ts
5
5
  const MISSING_STACK_API_ERROR = "useStackApi must be used within <StackApiProvider />";
6
6
  const MISSING_PROJECT_API_ERROR = "useProjectApi must be used within <ProjectApiProvider />";
7
- const MISSING_LEGACY_AUTH_ERROR = "useLegacyAuth must be used within <LegacyAuthProvider />";
8
7
  /**
9
8
  * One stack: what is there before a project — signing in, the account, the project list.
10
9
  *
@@ -14,8 +13,6 @@ const StackApiContext = (0, react.createContext)(null);
14
13
  const StackApiContextProvider = StackApiContext;
15
14
  const ProjectApiContext = (0, react.createContext)(null);
16
15
  const ProjectApiContextProvider = ProjectApiContext;
17
- const LegacyAuthContext = (0, react.createContext)(null);
18
- const LegacyAuthContextProvider = LegacyAuthContext;
19
16
  const useStackApi = () => {
20
17
  const api = (0, react.use)(StackApiContext);
21
18
  if (api === null) throw new Error(MISSING_STACK_API_ERROR);
@@ -26,18 +23,8 @@ const useProjectApi = () => {
26
23
  if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);
27
24
  return api;
28
25
  };
29
- /** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */
30
- const useLegacyAuth = () => {
31
- const session = (0, react.use)(LegacyAuthContext);
32
- if (session === null) throw new Error(MISSING_LEGACY_AUTH_ERROR);
33
- return session;
34
- };
35
26
  // src/ProjectApiProvider.tsx
36
- /**
37
- * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.
38
- *
39
- * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.
40
- */
27
+ /** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */
41
28
  const ProjectApiProvider = ({ api, children }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StackApiContextProvider, {
42
29
  value: api,
43
30
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProjectApiContextProvider, {
@@ -57,43 +44,9 @@ const useActiveStack = (session) => (0, react.useSyncExternalStore)(session.subs
57
44
  // src/useSessionState.ts
58
45
  /** The session table as a re-rendering value — the binding every gate and panel reads it through. */
59
46
  const useSessionState = (session) => (0, react.useSyncExternalStore)(session.subscribe, session.getState);
60
- // src/LegacyAuthProvider.tsx
61
- /**
62
- * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to
63
- * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is
64
- * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the
65
- * session via `useLegacyAuth()` and gates `children` behind readiness.
66
- */
67
- const LegacyAuthProvider = ({ session, baseUrl, storageToken, managementToken, fallback = null, errorFallback = fallback, children }) => {
68
- const [storageState, setStorageState] = (0, react.useState)(() => session.debug().storage);
69
- const startedRef = (0, react.useRef)(false);
70
- (0, react.useEffect)(() => {
71
- const unsubscribe = session.subscribe((snapshot) => setStorageState(snapshot.storage));
72
- if (!startedRef.current) {
73
- startedRef.current = true;
74
- session.setBaseUrl(baseUrl);
75
- if (managementToken) session.authenticateManagement(managementToken);
76
- session.authenticateStorageAsync(storageToken).catch((error) => console.error("Keboola session bootstrap failed", error));
77
- }
78
- return unsubscribe;
79
- }, []);
80
- (0, react.useEffect)(() => {
81
- if (storageState === "errored") console.error("Keboola session bootstrap failed: the storage build errored.");
82
- }, [storageState]);
83
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LegacyAuthContextProvider, {
84
- value: session,
85
- children: (() => {
86
- if (storageState === "ready") return children;
87
- if (storageState === "errored") return errorFallback;
88
- return fallback;
89
- })()
90
- });
91
- };
92
- exports.LegacyAuthProvider = LegacyAuthProvider;
93
47
  exports.ProjectApiProvider = ProjectApiProvider;
94
48
  exports.StackApiProvider = StackApiProvider;
95
49
  exports.useActiveStack = useActiveStack;
96
- exports.useLegacyAuth = useLegacyAuth;
97
50
  exports.useProjectApi = useProjectApi;
98
51
  exports.useSessionState = useSessionState;
99
52
  exports.useStackApi = useStackApi;
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["createContext","use","useSyncExternalStore","useSyncExternalStore","useState","useRef"],"sources":["../src/context.ts","../src/ProjectApiProvider.tsx","../src/StackApiProvider.tsx","../src/useActiveStack.ts","../src/useSessionState.ts","../src/LegacyAuthProvider.tsx"],"sourcesContent":["import { createContext, use } from 'react';\n\nimport type { LegacySession, ProjectApi, StackApi } from '@keboola/api-client';\n\nconst MISSING_STACK_API_ERROR = 'useStackApi must be used within <StackApiProvider />';\nconst MISSING_PROJECT_API_ERROR = 'useProjectApi must be used within <ProjectApiProvider />';\nconst MISSING_LEGACY_AUTH_ERROR = 'useLegacyAuth must be used within <LegacyAuthProvider />';\n\n/**\n * One stack: what is there before a project — signing in, the account, the project list.\n *\n * - A `ProjectApiProvider` provides its project's stack here too.\n */\nconst StackApiContext = createContext<StackApi | null>(null);\nexport const StackApiContextProvider = StackApiContext;\n\n// One project, on its stack. Both flows produce the same `ProjectApi`, so consumers never branch on\n// flow.\nconst ProjectApiContext = createContext<ProjectApi | null>(null);\nexport const ProjectApiContextProvider = ProjectApiContext;\n\n// The legacy lifecycle session lives in its own context; the bearer flows read their table through\n// `useSessionState` instead.\nconst LegacyAuthContext = createContext<LegacySession | null>(null);\nexport const LegacyAuthContextProvider = LegacyAuthContext;\n\nexport const useStackApi = () => {\n const api = use(StackApiContext);\n if (api === null) throw new Error(MISSING_STACK_API_ERROR);\n return api;\n};\n\nexport const useProjectApi = () => {\n const api = use(ProjectApiContext);\n if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);\n return api;\n};\n\n/** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */\nexport const useLegacyAuth = () => {\n const session = use(LegacyAuthContext);\n if (session === null) throw new Error(MISSING_LEGACY_AUTH_ERROR);\n return session;\n};\n","import type { ReactNode } from 'react';\n\nimport type { ProjectApi } from '@keboola/api-client';\n\nimport { ProjectApiContextProvider, StackApiContextProvider } from './context';\n\ntype Props = {\n api: ProjectApi;\n children: ReactNode;\n};\n\n/**\n * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.\n *\n * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.\n */\nexport const ProjectApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>\n <ProjectApiContextProvider value={api}>{children}</ProjectApiContextProvider>\n </StackApiContextProvider>\n);\n","import type { ReactNode } from 'react';\n\nimport type { StackApi } from '@keboola/api-client';\n\nimport { StackApiContextProvider } from './context';\n\ntype Props = {\n api: StackApi;\n children: ReactNode;\n};\n\n/** Provides one stack to `useStackApi()`. */\nexport const StackApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>{children}</StackApiContextProvider>\n);\n","import { useSyncExternalStore } from 'react';\n\nimport type { BearerSession } from '@keboola/api-client';\n\n/** The active stack's row as a re-rendering value; the default stack until something selects another. */\nexport const useActiveStack = (session: BearerSession) =>\n useSyncExternalStore(session.subscribe, session.stack.getActive);\n","import { useSyncExternalStore } from 'react';\n\nimport type { BearerSession } from '@keboola/api-client';\n\n/** The session table as a re-rendering value — the binding every gate and panel reads it through. */\nexport const useSessionState = (session: BearerSession) =>\n useSyncExternalStore(session.subscribe, session.getState);\n","import { useEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\n\nimport type { LegacySession } from '@keboola/api-client';\n\nimport { LegacyAuthContextProvider } from './context';\n\ntype Props = {\n session: LegacySession;\n /** Stack base URL. */\n baseUrl: string;\n /** SAPI token — drives the storage build to ready. */\n storageToken: string;\n /** Optional manage-api token — unlocks `api.management`. */\n managementToken?: string;\n /** Rendered until the storage build reaches ready. */\n fallback?: ReactNode;\n /** Rendered when the storage build fails — the stack index could not be read. */\n errorFallback?: ReactNode;\n children: ReactNode;\n};\n\n/**\n * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to\n * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is\n * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the\n * session via `useLegacyAuth()` and gates `children` behind readiness.\n */\nexport const LegacyAuthProvider = ({\n session,\n baseUrl,\n storageToken,\n managementToken,\n fallback = null,\n errorFallback = fallback,\n children,\n}: Props) => {\n // The build state, not just readiness: `errored` and `pending` render differently.\n const [storageState, setStorageState] = useState(() => session.debug().storage);\n // Guards the once-only drive against React StrictMode's double-mounted effect.\n const startedRef = useRef<boolean>(false);\n\n useEffect(() => {\n const unsubscribe = session.subscribe((snapshot) => setStorageState(snapshot.storage));\n\n if (!startedRef.current) {\n startedRef.current = true;\n session.setBaseUrl(baseUrl);\n if (managementToken) session.authenticateManagement(managementToken);\n // Fire-and-forget: `subscribe` moves `storageState` once the build resolves. A failed build\n // resolves rather than rejects, so this catch only covers a synchronous throw.\n void session\n .authenticateStorageAsync(storageToken)\n .catch((error) => console.error('Keboola session bootstrap failed', error));\n }\n\n return unsubscribe;\n // drive to ready only on initial mount\n // oxlint-disable-next-line react/exhaustive-deps\n }, []);\n\n // The only place a failed build is observable — nothing rejects, so without this it is silent.\n useEffect(() => {\n if (storageState === 'errored') {\n console.error('Keboola session bootstrap failed: the storage build errored.');\n }\n }, [storageState]);\n\n const content = (() => {\n if (storageState === 'ready') return children;\n if (storageState === 'errored') return errorFallback;\n return fallback;\n })();\n\n return <LegacyAuthContextProvider value={session}>{content}</LegacyAuthContextProvider>;\n};\n"],"mappings":";;;;AAIA,MAAM,0BAA0B;AAChC,MAAM,4BAA4B;AAClC,MAAM,4BAA4B;;;;;;AAOlC,MAAM,mBAAA,GAAkBA,MAAAA,cAAAA,CAA+B,IAAI;AAC3D,MAAa,0BAA0B;AAIvC,MAAM,qBAAA,GAAoBA,MAAAA,cAAAA,CAAiC,IAAI;AAC/D,MAAa,4BAA4B;AAIzC,MAAM,qBAAA,GAAoBA,MAAAA,cAAAA,CAAoC,IAAI;AAClE,MAAa,4BAA4B;AAEzC,MAAa,oBAAoB;CAC/B,MAAM,OAAA,GAAMC,MAAAA,IAAAA,CAAI,eAAe;CAC/B,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,uBAAuB;CACzD,OAAO;AACT;AAEA,MAAa,sBAAsB;CACjC,MAAM,OAAA,GAAMA,MAAAA,IAAAA,CAAI,iBAAiB;CACjC,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC3D,OAAO;AACT;;AAGA,MAAa,sBAAsB;CACjC,MAAM,WAAA,GAAUA,MAAAA,IAAAA,CAAI,iBAAiB;CACrC,IAAI,YAAY,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC/D,OAAO;AACT;;;;;;;AC3BA,MAAa,sBAAsB,EAAE,KAAK,eACxC,iBAAA,GAAA,kBAAA,IAAA,CAAC,yBAAD;CAAyB,OAAO;CAC9B,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,2BAAD;EAA2B,OAAO;EAAM;CAAoC,CAAA;AACrD,CAAA;;;ACP3B,MAAa,oBAAoB,EAAE,KAAK,eACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,yBAAD;CAAyB,OAAO;CAAM;AAAkC,CAAA;;;ACR1E,MAAa,kBAAkB,aAAA,GAC7BC,MAAAA,qBAAAA,CAAqB,QAAQ,WAAW,QAAQ,MAAM,SAAS;;;ACDjE,MAAa,mBAAmB,aAAA,GAC9BC,MAAAA,qBAAAA,CAAqB,QAAQ,WAAW,QAAQ,QAAQ;;;;;;;;ACsB1D,MAAa,sBAAsB,EACjC,SACA,SACA,cACA,iBACA,WAAW,MACX,gBAAgB,UAChB,eACW;CAEX,MAAM,CAAC,cAAc,oBAAA,GAAmBC,MAAAA,SAAAA,OAAe,QAAQ,MAAM,CAAC,CAAC,OAAO;CAE9E,MAAM,cAAA,GAAaC,MAAAA,OAAAA,CAAgB,KAAK;CAExC,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,cAAc,QAAQ,WAAW,aAAa,gBAAgB,SAAS,OAAO,CAAC;EAErF,IAAI,CAAC,WAAW,SAAS;GACvB,WAAW,UAAU;GACrB,QAAQ,WAAW,OAAO;GAC1B,IAAI,iBAAiB,QAAQ,uBAAuB,eAAe;GAGnE,QACG,yBAAyB,YAAY,CAAC,CACtC,OAAO,UAAU,QAAQ,MAAM,oCAAoC,KAAK,CAAC;EAC9E;EAEA,OAAO;CAGT,GAAG,CAAC,CAAC;CAGL,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,iBAAiB,WACnB,QAAQ,MAAM,8DAA8D;CAEhF,GAAG,CAAC,YAAY,CAAC;CAQjB,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,2BAAD;EAA2B,OAAO;EANlB,iBAAA;GACrB,IAAI,iBAAiB,SAAS,OAAO;GACrC,IAAI,iBAAiB,WAAW,OAAO;GACvC,OAAO;EACT,EAAA,CAEyD;CAA6B,CAAA;AACxF"}
1
+ {"version":3,"file":"index.cjs","names":["createContext","use","useSyncExternalStore","useSyncExternalStore"],"sources":["../src/context.ts","../src/ProjectApiProvider.tsx","../src/StackApiProvider.tsx","../src/useActiveStack.ts","../src/useSessionState.ts"],"sourcesContent":["import { createContext, use } from 'react';\n\nimport type { ProjectApi, StackApi } from '@keboola/api-client';\n\nconst MISSING_STACK_API_ERROR = 'useStackApi must be used within <StackApiProvider />';\nconst MISSING_PROJECT_API_ERROR = 'useProjectApi must be used within <ProjectApiProvider />';\n\n/**\n * One stack: what is there before a project — signing in, the account, the project list.\n *\n * - A `ProjectApiProvider` provides its project's stack here too.\n */\nconst StackApiContext = createContext<StackApi | null>(null);\nexport const StackApiContextProvider = StackApiContext;\n\n// One project, on its stack.\nconst ProjectApiContext = createContext<ProjectApi | null>(null);\nexport const ProjectApiContextProvider = ProjectApiContext;\n\nexport const useStackApi = () => {\n const api = use(StackApiContext);\n if (api === null) throw new Error(MISSING_STACK_API_ERROR);\n return api;\n};\n\nexport const useProjectApi = () => {\n const api = use(ProjectApiContext);\n if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);\n return api;\n};\n","import type { ReactNode } from 'react';\n\nimport type { ProjectApi } from '@keboola/api-client';\n\nimport { ProjectApiContextProvider, StackApiContextProvider } from './context';\n\ntype Props = {\n api: ProjectApi;\n children: ReactNode;\n};\n\n/** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */\nexport const ProjectApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>\n <ProjectApiContextProvider value={api}>{children}</ProjectApiContextProvider>\n </StackApiContextProvider>\n);\n","import type { ReactNode } from 'react';\n\nimport type { StackApi } from '@keboola/api-client';\n\nimport { StackApiContextProvider } from './context';\n\ntype Props = {\n api: StackApi;\n children: ReactNode;\n};\n\n/** Provides one stack to `useStackApi()`. */\nexport const StackApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>{children}</StackApiContextProvider>\n);\n","import { useSyncExternalStore } from 'react';\n\nimport type { Session } from '@keboola/api-client';\n\n/** The active stack's row as a re-rendering value; the default stack until something selects another. */\nexport const useActiveStack = (session: Session) =>\n useSyncExternalStore(session.subscribe, session.stack.getActive);\n","import { useSyncExternalStore } from 'react';\n\nimport type { Session } from '@keboola/api-client';\n\n/** The session table as a re-rendering value — the binding every gate and panel reads it through. */\nexport const useSessionState = (session: Session) =>\n useSyncExternalStore(session.subscribe, session.getState);\n"],"mappings":";;;;AAIA,MAAM,0BAA0B;AAChC,MAAM,4BAA4B;;;;;;AAOlC,MAAM,mBAAA,GAAkBA,MAAAA,cAAAA,CAA+B,IAAI;AAC3D,MAAa,0BAA0B;AAGvC,MAAM,qBAAA,GAAoBA,MAAAA,cAAAA,CAAiC,IAAI;AAC/D,MAAa,4BAA4B;AAEzC,MAAa,oBAAoB;CAC/B,MAAM,OAAA,GAAMC,MAAAA,IAAAA,CAAI,eAAe;CAC/B,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,uBAAuB;CACzD,OAAO;AACT;AAEA,MAAa,sBAAsB;CACjC,MAAM,OAAA,GAAMA,MAAAA,IAAAA,CAAI,iBAAiB;CACjC,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC3D,OAAO;AACT;;;ACjBA,MAAa,sBAAsB,EAAE,KAAK,eACxC,iBAAA,GAAA,kBAAA,IAAA,CAAC,yBAAD;CAAyB,OAAO;CAC9B,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,2BAAD;EAA2B,OAAO;EAAM;CAAoC,CAAA;AACrD,CAAA;;;ACH3B,MAAa,oBAAoB,EAAE,KAAK,eACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,yBAAD;CAAyB,OAAO;CAAM;AAAkC,CAAA;;;ACR1E,MAAa,kBAAkB,aAAA,GAC7BC,MAAAA,qBAAAA,CAAqB,QAAQ,WAAW,QAAQ,MAAM,SAAS;;;ACDjE,MAAa,mBAAmB,aAAA,GAC9BC,MAAAA,qBAAAA,CAAqB,QAAQ,WAAW,QAAQ,QAAQ"}
package/dist/index.d.cts CHANGED
@@ -1,77 +1,22 @@
1
- import { BearerSession, LegacySession, ProjectApi, StackApi } from "@keboola/api-client";
1
+ import { ProjectApi, Session, StackApi } from "@keboola/api-client";
2
2
  import { ReactNode } from "react";
3
3
  declare const useStackApi: () => StackApi;
4
4
  declare const useProjectApi: () => ProjectApi;
5
- /** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */
6
- declare const useLegacyAuth: () => {
7
- setBaseUrl: (baseUrl: string) => void;
8
- isStorageReady: () => boolean;
9
- authenticateStorage: (sapiToken: string) => void;
10
- authenticateStorageAsync: (sapiToken: string) => Promise<void>;
11
- authenticateManagement: (managementToken: string) => void;
12
- subscribe: (listener: (snapshot: {
13
- type: 'Sapi';
14
- config: {
15
- baseUrl: string | null;
16
- sapiToken: string | null;
17
- managementToken: string | null;
18
- };
19
- authReady: boolean;
20
- managementReady: boolean;
21
- storage: import("@keboola/api-client").AsyncState<unknown>['state'];
22
- }) => void) => () => void;
23
- debug: () => {
24
- type: 'Sapi';
25
- config: {
26
- baseUrl: string | null;
27
- sapiToken: string | null;
28
- managementToken: string | null;
29
- };
30
- authReady: boolean;
31
- managementReady: boolean;
32
- storage: import("@keboola/api-client").AsyncState<unknown>['state'];
33
- };
34
- };
35
- type Props$2 = {
5
+ type Props$1 = {
36
6
  api: ProjectApi;
37
7
  children: ReactNode;
38
8
  };
39
- /**
40
- * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.
41
- *
42
- * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.
43
- */
44
- declare const ProjectApiProvider: ({ api, children }: Props$2) => import("react").JSX.Element;
45
- type Props$1 = {
9
+ /** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */
10
+ declare const ProjectApiProvider: ({ api, children }: Props$1) => import("react").JSX.Element;
11
+ type Props = {
46
12
  api: StackApi;
47
13
  children: ReactNode;
48
14
  };
49
15
  /** Provides one stack to `useStackApi()`. */
50
- declare const StackApiProvider: ({ api, children }: Props$1) => import("react").JSX.Element;
16
+ declare const StackApiProvider: ({ api, children }: Props) => import("react").JSX.Element;
51
17
  /** The active stack's row as a re-rendering value; the default stack until something selects another. */
52
- declare const useActiveStack: (session: BearerSession) => import("@keboola/api-client").StackEntry;
18
+ declare const useActiveStack: (session: Session) => import("@keboola/api-client").StackEntry;
53
19
  /** The session table as a re-rendering value — the binding every gate and panel reads it through. */
54
- declare const useSessionState: (session: BearerSession) => import("@keboola/api-client").SessionState;
55
- type Props = {
56
- session: LegacySession;
57
- /** Stack base URL. */
58
- baseUrl: string;
59
- /** SAPI token — drives the storage build to ready. */
60
- storageToken: string;
61
- /** Optional manage-api token — unlocks `api.management`. */
62
- managementToken?: string;
63
- /** Rendered until the storage build reaches ready. */
64
- fallback?: ReactNode;
65
- /** Rendered when the storage build fails — the stack index could not be read. */
66
- errorFallback?: ReactNode;
67
- children: ReactNode;
68
- };
69
- /**
70
- * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to
71
- * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is
72
- * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the
73
- * session via `useLegacyAuth()` and gates `children` behind readiness.
74
- */
75
- declare const LegacyAuthProvider: ({ session, baseUrl, storageToken, managementToken, fallback, errorFallback, children }: Props) => import("react").JSX.Element;
76
- export { LegacyAuthProvider, ProjectApiProvider, StackApiProvider, useActiveStack, useLegacyAuth, useProjectApi, useSessionState, useStackApi };
20
+ declare const useSessionState: (session: Session) => import("@keboola/api-client").SessionState;
21
+ export { ProjectApiProvider, StackApiProvider, useActiveStack, useProjectApi, useSessionState, useStackApi };
77
22
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,77 +1,22 @@
1
1
  import { ReactNode } from "react";
2
- import { BearerSession, LegacySession, ProjectApi, StackApi } from "@keboola/api-client";
2
+ import { ProjectApi, Session, StackApi } from "@keboola/api-client";
3
3
  declare const useStackApi: () => StackApi;
4
4
  declare const useProjectApi: () => ProjectApi;
5
- /** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */
6
- declare const useLegacyAuth: () => {
7
- setBaseUrl: (baseUrl: string) => void;
8
- isStorageReady: () => boolean;
9
- authenticateStorage: (sapiToken: string) => void;
10
- authenticateStorageAsync: (sapiToken: string) => Promise<void>;
11
- authenticateManagement: (managementToken: string) => void;
12
- subscribe: (listener: (snapshot: {
13
- type: 'Sapi';
14
- config: {
15
- baseUrl: string | null;
16
- sapiToken: string | null;
17
- managementToken: string | null;
18
- };
19
- authReady: boolean;
20
- managementReady: boolean;
21
- storage: import("@keboola/api-client").AsyncState<unknown>['state'];
22
- }) => void) => () => void;
23
- debug: () => {
24
- type: 'Sapi';
25
- config: {
26
- baseUrl: string | null;
27
- sapiToken: string | null;
28
- managementToken: string | null;
29
- };
30
- authReady: boolean;
31
- managementReady: boolean;
32
- storage: import("@keboola/api-client").AsyncState<unknown>['state'];
33
- };
34
- };
35
- type Props$2 = {
5
+ type Props$1 = {
36
6
  api: ProjectApi;
37
7
  children: ReactNode;
38
8
  };
39
- /**
40
- * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.
41
- *
42
- * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.
43
- */
44
- declare const ProjectApiProvider: ({ api, children }: Props$2) => import("react").JSX.Element;
45
- type Props$1 = {
9
+ /** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */
10
+ declare const ProjectApiProvider: ({ api, children }: Props$1) => import("react").JSX.Element;
11
+ type Props = {
46
12
  api: StackApi;
47
13
  children: ReactNode;
48
14
  };
49
15
  /** Provides one stack to `useStackApi()`. */
50
- declare const StackApiProvider: ({ api, children }: Props$1) => import("react").JSX.Element;
16
+ declare const StackApiProvider: ({ api, children }: Props) => import("react").JSX.Element;
51
17
  /** The active stack's row as a re-rendering value; the default stack until something selects another. */
52
- declare const useActiveStack: (session: BearerSession) => import("@keboola/api-client").StackEntry;
18
+ declare const useActiveStack: (session: Session) => import("@keboola/api-client").StackEntry;
53
19
  /** The session table as a re-rendering value — the binding every gate and panel reads it through. */
54
- declare const useSessionState: (session: BearerSession) => import("@keboola/api-client").SessionState;
55
- type Props = {
56
- session: LegacySession;
57
- /** Stack base URL. */
58
- baseUrl: string;
59
- /** SAPI token — drives the storage build to ready. */
60
- storageToken: string;
61
- /** Optional manage-api token — unlocks `api.management`. */
62
- managementToken?: string;
63
- /** Rendered until the storage build reaches ready. */
64
- fallback?: ReactNode;
65
- /** Rendered when the storage build fails — the stack index could not be read. */
66
- errorFallback?: ReactNode;
67
- children: ReactNode;
68
- };
69
- /**
70
- * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to
71
- * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is
72
- * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the
73
- * session via `useLegacyAuth()` and gates `children` behind readiness.
74
- */
75
- declare const LegacyAuthProvider: ({ session, baseUrl, storageToken, managementToken, fallback, errorFallback, children }: Props) => import("react").JSX.Element;
76
- export { LegacyAuthProvider, ProjectApiProvider, StackApiProvider, useActiveStack, useLegacyAuth, useProjectApi, useSessionState, useStackApi };
20
+ declare const useSessionState: (session: Session) => import("@keboola/api-client").SessionState;
21
+ export { ProjectApiProvider, StackApiProvider, useActiveStack, useProjectApi, useSessionState, useStackApi };
77
22
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
- import { createContext, use, useEffect, useRef, useState, useSyncExternalStore } from "react";
1
+ import { createContext, use, useSyncExternalStore } from "react";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  // src/context.ts
4
4
  const MISSING_STACK_API_ERROR = "useStackApi must be used within <StackApiProvider />";
5
5
  const MISSING_PROJECT_API_ERROR = "useProjectApi must be used within <ProjectApiProvider />";
6
- const MISSING_LEGACY_AUTH_ERROR = "useLegacyAuth must be used within <LegacyAuthProvider />";
7
6
  /**
8
7
  * One stack: what is there before a project — signing in, the account, the project list.
9
8
  *
@@ -13,8 +12,6 @@ const StackApiContext = createContext(null);
13
12
  const StackApiContextProvider = StackApiContext;
14
13
  const ProjectApiContext = createContext(null);
15
14
  const ProjectApiContextProvider = ProjectApiContext;
16
- const LegacyAuthContext = createContext(null);
17
- const LegacyAuthContextProvider = LegacyAuthContext;
18
15
  const useStackApi = () => {
19
16
  const api = use(StackApiContext);
20
17
  if (api === null) throw new Error(MISSING_STACK_API_ERROR);
@@ -25,18 +22,8 @@ const useProjectApi = () => {
25
22
  if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);
26
23
  return api;
27
24
  };
28
- /** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */
29
- const useLegacyAuth = () => {
30
- const session = use(LegacyAuthContext);
31
- if (session === null) throw new Error(MISSING_LEGACY_AUTH_ERROR);
32
- return session;
33
- };
34
25
  // src/ProjectApiProvider.tsx
35
- /**
36
- * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.
37
- *
38
- * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.
39
- */
26
+ /** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */
40
27
  const ProjectApiProvider = ({ api, children }) => /* @__PURE__ */ jsx(StackApiContextProvider, {
41
28
  value: api,
42
29
  children: /* @__PURE__ */ jsx(ProjectApiContextProvider, {
@@ -56,38 +43,6 @@ const useActiveStack = (session) => useSyncExternalStore(session.subscribe, sess
56
43
  // src/useSessionState.ts
57
44
  /** The session table as a re-rendering value — the binding every gate and panel reads it through. */
58
45
  const useSessionState = (session) => useSyncExternalStore(session.subscribe, session.getState);
59
- // src/LegacyAuthProvider.tsx
60
- /**
61
- * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to
62
- * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is
63
- * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the
64
- * session via `useLegacyAuth()` and gates `children` behind readiness.
65
- */
66
- const LegacyAuthProvider = ({ session, baseUrl, storageToken, managementToken, fallback = null, errorFallback = fallback, children }) => {
67
- const [storageState, setStorageState] = useState(() => session.debug().storage);
68
- const startedRef = useRef(false);
69
- useEffect(() => {
70
- const unsubscribe = session.subscribe((snapshot) => setStorageState(snapshot.storage));
71
- if (!startedRef.current) {
72
- startedRef.current = true;
73
- session.setBaseUrl(baseUrl);
74
- if (managementToken) session.authenticateManagement(managementToken);
75
- session.authenticateStorageAsync(storageToken).catch((error) => console.error("Keboola session bootstrap failed", error));
76
- }
77
- return unsubscribe;
78
- }, []);
79
- useEffect(() => {
80
- if (storageState === "errored") console.error("Keboola session bootstrap failed: the storage build errored.");
81
- }, [storageState]);
82
- return /* @__PURE__ */ jsx(LegacyAuthContextProvider, {
83
- value: session,
84
- children: (() => {
85
- if (storageState === "ready") return children;
86
- if (storageState === "errored") return errorFallback;
87
- return fallback;
88
- })()
89
- });
90
- };
91
- export { LegacyAuthProvider, ProjectApiProvider, StackApiProvider, useActiveStack, useLegacyAuth, useProjectApi, useSessionState, useStackApi };
46
+ export { ProjectApiProvider, StackApiProvider, useActiveStack, useProjectApi, useSessionState, useStackApi };
92
47
 
93
48
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/context.ts","../src/ProjectApiProvider.tsx","../src/StackApiProvider.tsx","../src/useActiveStack.ts","../src/useSessionState.ts","../src/LegacyAuthProvider.tsx"],"sourcesContent":["import { createContext, use } from 'react';\n\nimport type { LegacySession, ProjectApi, StackApi } from '@keboola/api-client';\n\nconst MISSING_STACK_API_ERROR = 'useStackApi must be used within <StackApiProvider />';\nconst MISSING_PROJECT_API_ERROR = 'useProjectApi must be used within <ProjectApiProvider />';\nconst MISSING_LEGACY_AUTH_ERROR = 'useLegacyAuth must be used within <LegacyAuthProvider />';\n\n/**\n * One stack: what is there before a project — signing in, the account, the project list.\n *\n * - A `ProjectApiProvider` provides its project's stack here too.\n */\nconst StackApiContext = createContext<StackApi | null>(null);\nexport const StackApiContextProvider = StackApiContext;\n\n// One project, on its stack. Both flows produce the same `ProjectApi`, so consumers never branch on\n// flow.\nconst ProjectApiContext = createContext<ProjectApi | null>(null);\nexport const ProjectApiContextProvider = ProjectApiContext;\n\n// The legacy lifecycle session lives in its own context; the bearer flows read their table through\n// `useSessionState` instead.\nconst LegacyAuthContext = createContext<LegacySession | null>(null);\nexport const LegacyAuthContextProvider = LegacyAuthContext;\n\nexport const useStackApi = () => {\n const api = use(StackApiContext);\n if (api === null) throw new Error(MISSING_STACK_API_ERROR);\n return api;\n};\n\nexport const useProjectApi = () => {\n const api = use(ProjectApiContext);\n if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);\n return api;\n};\n\n/** The legacy (SAPI) lifecycle session. Throws outside `<LegacyAuthProvider />`. */\nexport const useLegacyAuth = () => {\n const session = use(LegacyAuthContext);\n if (session === null) throw new Error(MISSING_LEGACY_AUTH_ERROR);\n return session;\n};\n","import type { ReactNode } from 'react';\n\nimport type { ProjectApi } from '@keboola/api-client';\n\nimport { ProjectApiContextProvider, StackApiContextProvider } from './context';\n\ntype Props = {\n api: ProjectApi;\n children: ReactNode;\n};\n\n/**\n * Provides one project to `useProjectApi()`, and its stack to `useStackApi()`.\n *\n * - A pure pass-through: the auth lifecycle belongs to the session, or to `LegacyAuthProvider`.\n */\nexport const ProjectApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>\n <ProjectApiContextProvider value={api}>{children}</ProjectApiContextProvider>\n </StackApiContextProvider>\n);\n","import type { ReactNode } from 'react';\n\nimport type { StackApi } from '@keboola/api-client';\n\nimport { StackApiContextProvider } from './context';\n\ntype Props = {\n api: StackApi;\n children: ReactNode;\n};\n\n/** Provides one stack to `useStackApi()`. */\nexport const StackApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>{children}</StackApiContextProvider>\n);\n","import { useSyncExternalStore } from 'react';\n\nimport type { BearerSession } from '@keboola/api-client';\n\n/** The active stack's row as a re-rendering value; the default stack until something selects another. */\nexport const useActiveStack = (session: BearerSession) =>\n useSyncExternalStore(session.subscribe, session.stack.getActive);\n","import { useSyncExternalStore } from 'react';\n\nimport type { BearerSession } from '@keboola/api-client';\n\n/** The session table as a re-rendering value — the binding every gate and panel reads it through. */\nexport const useSessionState = (session: BearerSession) =>\n useSyncExternalStore(session.subscribe, session.getState);\n","import { useEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\n\nimport type { LegacySession } from '@keboola/api-client';\n\nimport { LegacyAuthContextProvider } from './context';\n\ntype Props = {\n session: LegacySession;\n /** Stack base URL. */\n baseUrl: string;\n /** SAPI token — drives the storage build to ready. */\n storageToken: string;\n /** Optional manage-api token — unlocks `api.management`. */\n managementToken?: string;\n /** Rendered until the storage build reaches ready. */\n fallback?: ReactNode;\n /** Rendered when the storage build fails — the stack index could not be read. */\n errorFallback?: ReactNode;\n children: ReactNode;\n};\n\n/**\n * Owns the legacy (SAPI) lifecycle: on mount it configures the stack and drives the session to\n * ready, rendering `fallback` until the storage build resolves. The backend-injected SAPI token is\n * known up front, so this drives itself (unlike the interactive bearer `AuthProvider`). Exposes the\n * session via `useLegacyAuth()` and gates `children` behind readiness.\n */\nexport const LegacyAuthProvider = ({\n session,\n baseUrl,\n storageToken,\n managementToken,\n fallback = null,\n errorFallback = fallback,\n children,\n}: Props) => {\n // The build state, not just readiness: `errored` and `pending` render differently.\n const [storageState, setStorageState] = useState(() => session.debug().storage);\n // Guards the once-only drive against React StrictMode's double-mounted effect.\n const startedRef = useRef<boolean>(false);\n\n useEffect(() => {\n const unsubscribe = session.subscribe((snapshot) => setStorageState(snapshot.storage));\n\n if (!startedRef.current) {\n startedRef.current = true;\n session.setBaseUrl(baseUrl);\n if (managementToken) session.authenticateManagement(managementToken);\n // Fire-and-forget: `subscribe` moves `storageState` once the build resolves. A failed build\n // resolves rather than rejects, so this catch only covers a synchronous throw.\n void session\n .authenticateStorageAsync(storageToken)\n .catch((error) => console.error('Keboola session bootstrap failed', error));\n }\n\n return unsubscribe;\n // drive to ready only on initial mount\n // oxlint-disable-next-line react/exhaustive-deps\n }, []);\n\n // The only place a failed build is observable — nothing rejects, so without this it is silent.\n useEffect(() => {\n if (storageState === 'errored') {\n console.error('Keboola session bootstrap failed: the storage build errored.');\n }\n }, [storageState]);\n\n const content = (() => {\n if (storageState === 'ready') return children;\n if (storageState === 'errored') return errorFallback;\n return fallback;\n })();\n\n return <LegacyAuthContextProvider value={session}>{content}</LegacyAuthContextProvider>;\n};\n"],"mappings":";;;AAIA,MAAM,0BAA0B;AAChC,MAAM,4BAA4B;AAClC,MAAM,4BAA4B;;;;;;AAOlC,MAAM,kBAAkB,cAA+B,IAAI;AAC3D,MAAa,0BAA0B;AAIvC,MAAM,oBAAoB,cAAiC,IAAI;AAC/D,MAAa,4BAA4B;AAIzC,MAAM,oBAAoB,cAAoC,IAAI;AAClE,MAAa,4BAA4B;AAEzC,MAAa,oBAAoB;CAC/B,MAAM,MAAM,IAAI,eAAe;CAC/B,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,uBAAuB;CACzD,OAAO;AACT;AAEA,MAAa,sBAAsB;CACjC,MAAM,MAAM,IAAI,iBAAiB;CACjC,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC3D,OAAO;AACT;;AAGA,MAAa,sBAAsB;CACjC,MAAM,UAAU,IAAI,iBAAiB;CACrC,IAAI,YAAY,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC/D,OAAO;AACT;;;;;;;AC3BA,MAAa,sBAAsB,EAAE,KAAK,eACxC,oBAAC,yBAAD;CAAyB,OAAO;CAC9B,UAAA,oBAAC,2BAAD;EAA2B,OAAO;EAAM;CAAoC,CAAA;AACrD,CAAA;;;ACP3B,MAAa,oBAAoB,EAAE,KAAK,eACtC,oBAAC,yBAAD;CAAyB,OAAO;CAAM;AAAkC,CAAA;;;ACR1E,MAAa,kBAAkB,YAC7B,qBAAqB,QAAQ,WAAW,QAAQ,MAAM,SAAS;;;ACDjE,MAAa,mBAAmB,YAC9B,qBAAqB,QAAQ,WAAW,QAAQ,QAAQ;;;;;;;;ACsB1D,MAAa,sBAAsB,EACjC,SACA,SACA,cACA,iBACA,WAAW,MACX,gBAAgB,UAChB,eACW;CAEX,MAAM,CAAC,cAAc,mBAAmB,eAAe,QAAQ,MAAM,CAAC,CAAC,OAAO;CAE9E,MAAM,aAAa,OAAgB,KAAK;CAExC,gBAAgB;EACd,MAAM,cAAc,QAAQ,WAAW,aAAa,gBAAgB,SAAS,OAAO,CAAC;EAErF,IAAI,CAAC,WAAW,SAAS;GACvB,WAAW,UAAU;GACrB,QAAQ,WAAW,OAAO;GAC1B,IAAI,iBAAiB,QAAQ,uBAAuB,eAAe;GAGnE,QACG,yBAAyB,YAAY,CAAC,CACtC,OAAO,UAAU,QAAQ,MAAM,oCAAoC,KAAK,CAAC;EAC9E;EAEA,OAAO;CAGT,GAAG,CAAC,CAAC;CAGL,gBAAgB;EACd,IAAI,iBAAiB,WACnB,QAAQ,MAAM,8DAA8D;CAEhF,GAAG,CAAC,YAAY,CAAC;CAQjB,OAAO,oBAAC,2BAAD;EAA2B,OAAO;EANlB,iBAAA;GACrB,IAAI,iBAAiB,SAAS,OAAO;GACrC,IAAI,iBAAiB,WAAW,OAAO;GACvC,OAAO;EACT,EAAA,CAEyD;CAA6B,CAAA;AACxF"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/context.ts","../src/ProjectApiProvider.tsx","../src/StackApiProvider.tsx","../src/useActiveStack.ts","../src/useSessionState.ts"],"sourcesContent":["import { createContext, use } from 'react';\n\nimport type { ProjectApi, StackApi } from '@keboola/api-client';\n\nconst MISSING_STACK_API_ERROR = 'useStackApi must be used within <StackApiProvider />';\nconst MISSING_PROJECT_API_ERROR = 'useProjectApi must be used within <ProjectApiProvider />';\n\n/**\n * One stack: what is there before a project — signing in, the account, the project list.\n *\n * - A `ProjectApiProvider` provides its project's stack here too.\n */\nconst StackApiContext = createContext<StackApi | null>(null);\nexport const StackApiContextProvider = StackApiContext;\n\n// One project, on its stack.\nconst ProjectApiContext = createContext<ProjectApi | null>(null);\nexport const ProjectApiContextProvider = ProjectApiContext;\n\nexport const useStackApi = () => {\n const api = use(StackApiContext);\n if (api === null) throw new Error(MISSING_STACK_API_ERROR);\n return api;\n};\n\nexport const useProjectApi = () => {\n const api = use(ProjectApiContext);\n if (api === null) throw new Error(MISSING_PROJECT_API_ERROR);\n return api;\n};\n","import type { ReactNode } from 'react';\n\nimport type { ProjectApi } from '@keboola/api-client';\n\nimport { ProjectApiContextProvider, StackApiContextProvider } from './context';\n\ntype Props = {\n api: ProjectApi;\n children: ReactNode;\n};\n\n/** Provides one project to `useProjectApi()`, and its stack to `useStackApi()`. */\nexport const ProjectApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>\n <ProjectApiContextProvider value={api}>{children}</ProjectApiContextProvider>\n </StackApiContextProvider>\n);\n","import type { ReactNode } from 'react';\n\nimport type { StackApi } from '@keboola/api-client';\n\nimport { StackApiContextProvider } from './context';\n\ntype Props = {\n api: StackApi;\n children: ReactNode;\n};\n\n/** Provides one stack to `useStackApi()`. */\nexport const StackApiProvider = ({ api, children }: Props) => (\n <StackApiContextProvider value={api}>{children}</StackApiContextProvider>\n);\n","import { useSyncExternalStore } from 'react';\n\nimport type { Session } from '@keboola/api-client';\n\n/** The active stack's row as a re-rendering value; the default stack until something selects another. */\nexport const useActiveStack = (session: Session) =>\n useSyncExternalStore(session.subscribe, session.stack.getActive);\n","import { useSyncExternalStore } from 'react';\n\nimport type { Session } from '@keboola/api-client';\n\n/** The session table as a re-rendering value — the binding every gate and panel reads it through. */\nexport const useSessionState = (session: Session) =>\n useSyncExternalStore(session.subscribe, session.getState);\n"],"mappings":";;;AAIA,MAAM,0BAA0B;AAChC,MAAM,4BAA4B;;;;;;AAOlC,MAAM,kBAAkB,cAA+B,IAAI;AAC3D,MAAa,0BAA0B;AAGvC,MAAM,oBAAoB,cAAiC,IAAI;AAC/D,MAAa,4BAA4B;AAEzC,MAAa,oBAAoB;CAC/B,MAAM,MAAM,IAAI,eAAe;CAC/B,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,uBAAuB;CACzD,OAAO;AACT;AAEA,MAAa,sBAAsB;CACjC,MAAM,MAAM,IAAI,iBAAiB;CACjC,IAAI,QAAQ,MAAM,MAAM,IAAI,MAAM,yBAAyB;CAC3D,OAAO;AACT;;;ACjBA,MAAa,sBAAsB,EAAE,KAAK,eACxC,oBAAC,yBAAD;CAAyB,OAAO;CAC9B,UAAA,oBAAC,2BAAD;EAA2B,OAAO;EAAM;CAAoC,CAAA;AACrD,CAAA;;;ACH3B,MAAa,oBAAoB,EAAE,KAAK,eACtC,oBAAC,yBAAD;CAAyB,OAAO;CAAM;AAAkC,CAAA;;;ACR1E,MAAa,kBAAkB,YAC7B,qBAAqB,QAAQ,WAAW,QAAQ,MAAM,SAAS;;;ACDjE,MAAa,mBAAmB,YAC9B,qBAAqB,QAAQ,WAAW,QAAQ,QAAQ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keboola/api-client-react",
3
- "version": "55.0.0",
3
+ "version": "57.0.0",
4
4
  "description": "React bindings for @keboola/api-client",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,13 +50,13 @@
50
50
  }
51
51
  },
52
52
  "peerDependencies": {
53
- "@keboola/api-client": "^55.0.0",
53
+ "@keboola/api-client": "^57.0.0",
54
54
  "react": "^19.0.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@arethetypeswrong/cli": "^0.18.2",
58
- "@keboola/api-client": "^55.0.0",
59
- "@keboola/api-fixtures": "^50.0.0",
58
+ "@keboola/api-client": "^57.0.0",
59
+ "@keboola/api-fixtures": "^52.0.0",
60
60
  "@keboola/eslint-plugin-design": "^0.8.0",
61
61
  "@keboola/oxlint-config": "^10.3.0",
62
62
  "@keboola/tsconfig": "^0.2.1",
@@ -83,7 +83,7 @@
83
83
  "type-check": "tsc",
84
84
  "lint": "pnpm lint:format && pnpm lint:oxlint",
85
85
  "lint:fix": "oxlint --fix . && oxfmt",
86
- "knip:check": "pnpm --dir ../.. exec knip --workspace packages/api-client-react",
86
+ "knip:check": "node ../../scripts/knip-check.mjs",
87
87
  "knip:fix": "pnpm --dir ../.. exec knip --workspace packages/api-client-react --fix-type types,exports,files",
88
88
  "lint:oxlint": "oxlint . --quiet",
89
89
  "lint:format": "oxfmt --check",