Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .storybook/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ export default defineConfig({
apiClient: fileURLToPath(
new URL('../redisinsight/api-client', import.meta.url),
),
'riShared': fileURLToPath(
new URL('../redisinsight/api/src/ri-shared', import.meta.url),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a shared package/dir should not be inside api folder, it would be in redisinsight/ri-shared

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good instinct, and I went down that path — but there's a build constraint that makes a true top-level redisinsight/ri-shared much more involved than a relocation, so I've kept it at api/src/ri-shared for now. Reasoning:

The API actually consumes this util (the array-index validator imports it), so it has to be compiled into the api's dist. The api's tsconfig has no explicit rootDir, so tsc infers it from the common ancestor of all compiled files — today that's src, giving us dist/src/.... The moment a file from ../ri-shared enters the compile, the common ancestor becomes redisinsight/ and tsc emits dist/api/src/main.js + dist/ri-shared/... instead.

That breaks two things that hard-depend on the current layout:

  • node dist/src/main (the start:prod / start:stage boot path)
  • the desktop app's hard-coded api/dist/src/... imports — desktop/src/lib/server/server.ts does import server from '../../../../api/dist/src/main', plus the azure / cloud-auth / window-auth modules

api-client gets to live top-level only because it's UI-consumed and never goes through nest build — ri-shared can't follow that pattern since the API compiles it.

To put it genuinely top-level we'd need to make ri-shared its own independently-built TS unit (project reference + own dist) and wire it into both api runtime resolution and desktop packaging — a real chunk of work + new CI surface for what's currently one small shared util. The api/src/ri-shared folder keeps the "shared, dependency-free, both-sides" boundary explicit (see its README) with zero packaging risk. If we accumulate enough shared code to justify the standalone package later, happy to revisit — flag it if you'd rather take that on now.

),
},
},
server: {
Expand Down
1 change: 1 addition & 0 deletions jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports = {
'uiSrc/(.*)': '<rootDir>/redisinsight/ui/src/$1',
'^apiClient$': '<rootDir>/redisinsight/api-client',
'apiClient/(.*)': '<rootDir>/redisinsight/api-client/$1',
'^riShared/(.*)$': '<rootDir>/redisinsight/api/src/ri-shared/$1',
'@redislabsdev/redis-ui-components': '@redis-ui/components',
'@redislabsdev/redis-ui-styles': '@redis-ui/styles',
'@redislabsdev/redis-ui-icons': '@redis-ui/icons',
Expand Down
2 changes: 1 addition & 1 deletion redisinsight/api/src/common/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './array-index.helper';
export * from '../../ri-shared/utils/array-index';
export * from './certificate-import.util';
export * from './errors.util';
export * from './merge.util';
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import {
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
import {
ARRAY_INDEX_MAX,
parseArrayIndex,
} from 'src/common/utils/array-index.helper';
import { ARRAY_INDEX_MAX, parseArrayIndex } from 'src/common/utils';

@ValidatorConstraint({ name: 'ArrayIndexValidator', async: false })
export class ArrayIndexValidator implements ValidatorConstraintInterface {
Expand Down
33 changes: 33 additions & 0 deletions redisinsight/api/src/ri-shared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ri-shared — code shared across the RedisInsight apps (API + UI)

Modules here are consumed by **both** the API (relative imports, e.g.
`src/ri-shared/utils/array-index`) and the UI (the `riShared/*` path alias). They live
inside `api/src` because the api's production build (`nest build` → `node dist/src/main`)
compiles with `api/src` as the tsc rootDir — sources outside it restructure `dist/` and
break the packaged app. The UI/Storybook/jest aliases simply point into this folder, so
shared code ships with zero extra packaging surface (desktop bundles it like any api file).

## What belongs here

- Cross-boundary **contracts**: value formats both sides must agree on (e.g. the
BigInt-as-string array index format), stable message formats, shared constants.
- Small **dependency-free** utilities needed verbatim on both sides.

## Rules

- **No imports** from Nest, React, ioredis, lodash or anything else — dependency-free
TypeScript only (the UI and API have separate node_modules; nothing here may assume
either).
- **es2019-compatible**: the api compiles this folder with `target: es2019` — no BigInt
literals (`1n` is TS2737; use `BigInt('...')`), no newer syntax.
- API code style (semicolons) — this folder is linted by `yarn lint:api`.
- Tests live next to the module (`*.spec.ts`, runs under the api jest config) and define
the shared behavior once — UI consumers exercise it through their barrel imports.

## Alias wiring (when adding the alias to a new consumer)

`redisinsight/ui/tsconfig.json` + `redisinsight/ui/vite.config.mjs` +
`redisinsight/ui/src/packages/vite.config.mjs` (Workbench plugin builds reach
the `uiSrc/utils` barrel) + `jest.config.cjs` (root, UI tests) +
`.storybook/vite.config.ts` + `redisinsight/desktop/tsconfig.json` all map
`riShared/*` → `redisinsight/api/src/ri-shared/*`.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {
ARRAY_INDEX_MAX,
isValidArrayIndex,
parseArrayIndex,
} from 'src/common/utils';
} from './array-index';

describe('array-index.helper', () => {
describe('shared array-index', () => {
it('should expose max unsigned 64-bit value', () => {
expect(ARRAY_INDEX_MAX).toEqual(BigInt('18446744073709551615'));
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/**
* Redis array indexes are unsigned 64-bit integers (0 … 2^64−1) and exceed
* Number.MAX_SAFE_INTEGER, so they travel as numeric strings end-to-end —
* never parseInt/Number, no JS-side arithmetic on indexes.
* never parseInt/Number, no JS-side arithmetic on indexes (the UI's Redux
* store keeps them as strings too).
*
* Mirrored in redisinsight/ui/src/utils/arrayIndex.ts — keep semantics and
* tests in sync.
* Shared by the UI and the API (see src/ri-shared/README.md): the API
* imports it relatively (it lives in the api compile root, so `nest build`
* emits it into dist like any other api source), the UI through the
* `riShared/*` alias (wired in redisinsight/ui/vite.config.mjs,
* redisinsight/ui/tsconfig.json, .storybook/vite.config.ts and
* jest.config.cjs). It must stay dependency-free and es2019-compatible —
* BigInt('...') calls only, since BigInt literals are a syntax error
* (TS2737) under the api's es2019 target.
*/
// 2^64 - 1; BigInt() call (not a literal) — this tsconfig targets es2019,
// where BigInt literals are a syntax error (TS2737).
// 2^64 - 1
export const ARRAY_INDEX_MAX = BigInt('18446744073709551615');

const ARRAY_INDEX_REGEX = /^\d+$/;
Expand Down
3 changes: 2 additions & 1 deletion redisinsight/desktop/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"apiSrc/*": ["redisinsight/api/src/*"],
"uiSrc/*": ["redisinsight/ui/src/*"],
"apiClient": ["redisinsight/api-client"],
"apiClient/*": ["redisinsight/api-client/*"]
"apiClient/*": ["redisinsight/api-client/*"],
"riShared/*": ["redisinsight/api/src/ri-shared/*"]
}
},
"include": ["**/*"],
Expand Down
3 changes: 3 additions & 0 deletions redisinsight/ui/src/packages/vite.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export default defineConfig({
'@redislabsdev/redis-ui-table': '@redis-ui/table',
uiSrc: fileURLToPath(new URL('../../src', import.meta.url)),
apiClient: fileURLToPath(new URL('../../../api-client', import.meta.url)),
riShared: fileURLToPath(
new URL('../../../api/src/ri-shared', import.meta.url),
),
},
dedupe: ['react', 'react-dom'],
},
Expand Down
44 changes: 0 additions & 44 deletions redisinsight/ui/src/utils/arrayIndex.ts

This file was deleted.

2 changes: 1 addition & 1 deletion redisinsight/ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RouterWithSubRoutes from './routerWithSubRoutes'

export * from './common'
export * from './validations'
export * from './arrayIndex'
export * from 'riShared/utils/array-index'
export * from './statuses'
export * from './instance'
export * from './apiResponse'
Expand Down
53 changes: 0 additions & 53 deletions redisinsight/ui/src/utils/tests/arrayIndex.spec.ts

This file was deleted.

3 changes: 2 additions & 1 deletion redisinsight/ui/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"paths": {
"uiSrc/*": ["src/*"],
"apiClient": ["../api-client"],
"apiClient/*": ["../api-client/*"]
"apiClient/*": ["../api-client/*"],
"riShared/*": ["../api/src/ri-shared/*"]
}
},
"include": [
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/vite.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default defineConfig({
'@redislabsdev/redis-ui-table': '@redis-ui/table',
uiSrc: fileURLToPath(new URL('./src', import.meta.url)),
apiClient: fileURLToPath(new URL('../api-client', import.meta.url)),
'riShared': fileURLToPath(new URL('../api/src/ri-shared', import.meta.url)),
},
},
server: {
Expand Down