@norbix.ai/react-redux 0.1.1 → 1.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/README.md CHANGED
@@ -150,6 +150,7 @@ A *curated* set of hooks for the most common endpoints. Every hook is end-to-end
150
150
  | `useGetApiKeysQuery` | `api.apikeys.getApiKeys` | provides `ApiKey/LIST` |
151
151
  | `useRegenerateApiKeysMutation` | `api.apikeys.regenerateApiKeys` | invalidates `ApiKey/LIST` |
152
152
  | `useGetPublicFileQuery` | `api.files.getPublicFile` | provides `Files/PUBLIC:<publicId>` |
153
+ | `useTestFilesIntegrationApiMutation` | `api.files.testFilesIntegration` | invalidates `Files` + `FilesIntegrations` |
153
154
 
154
155
  ### Hub surface — `norbix.hub.*`
155
156
 
@@ -213,6 +214,31 @@ on the page. `useGetPublicFileQuery` caches under its own
213
214
  making a file private again invalidates `Files`, a different tag, so call
214
215
  `refetch()` if a stale entry would matter to you.
215
216
 
217
+ ## Testing a files integration
218
+
219
+ Two hooks run the same live probe against a files integration — upload a
220
+ small file, read it, list the folder, delete the file — and answer one item
221
+ per step (`UploadFile`, `GetFile`, `GetAllFiles`, `DeleteFile`) with `result`
222
+ `OK`, `FAILED` or `NOT_TESTED`:
223
+
224
+ | Hook | Wraps | Route | Use it from |
225
+ |---|---|---|---|
226
+ | `useTestFilesIntegrationApiMutation` | `api.files.testFilesIntegration` | `POST /{version}/files/{filesIntegrationId}/test` | your app, with an API key or a user session (needs `files:create`) |
227
+ | `useTestFilesIntegrationMutation` | `hub.files.testFilesIntegration` | `POST /{version}/files/integrations/test` | a dashboard, signed in to the Hub |
228
+
229
+ ```tsx
230
+ const [testIntegration, { data, isLoading }] = useTestFilesIntegrationApiMutation();
231
+
232
+ await testIntegration({ filesIntegrationId: 'nbin_1' });
233
+ const failed = data?.items?.filter((i) => i.result !== 'OK');
234
+ ```
235
+
236
+ The API one carries the `Api` suffix because both live in one endpoint map
237
+ (like `useDeleteFileApiMutation`). It invalidates `Files` — the probe writes to
238
+ the storage, and a failed delete step leaves its file behind — and
239
+ `FilesIntegrations`, because the gateway records the last test result on the
240
+ integration.
241
+
216
242
  ## Working with terms
217
243
 
218
244
  A **taxonomy** is a named tree of **terms** (labels). A term can have one parent (a clean hierarchy) or several parents (the same item under many categories). There is one read hook per scenario — pick the one that matches what you want:
@@ -782,6 +808,37 @@ If your app currently calls Norbix via `fetchBaseQuery({ baseUrl })` + a custom
782
808
  4. **Remove** the custom error interceptor — `createNorbixBaseQuery` already maps `NorbixError` to `SerializedNorbixError` with `code`, `status`, `message`, `fieldErrors`. Consume those in your error UI instead.
783
809
  5. **Keep** the same tag taxonomy — the package exports the full set (`Account`, `Projects`, `Regions`, `MembershipUsers`, `DatabaseSchemas`, ... 59 in total), so existing `providesTags` keep working.
784
810
 
811
+ ## Errors
812
+
813
+ A failed call lands in the Redux state as a plain `SerializedNorbixError`:
814
+
815
+ ```ts
816
+ const { error } = useGetFileInfoQuery({ filesIntegrationId, path });
817
+ if (error) {
818
+ // httpStatus / errorCode / errors are the names every Norbix SDK uses.
819
+ // status / code / fieldErrors are the same values, kept for older code.
820
+ console.log(error.httpStatus, error.errorCode, error.message);
821
+ error.errors.forEach((e) => console.log(e.errorCode, e.fieldName, e.message));
822
+ }
823
+ ```
824
+
825
+ The message and the error code are the gateway's own. `@norbix.ai/ts` reads
826
+ them out of `responseStatus.errors[]`, where the gateway puts them, and this
827
+ package copies them into the store unchanged — it does not parse bodies
828
+ itself.
829
+
830
+ ### Breaking change — a refused call now lands as an error
831
+
832
+ The gateway answers a business refusal (an unknown id, a rule that says no)
833
+ with **HTTP 200** and `responseStatus.isSuccess = false`. Until now such an
834
+ answer arrived as `{ data }` and your components rendered it as a success.
835
+ With the fixed `@norbix.ai/ts` it arrives as `{ error }` with `httpStatus` 200
836
+ and the gateway's message and error code.
837
+
838
+ If a component checked `data.responseStatus.isSuccess` itself, read `error`
839
+ instead. This needs `@norbix.ai/ts` **2.0.0 or newer** — the version that
840
+ carries the fix.
841
+
785
842
  ## How it works under the hood
