Skip to content
Closed
24 changes: 24 additions & 0 deletions packages/api-client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,30 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

# [27.32.0](https://github.com/wireapp/wire-web-packages/compare/@wireapp/api-client@27.31.0...@wireapp/api-client@27.32.0) (2025-03-26)

### Features

* update feature config and POST /conversations payload for channels [WPB-15758] ([#6991](https://github.com/wireapp/wire-web-packages/issues/6991)) ([025f02e](https://github.com/wireapp/wire-web-packages/commit/025f02ecd47c0a28cbec24f1f41002c38dbaefda))

# [27.31.0](https://github.com/wireapp/wire-web-packages/compare/@wireapp/api-client@27.30.0...@wireapp/api-client@27.31.0) (2025-03-25)

### Features

* **api-client/cells:** add "offset" and "limit" configuration ([#6990](https://github.com/wireapp/wire-web-packages/issues/6990)) ([d7ed523](https://github.com/wireapp/wire-web-packages/commit/d7ed5231a1322d8da500b0a009e4e07ff2ba47ef))

# [27.30.0](https://github.com/wireapp/wire-web-packages/compare/@wireapp/api-client@27.29.1...@wireapp/api-client@27.30.0) (2025-03-24)

### Features

* Update verify domain registration api path ([#6989](https://github.com/wireapp/wire-web-packages/issues/6989)) ([65277e4](https://github.com/wireapp/wire-web-packages/commit/65277e456b9f32a06b8714f998981742a29d6fec))

## [27.29.1](https://github.com/wireapp/wire-web-packages/compare/@wireapp/api-client@27.29.0...@wireapp/api-client@27.29.1) (2025-03-20)

### Bug Fixes

* **api-client/cells:** single cells initialization ([#6988](https://github.com/wireapp/wire-web-packages/issues/6988)) ([52ff551](https://github.com/wireapp/wire-web-packages/commit/52ff55162cc65d5d8df1c7e66e961611e80ddd5d))

# [27.29.0](https://github.com/wireapp/wire-web-packages/compare/@wireapp/api-client@27.28.0...@wireapp/api-client@27.29.0) (2025-03-20)

### Features
Expand Down
2 changes: 1 addition & 1 deletion packages/api-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,6 @@
"watch": "webpack serve --config webpack.browser.js",
"prepare": "yarn dist"
},
"version": "27.29.0",
"version": "27.32.0",
"gitHead": "5339f01fe01ef0871da8c8bc8662fbe9e604754a"
}
14 changes: 10 additions & 4 deletions packages/api-client/src/APIClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export class APIClient extends EventEmitter {

// APIs
public api: Apis;
private cellsApi: CellsAPI | null = null;

// Configuration
private readonly accessTokenStore: AccessTokenStore;
Expand Down Expand Up @@ -208,16 +209,21 @@ export class APIClient extends EventEmitter {

const assetAPI = new AssetAPI(this.transport.http, backendFeatures);

// Prevents the CellsAPI from being initialized multiple times
if (!this.cellsApi) {
this.cellsApi = new CellsAPI({
httpClientConfig: this.config,
accessTokenStore: this.accessTokenStore,
});
}

return {
account: new AccountAPI(this.transport.http),
asset: assetAPI,
auth: new AuthAPI(this.transport.http),
services: new ServicesAPI(this.transport.http, assetAPI),
broadcast: new BroadcastAPI(this.transport.http),
cells: new CellsAPI({
httpClientConfig: this.config,
accessTokenStore: this.accessTokenStore,
}),
cells: this.cellsApi,
client: new ClientAPI(this.transport.http),
connection: new ConnectionAPI(this.transport.http),
conversation: new ConversationAPI(this.transport.http, backendFeatures),
Expand Down
127 changes: 120 additions & 7 deletions packages/api-client/src/cells/CellsAPI.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,6 @@ describe('CellsAPI', () => {
describe('getAllFiles', () => {
it('retrieves all files with the correct parameters', async () => {
const mockCollection: Partial<RestNodeCollection> = {
// Use appropriate properties based on the actual RestNodeCollection interface
Nodes: [
{Path: '/file1.txt', Uuid: 'uuid1'},
{Path: '/file2.txt', Uuid: 'uuid2'},
Expand All @@ -315,7 +314,55 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Locators: {Many: [{Path: `${TEST_FILE_PATH}/*`}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockCollection);
});

it('uses default values when limit and offset are not provided', async () => {
const mockCollection: Partial<RestNodeCollection> = {
Nodes: [
{Path: '/file1.txt', Uuid: 'uuid1'},
{Path: '/file2.txt', Uuid: 'uuid2'},
],
};

mockNodeServiceApi.lookup.mockResolvedValueOnce(createMockResponse(mockCollection as RestNodeCollection));

const result = await cellsAPI.getAllFiles({path: TEST_FILE_PATH});

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Locators: {Many: [{Path: `${TEST_FILE_PATH}/*`}]},
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockCollection);
});

it('respects custom limit and offset parameters', async () => {
const mockCollection: Partial<RestNodeCollection> = {
Nodes: [
{Path: '/file1.txt', Uuid: 'uuid1'},
{Path: '/file2.txt', Uuid: 'uuid2'},
],
};

mockNodeServiceApi.lookup.mockResolvedValueOnce(createMockResponse(mockCollection as RestNodeCollection));

const result = await cellsAPI.getAllFiles({
path: TEST_FILE_PATH,
limit: 5,
offset: 10,
});

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Locators: {Many: [{Path: `${TEST_FILE_PATH}/*`}]},
Flags: ['WithPreSignedURLs'],
Limit: '5',
Offset: '10',
});
expect(result).toEqual(mockCollection);
});
Expand Down Expand Up @@ -500,7 +547,7 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Locators: {Many: [{Path: filePath}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
});
expect(result).toEqual(mockNode);
});
Expand Down Expand Up @@ -543,7 +590,7 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Locators: {Many: [{Uuid: fileUuid}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
});
expect(result).toEqual(mockNode);
});
Expand Down Expand Up @@ -750,7 +797,69 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Query: {FileName: searchPhrase, Type: 'LEAF'},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockResponse);
});

it('uses default values when limit and offset are not provided', async () => {
const searchPhrase = 'test';
const mockResponse: RestNodeCollection = {
Nodes: [
{
Path: '/test.txt',
Uuid: 'file-uuid-1',
},
{
Path: '/folder/test-file.txt',
Uuid: 'file-uuid-2',
},
],
} as RestNodeCollection;

mockNodeServiceApi.lookup.mockResolvedValueOnce(createMockResponse(mockResponse));

const result = await cellsAPI.searchFiles({phrase: searchPhrase});

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Query: {FileName: searchPhrase, Type: 'LEAF'},
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockResponse);
});

it('respects custom limit and offset parameters', async () => {
const searchPhrase = 'test';
const mockResponse: RestNodeCollection = {
Nodes: [
{
Path: '/test.txt',
Uuid: 'file-uuid-1',
},
{
Path: '/folder/test-file.txt',
Uuid: 'file-uuid-2',
},
],
} as RestNodeCollection;

mockNodeServiceApi.lookup.mockResolvedValueOnce(createMockResponse(mockResponse));

const result = await cellsAPI.searchFiles({
phrase: searchPhrase,
limit: 5,
offset: 10,
});

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Query: {FileName: searchPhrase, Type: 'LEAF'},
Flags: ['WithPreSignedURLs'],
Limit: '5',
Offset: '10',
});
expect(result).toEqual(mockResponse);
});
Expand All @@ -767,7 +876,9 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Query: {FileName: searchPhrase, Type: 'LEAF'},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockResponse);
});
Expand All @@ -793,7 +904,9 @@ describe('CellsAPI', () => {

expect(mockNodeServiceApi.lookup).toHaveBeenCalledWith({
Query: {FileName: searchPhrase, Type: 'LEAF'},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: '10',
Offset: '0',
});
expect(result).toEqual(mockResponse);
});
Expand Down
36 changes: 29 additions & 7 deletions packages/api-client/src/cells/CellsAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import {S3Service} from './CellsStorage/S3Service';
import {AccessTokenStore} from '../auth';
import {HttpClient} from '../http';

