Skip to content
Merged
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
5 changes: 3 additions & 2 deletions src/guilds/guilds.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { HttpClient } from '../http/httpClient';
// GuildPass SDK: Pull in package or module bindings.
import { validateGuildId } from '../utils/validation';
import { encodePathSegment } from '../utils/formatting';
// GuildPass SDK: Import external module dependencies.
import { GetGuildParams, Guild, GuildConfig } from './guilds.types';

Expand All @@ -20,7 +21,7 @@ export class GuildsService {
validateGuildId(guildId);

// GuildPass SDK: Send back computed results to the caller.
return this.http.get<Guild>(`/guilds/${guildId}`);
return this.http.get<Guild>(`/guilds/${encodePathSegment(guildId)}`);
// GuildPass SDK: End of logic containment structure block.
}

Expand All @@ -34,7 +35,7 @@ export class GuildsService {
validateGuildId(guildId);

// GuildPass SDK: Return evaluated output value.
return this.http.get<GuildConfig>(`/guilds/${guildId}/config`);
return this.http.get<GuildConfig>(`/guilds/${encodePathSegment(guildId)}/config`);
// GuildPass SDK: End of logic containment structure block.
}
// GuildPass SDK: End of logic containment structure block.
Expand Down
7 changes: 5 additions & 2 deletions src/roles/roles.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { HttpClient } from '../http/httpClient';
// GuildPass SDK: Import external module dependencies.
import { validateAddress, validateGuildId } from '../utils/validation';
import { encodePathSegment } from '../utils/formatting';
// GuildPass SDK: Pull in package or module bindings.
import { GetRolesParams, GetUserRolesParams, GuildRole } from './roles.types';

Expand All @@ -20,7 +21,7 @@ export class RolesService {
validateGuildId(guildId);

// GuildPass SDK: Return evaluated output value.
return this.http.get<GuildRole[]>(`/guilds/${guildId}/roles`);
return this.http.get<GuildRole[]>(`/guilds/${encodePathSegment(guildId)}/roles`);
// GuildPass SDK: End of logic containment structure block.
}

Expand All @@ -36,7 +37,9 @@ export class RolesService {
validateGuildId(guildId);

// GuildPass SDK: Terminate function block execution and return.
return this.http.get<GuildRole[]>(`/guilds/${guildId}/members/${walletAddress}/roles`);
return this.http.get<GuildRole[]>(
`/guilds/${encodePathSegment(guildId)}/members/${encodePathSegment(walletAddress)}/roles`,
);
// GuildPass SDK: End of logic containment structure block.
}
// GuildPass SDK: End of logic containment structure block.
Expand Down
12 changes: 12 additions & 0 deletions src/utils/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ export const capitalise = (str: string): string => {
return str.charAt(0).toUpperCase() + str.slice(1);
// GuildPass SDK: End of logic containment structure block.
};

/**
* Encodes a path segment for safe insertion into URL paths.
*
* @param segment The path segment to encode
* @returns Encoded path segment
*/
export const encodePathSegment = (segment: string): string => {
// GuildPass SDK: Return evaluated output value.
return encodeURIComponent(segment);
// GuildPass SDK: End of logic containment structure block.
};
51 changes: 51 additions & 0 deletions tests/services.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ describe('Service Modules', () => {
expect.any(Object),
);
});

it('should URL-encode guild IDs in role endpoint paths', async () => {
const mockRoles = [{ id: '1', name: 'Role 1' }];
(fetch as any).mockResolvedValue({
ok: true,
status: 200,
json: () => Promise.resolve(mockRoles),
headers: new Headers(),
});

const result = await client.roles.getRoles({ guildId: 'guild/1' });
expect(result).toEqual(mockRoles);
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining('/guilds/guild%2F1/roles'),
expect.any(Object),
);
});

it('should URL-encode wallet addresses and guild IDs in user roles endpoint paths', async () => {
const mockRoles = [{ id: '1', name: 'Role 1' }];
(fetch as any).mockResolvedValue({
ok: true,
status: 200,
json: () => Promise.resolve(mockRoles),
headers: new Headers(),
});

const result = await client.roles.getUserRoles({ guildId: 'guild/1', walletAddress: '0x123/456 space' });
expect(result).toEqual(mockRoles);
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining('/guilds/guild%2F1/members/0x123%2F456%20space/roles'),
expect.any(Object),
);
});
});

describe('GuildsService', () => {
Expand All @@ -84,5 +118,22 @@ describe('Service Modules', () => {
const result = await client.guilds.getGuild({ guildId: 'guild_1' });
expect(result).toEqual(mockGuild);
});

it('should URL-encode guild IDs in guild endpoint paths', async () => {
const mockGuild = { id: 'guild/1', name: 'Encoded Guild' };
(fetch as any).mockResolvedValue({
ok: true,
status: 200,
json: () => Promise.resolve(mockGuild),
headers: new Headers(),
});

const result = await client.guilds.getGuild({ guildId: 'guild/1' });
expect(result).toEqual(mockGuild);
expect(fetch).toHaveBeenCalledWith(
expect.stringContaining('/guilds/guild%2F1'),
expect.any(Object),
);
});
});
});
Loading