feat(opsserver,web): replace the Angular UI and REST management layer with a TypedRequest-based ops server and bundled web frontend

This commit is contained in:
2026-03-20 16:43:44 +00:00
parent 0fc74ff995
commit d4f758ce0f
159 changed files with 12465 additions and 14861 deletions

View File

@@ -50,7 +50,7 @@ export class StackGalleryAuthProvider implements plugins.smartregistry.IAuthProv
* Returns userId on success, null on failure
*/
public async authenticate(
credentials: plugins.smartregistry.ICredentials
credentials: plugins.smartregistry.ICredentials,
): Promise<string | null> {
const result = await this.authService.login(credentials.username, credentials.password);
if (!result.success || !result.user) return null;
@@ -62,7 +62,7 @@ export class StackGalleryAuthProvider implements plugins.smartregistry.IAuthProv
*/
public async validateToken(
token: string,
protocol?: plugins.smartregistry.TRegistryProtocol
protocol?: plugins.smartregistry.TRegistryProtocol,
): Promise<plugins.smartregistry.IAuthToken | null> {
// Try API token (srg_ prefix)
if (token.startsWith('srg_')) {
@@ -70,11 +70,10 @@ export class StackGalleryAuthProvider implements plugins.smartregistry.IAuthProv
if (!result.valid || !result.token || !result.user) return null;
return {
type: (protocol || result.token.protocols[0] || 'npm') as plugins.smartregistry.TRegistryProtocol,
type: (protocol || result.token.protocols[0] ||
'npm') as plugins.smartregistry.TRegistryProtocol,
userId: result.user.id,
scopes: result.token.scopes.map((s) =>
`${s.protocol}:${s.actions.join(',')}`
),
scopes: result.token.scopes.map((s) => `${s.protocol}:${s.actions.join(',')}`),
readonly: !result.token.scopes.some((s) =>
s.actions.includes('write') || s.actions.includes('*')
),
@@ -98,7 +97,7 @@ export class StackGalleryAuthProvider implements plugins.smartregistry.IAuthProv
public async createToken(
userId: string,
protocol: plugins.smartregistry.TRegistryProtocol,
options?: plugins.smartregistry.ITokenOptions
options?: plugins.smartregistry.ITokenOptions,
): Promise<string> {
const result = await this.tokenService.createToken({
userId,
@@ -133,7 +132,7 @@ export class StackGalleryAuthProvider implements plugins.smartregistry.IAuthProv
public async authorize(
token: plugins.smartregistry.IAuthToken | null,
resource: string,
action: string
action: string,
): Promise<boolean> {
// Anonymous access: only public reads
if (!token) return false;

View File

@@ -2,5 +2,5 @@
* Provider exports
*/
export { StackGalleryAuthProvider, type IStackGalleryActor } from './auth.provider.ts';
export { StackGalleryStorageHooks, type IStorageConfig } from './storage.provider.ts';
export { type IStackGalleryActor, StackGalleryAuthProvider } from './auth.provider.ts';
export { type IStorageConfig, StackGalleryStorageHooks } from './storage.provider.ts';

View File

@@ -30,7 +30,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
* Called before a package is stored
*/
public async beforePut(
context: plugins.smartregistry.IStorageHookContext
context: plugins.smartregistry.IStorageHookContext,
): Promise<plugins.smartregistry.IBeforePutResult> {
// Validate organization exists and has quota
const orgId = context.actor?.orgId;
@@ -54,7 +54,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
* Called after a package is successfully stored
*/
public async afterPut(
context: plugins.smartregistry.IStorageHookContext
context: plugins.smartregistry.IStorageHookContext,
): Promise<void> {
const protocol = context.protocol as TRegistryProtocol;
const packageName = context.metadata?.packageName || context.key;
@@ -115,7 +115,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
* Called after a package is fetched
*/
public async afterGet(
context: plugins.smartregistry.IStorageHookContext
context: plugins.smartregistry.IStorageHookContext,
): Promise<void> {
const protocol = context.protocol as TRegistryProtocol;
const packageName = context.metadata?.packageName || context.key;
@@ -134,7 +134,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
* Called before a package is deleted
*/
public async beforeDelete(
context: plugins.smartregistry.IStorageHookContext
context: plugins.smartregistry.IStorageHookContext,
): Promise<plugins.smartregistry.IBeforeDeleteResult> {
return { allowed: true };
}
@@ -143,7 +143,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
* Called after a package is deleted
*/
public async afterDelete(
context: plugins.smartregistry.IStorageHookContext
context: plugins.smartregistry.IStorageHookContext,
): Promise<void> {
const protocol = context.protocol as TRegistryProtocol;
const packageName = context.metadata?.packageName || context.key;
@@ -216,7 +216,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
organizationName: string,
packageName: string,
version: string,
filename: string
filename: string,
): string {
return `${this.config.basePath}/${protocol}/${organizationName}/${packageName}/${version}/${filename}`;
}
@@ -227,7 +227,7 @@ export class StackGalleryStorageHooks implements plugins.smartregistry.IStorageH
public async storeArtifact(
path: string,
data: Uint8Array,
contentType?: string
contentType?: string,
): Promise<string> {
const bucket = await this.config.bucket.getBucketByName(this.config.bucketName);
await bucket.fastPut({