const CONFIGURATION_ERROR = 'CellsAPI is not configured. Call configure() before using any methods.';
const CONFIGURATION_ERROR = 'CellsAPI is not initialized. Call initialize() before using any methods.';
const DEFAULT_LIMIT = 10;
const DEFAULT_OFFSET = 0;

interface CellsConfig {
pydio: {
Expand Down Expand Up @@ -171,7 +173,7 @@ export class CellsAPI {

const result = await this.client.lookup({
Locators: {Many: [{Path: path}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
});

const node = result.data.Nodes?.[0];
Expand All @@ -190,7 +192,7 @@ export class CellsAPI {

const result = await this.client.lookup({
Locators: {Many: [{Uuid: uuid}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
});

const node = result.data.Nodes?.[0];
Expand Down Expand Up @@ -222,27 +224,47 @@ export class CellsAPI {
return result.data;
}

async getAllFiles({path}: {path: string}): Promise<RestNodeCollection> {
async getAllFiles({
path,
limit = DEFAULT_LIMIT,
offset = DEFAULT_OFFSET,
}: {
path: string;
limit?: number;
offset?: number;
}): Promise<RestNodeCollection> {
if (!this.client || !this.storageService) {
throw new Error(CONFIGURATION_ERROR);
}

const result = await this.client.lookup({
Locators: {Many: [{Path: `${path}/*`}]},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: `${limit}`,
Offset: `${offset}`,
});

return result.data;
}

async searchFiles({phrase}: {phrase: string}): Promise<RestNodeCollection> {
async searchFiles({
phrase,
limit = DEFAULT_LIMIT,
offset = DEFAULT_OFFSET,
}: {
phrase: string;
limit?: number;
offset?: number;
}): Promise<RestNodeCollection> {
if (!this.client || !this.storageService) {
throw new Error(CONFIGURATION_ERROR);
}

const result = await this.client.lookup({
Query: {FileName: phrase, Type: 'LEAF'},
Flags: ['WithVersionsAll', 'WithPreSignedURLs'],
Flags: ['WithPreSignedURLs'],
Limit: `${limit}`,
Offset: `${offset}`,
});

return result.data;
Expand Down
13 changes: 12 additions & 1 deletion packages/api-client/src/conversation/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ export enum CONVERSATION_ACCESS {
PRIVATE = 'private',
}

export enum GROUP_CONVERSATION_TYPE {
CHANNEL = 'channel',
GROUP_CONVERSATION = 'group_conversation',
}

export enum ADD_PERMISSION {
EVERYONE = 'everyone',
ADMINS = 'admins',
}

type UUID = string;
/**
* A conversation object as returned from the server
Expand All @@ -64,7 +74,8 @@ export interface Conversation {
type: CONVERSATION_TYPE;
creator: UUID;
access: CONVERSATION_ACCESS[];

group_conv_type?: GROUP_CONVERSATION_TYPE;
add_permission?: ADD_PERMISSION;
/** How users can join conversations */
//CONVERSATION_ACCESS_ROLE for api <= v2, ACCESS_ROLE_V2[] since api v3
access_role: CONVERSATION_LEGACY_ACCESS_ROLE | CONVERSATION_ACCESS_ROLE[];
Expand Down
7 changes: 6 additions & 1 deletion packages/api-client/src/conversation/NewConversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ export enum ConversationProtocol {
}

export interface NewConversation
extends Partial<Pick<Conversation, 'access' | 'access_role' | 'access_role_v2' | 'message_timer' | 'name'>> {
extends Partial<
Pick<
Conversation,
'access' | 'access_role' | 'access_role_v2' | 'message_timer' | 'name' | 'group_conv_type' | 'add_permission'
>
> {
conversation_role?: DefaultConversationRoleName;
qualified_users?: QualifiedId[];
receipt_mode: RECEIPT_MODE | null;
Expand Down
Loading
Loading