chore: update cloudly dependency stack

Align Cloudly with the current typedserver, smartconfig, smartstate, and Docker tooling releases so builds and Docker output stay compatible with the upgraded stack.
This commit is contained in:
2026-05-08 13:56:20 +00:00
parent 80226c8a1c
commit f40ef6b7c0
75 changed files with 4003 additions and 6406 deletions
+60 -61
View File
@@ -66,37 +66,32 @@ export class CloudlyRegistryManager {
}
public async handleHttpRequest(
req: plugins.typedserver.Request,
res: plugins.typedserver.Response,
) {
ctx: plugins.typedserver.IRequestContext,
): Promise<Response> {
try {
const requestUrl = new URL((req as any).originalUrl || req.url || '/', 'http://localhost');
const requestUrl = ctx.url;
if (requestUrl.pathname === '/v2/token') {
await this.handleTokenRequest(req, res, requestUrl);
return;
return await this.handleTokenRequest(ctx, requestUrl);
}
if (!this.started) {
res.status(503);
res.end('registry is not ready');
return;
return new Response('registry is not ready', { status: 503 });
}
const rawBody = await this.getRawBody(req);
const rawBody = Buffer.from(await ctx.request.arrayBuffer());
const response = await this.smartRegistry.handleRequest({
method: req.method || 'GET',
method: ctx.method || 'GET',
path: requestUrl.pathname,
query: Object.fromEntries(requestUrl.searchParams),
headers: this.headersToRecord(req.headers),
headers: this.headersToRecord(ctx.headers),
rawBody: rawBody.length > 0 ? rawBody : undefined,
});
await this.sendRegistryResponse(res, response);
return this.createRegistryResponse(response);
} catch (error) {
logger.log('error', `registry request failed: ${(error as Error).message}`);
res.status(500);
res.end('registry request failed');
return new Response('registry request failed', { status: 500 });
}
}
@@ -259,16 +254,17 @@ export class CloudlyRegistryManager {
}
private async handleTokenRequest(
req: plugins.typedserver.Request,
res: plugins.typedserver.Response,
ctx: plugins.typedserver.IRequestContext,
requestUrl: URL,
) {
const user = await this.authenticateRequest(req);
): Promise<Response> {
const user = await this.authenticateRequest(ctx);
if (!user) {
res.status(401);
res.setHeader('WWW-Authenticate', 'Basic realm="Cloudly Registry"');
res.end('authentication required');
return;
return new Response('authentication required', {
status: 401,
headers: {
'WWW-Authenticate': 'Basic realm="Cloudly Registry"',
},
});
}
const requestedScopes = this.getRequestedOciScopes(requestUrl.searchParams);
@@ -277,9 +273,7 @@ export class CloudlyRegistryManager {
return action === 'push' || action === 'delete';
});
if (requestedWriteAccess && !user.canWrite) {
res.status(403);
res.end('registry write access denied');
return;
return new Response('registry write access denied', { status: 403 });
}
const token = await this.smartRegistry.getAuthManager().createOciToken(
@@ -287,22 +281,26 @@ export class CloudlyRegistryManager {
requestedScopes,
3600,
);
res.status(200);
res.setHeader('Content-Type', 'application/json');
res.end(
return new Response(
JSON.stringify({
token,
access_token: token,
expires_in: 3600,
issued_at: new Date().toISOString(),
}),
{
status: 200,
headers: {
'Content-Type': 'application/json',
},
},
);
}
private async authenticateRequest(
req: plugins.typedserver.Request,
ctx: plugins.typedserver.IRequestContext,
): Promise<TAuthenticatedRegistryUser | null> {
const credentials = this.getBasicCredentials(req);
const credentials = this.getBasicCredentials(ctx);
if (!credentials) {
return null;
}
@@ -332,8 +330,8 @@ export class CloudlyRegistryManager {
return null;
}
private getBasicCredentials(req: plugins.typedserver.Request) {
const authHeader = req.headers.authorization;
private getBasicCredentials(ctx: plugins.typedserver.IRequestContext) {
const authHeader = ctx.headers.get('authorization');
if (!authHeader?.startsWith('Basic ')) {
return null;
}
@@ -370,48 +368,49 @@ export class CloudlyRegistryManager {
return `${this.cloudlyRef.config.data.sslMode === 'none' ? 'http' : 'https'}://${this.getRegistryHost()}`;
}
private headersToRecord(headersArg: plugins.typedserver.Request['headers']) {
return Object.fromEntries(
Object.entries(headersArg).map(([key, value]) => [
key.toLowerCase(),
Array.isArray(value) ? value.join(', ') : value || '',
]),
);
private headersToRecord(headersArg: Headers) {
const headers: Record<string, string> = {};
headersArg.forEach((value, key) => {
headers[key.toLowerCase()] = value;
});
return headers;
}
private async getRawBody(req: plugins.typedserver.Request) {
const chunks: Buffer[] = [];
for await (const chunk of req as any) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
return Buffer.concat(chunks);
}
private async sendRegistryResponse(
res: plugins.typedserver.Response,
private createRegistryResponse(
responseArg: plugins.smartregistry.IResponse,
) {
res.status(responseArg.status);
): Response {
const headers = new Headers();
for (const [key, value] of Object.entries(responseArg.headers)) {
res.setHeader(key, value);
headers.set(key, value);
}
if (!responseArg.body) {
res.end();
return;
return new Response(null, {
status: responseArg.status,
headers,
});
}
if (responseArg.body instanceof ReadableStream) {
plugins.stream.Readable.fromWeb(responseArg.body as any).pipe(res);
return;
return new Response(responseArg.body, {
status: responseArg.status,
headers,
});
}
if (Buffer.isBuffer(responseArg.body) || typeof responseArg.body === 'string') {
res.end(responseArg.body);
return;
return new Response(responseArg.body as BodyInit, {
status: responseArg.status,
headers,
});
}
res.setHeader('Content-Type', responseArg.headers['Content-Type'] || 'application/json');
res.end(JSON.stringify(responseArg.body));
if (!headers.has('Content-Type')) {
headers.set('Content-Type', 'application/json');
}
return new Response(JSON.stringify(responseArg.body), {
status: responseArg.status,
headers,
});
}
}