786
843
 
787
844
  `createNorbixApi(getClient)` returns an RTK Query API. Its `baseQuery` is a thin wrapper that calls a closure you pass at endpoint definition time:
package/dist/index.cjs CHANGED
@@ -10,18 +10,27 @@ var jsxRuntime = require('react/jsx-runtime');
10
10
  function serializeNorbixError(err) {
11
11
  if (err && typeof err === "object") {
12
12
  const e = err;
13
+ const status = typeof e.status === "number" ? e.status : typeof e.httpStatus === "number" ? e.httpStatus : 0;
14
+ const code = e.code ?? e.errorCode;
15
+ const list = Array.isArray(e.fieldErrors) ? e.fieldErrors : Array.isArray(e.errors) ? e.errors : [];
13
16
  return {
14
- status: typeof e.status === "number" ? e.status : 0,
15
- code: e.code,
17
+ status,
18
+ httpStatus: status,
19
+ code,
20
+ errorCode: code,
16
21
  message: e.message ?? "Unknown Norbix error",
17
- fieldErrors: Array.isArray(e.fieldErrors) ? e.fieldErrors : [],
22
+ fieldErrors: list,
23
+ errors: list,
18
24
  url: e.url
19
25
  };
20
26
  }
27
+ const message = typeof err === "string" ? err : "Unknown Norbix error";
21
28
  return {
22
29
  status: 0,
23
- message: typeof err === "string" ? err : "Unknown Norbix error",
24
- fieldErrors: []
30
+ httpStatus: 0,
31
+ message,
32
+ fieldErrors: [],
33
+ errors: []
25
34
  };
26
35
  }
27
36
 
@@ -38,9 +47,12 @@ function createNorbixBaseQuery(getClient) {
38
47
  return {
39
48
  error: {
40
49
  status: 0,
50
+ httpStatus: 0,
41
51
  code: "NORBIX_NO_CLIENT",
52
+ errorCode: "NORBIX_NO_CLIENT",
42
53
  message: "No Norbix client available. Did you forget <NorbixProvider>?",
43
- fieldErrors: []
54
+ fieldErrors: [],
55
+ errors: []
44
56
  }
45
57
  };
46
58
  }
@@ -276,6 +288,36 @@ var apiFiles = (b) => ({
276
288
  providesTags: (_res, _err, arg) => [
277
289
  { type: "Files", id: `PUBLIC:${arg?.publicId ?? "unknown"}` }
278
290
  ]
291
+ }),
292
+ /**
293
+ * Runs a live probe against a files integration with the caller's own API
294
+ * key or session: uploads a small file, reads it, lists the folder and
295
+ * deletes the file again. Answers one item per step (`UploadFile`,
296
+ * `GetFile`, `GetAllFiles`, `DeleteFile`) with `result` `OK`, `FAILED` or
297
+ * `NOT_TESTED`, plus the step's `errors`. Needs the `files:create`
298
+ * permission, because the probe writes to the storage.
299
+ *
300
+ * Wraps `api.files.testFilesIntegration`
301
+ * (`POST /{version}/files/{filesIntegrationId}/test`). This is NOT the
302
+ * dashboard endpoint `hub.files.testFilesIntegration`
303
+ * (`POST /{version}/files/integrations/test`), whose hook is
304
+ * `useTestFilesIntegrationMutation`. Both live in one flat endpoint map,
305
+ * so this one carries the `Api` suffix — the same way `deleteFileApi` and
306
+ * `downloadFileApi` do — otherwise the Hub one, spread later, would
307
+ * silently replace it. Hook: `useTestFilesIntegrationApiMutation`.
308
+ *
309
+ * A mutation, like every other write in this file, so its answer is never
310
+ * served from cache. It invalidates:
311
+ * - `Files`, like its write neighbours: the probe uploads and deletes a
312
+ * real file in the storage `listFiles` reads, and if the delete step
313
+ * fails the probe file stays behind;
314
+ * - `FilesIntegrations`: the gateway records the outcome on the
315
+ * integration (last test time, success, errors), which
316
+ * `getFilesIntegration(s)` return.
317
+ */
318
+ testFilesIntegrationApi: b.mutation({
319
+ query: (args) => (norbix) => norbix.api.files.testFilesIntegration(args),
320
+ invalidatesTags: ["Files", "FilesIntegrations"]
279
321
  })
280
322
  });
281
323