Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f67ee5719 | |||
| a6a4426249 | |||
| 8b7ec648cd | |||
| 8151ec094d | |||
| 63e85d5306 | |||
| 3945e42c53 | |||
| 53b4909df7 | |||
| a80e6eab20 | |||
| 1c240e895b | |||
| 03d065bccb | |||
| f4a748b5f3 | |||
| d922b873e4 | |||
| 78f3578098 | |||
| e811208773 |
+6
-2
@@ -8,11 +8,15 @@ RUN npm run build
|
||||
FROM node:22-bookworm-slim AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ARG DOCKER_VERSION=27.5.1
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl git docker.io binutils \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl git python3 make g++ \
|
||||
&& curl -fsSL "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" \
|
||||
| tar -xz -C /tmp \
|
||||
&& install -m 0755 /tmp/docker/docker /usr/local/bin/docker \
|
||||
&& curl -fsSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl" \
|
||||
&& chmod 0755 /usr/local/bin/kubectl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& rm -rf /tmp/docker /var/lib/apt/lists/*
|
||||
COPY package*.json ./
|
||||
RUN npm ci --omit=dev
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: atnmy-stdo-adm-v2-postgres
|
||||
environment:
|
||||
POSTGRES_DB: studio_admin
|
||||
POSTGRES_USER: studio_admin
|
||||
POSTGRES_PASSWORD: future1234!@
|
||||
ports:
|
||||
- "5436:5432"
|
||||
volumes:
|
||||
- atnmy-stdo-adm-v2-postgres:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U studio_admin -d studio_admin"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
|
||||
volumes:
|
||||
atnmy-stdo-adm-v2-postgres:
|
||||
@@ -44,6 +44,7 @@ model User {
|
||||
userLicenses UserLicense[]
|
||||
refreshTokens RefreshToken[]
|
||||
affiliations UserAffiliation[]
|
||||
appRoles UserAppRole[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@@ -108,18 +109,23 @@ model UserLicense {
|
||||
}
|
||||
|
||||
model Organization {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
type OrganizationType @default(OTHER)
|
||||
domain String?
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
type OrganizationType @default(OTHER)
|
||||
domain String?
|
||||
defaultLicenseCode String? @map("default_license_code")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
affiliations UserAffiliation[]
|
||||
instructorInviteCode String @unique @map("instructor_invite_code")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdById String? @map("created_by_id") @db.Uuid
|
||||
createdByName String? @map("created_by_name")
|
||||
createdByEmail String? @map("created_by_email")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
affiliations UserAffiliation[]
|
||||
|
||||
@@unique([name, type])
|
||||
@@index([isActive, type])
|
||||
@@index([createdByEmail])
|
||||
@@map("organizations")
|
||||
}
|
||||
|
||||
@@ -141,3 +147,22 @@ model UserAffiliation {
|
||||
@@index([organizationId])
|
||||
@@map("user_affiliations")
|
||||
}
|
||||
|
||||
model UserAppRole {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
userId String @map("user_id") @db.Uuid
|
||||
appKey String @map("app_key")
|
||||
roleCode String @map("role_code")
|
||||
assignedById String? @map("assigned_by") @db.Uuid
|
||||
assignedAt DateTime @default(now()) @map("assigned_at") @db.Timestamptz(3)
|
||||
startsAt DateTime? @map("starts_at") @db.Timestamptz(3)
|
||||
endsAt DateTime? @map("ends_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, appKey, roleCode])
|
||||
@@index([appKey, roleCode])
|
||||
@@index([userId, appKey])
|
||||
@@map("user_app_roles")
|
||||
}
|
||||
|
||||
@@ -46,16 +46,20 @@ model LauncherTerm {
|
||||
}
|
||||
|
||||
model LauncherManualDocument {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
appKey String @map("app_key")
|
||||
title String
|
||||
body String
|
||||
isPublished Boolean @default(true) @map("is_published")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
appKey String @map("app_key")
|
||||
title String
|
||||
body String
|
||||
isPublished Boolean @default(true) @map("is_published")
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
createdById String? @map("created_by_id") @db.Uuid
|
||||
createdByName String? @map("created_by_name")
|
||||
createdByEmail String? @map("created_by_email")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
|
||||
@@index([appKey, isPublished, sortOrder])
|
||||
@@index([createdByEmail])
|
||||
@@map("launcher_manual_documents")
|
||||
}
|
||||
|
||||
@@ -73,6 +77,9 @@ model ProvisionedDevice {
|
||||
kernel String?
|
||||
distro String?
|
||||
device Json?
|
||||
agentVersion String? @map("agent_version")
|
||||
agentUpdatedAt DateTime? @map("agent_updated_at") @db.Timestamptz(3)
|
||||
agentLastSeenAt DateTime? @map("agent_last_seen_at") @db.Timestamptz(3)
|
||||
installedAt DateTime @default(now()) @map("installed_at") @db.Timestamptz(3)
|
||||
lastProvisionedAt DateTime @default(now()) @map("last_provisioned_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
@@ -81,9 +88,32 @@ model ProvisionedDevice {
|
||||
@@unique([accountEmail, tailscaleHostname])
|
||||
@@index([accountEmail])
|
||||
@@index([tailscaleHostname])
|
||||
@@index([agentLastSeenAt])
|
||||
@@map("provisioned_devices")
|
||||
}
|
||||
|
||||
model DeviceAuthorization {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
deviceCodeHash String @unique @map("device_code_hash")
|
||||
userCode String @unique @map("user_code")
|
||||
status String @default("PENDING")
|
||||
authUserId String? @map("auth_user_id") @db.Uuid
|
||||
accountEmail String? @map("account_email")
|
||||
authUserName String? @map("auth_user_name")
|
||||
authUserRole String? @map("auth_user_role")
|
||||
authUserRoles Json? @map("auth_user_roles")
|
||||
device Json?
|
||||
expiresAt DateTime @map("expires_at") @db.Timestamptz(3)
|
||||
approvedAt DateTime? @map("approved_at") @db.Timestamptz(3)
|
||||
consumedAt DateTime? @map("consumed_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
|
||||
@@index([status, expiresAt])
|
||||
@@index([authUserId, createdAt])
|
||||
@@map("device_authorizations")
|
||||
}
|
||||
|
||||
model LauncherSshKey {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
accountEmail String @map("account_email")
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE "launcher_manual_documents"
|
||||
ADD COLUMN IF NOT EXISTS "created_by_id" UUID,
|
||||
ADD COLUMN IF NOT EXISTS "created_by_name" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "created_by_email" TEXT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "launcher_manual_documents_created_by_email_idx"
|
||||
ON "launcher_manual_documents"("created_by_email");
|
||||
@@ -0,0 +1,9 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF to_regclass('public.organizations') IS NOT NULL THEN
|
||||
ALTER TABLE "organizations"
|
||||
ADD COLUMN IF NOT EXISTS "created_by_id" UUID,
|
||||
ADD COLUMN IF NOT EXISTS "created_by_name" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "created_by_email" TEXT;
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "build_jobs"
|
||||
ADD COLUMN "artifact_sha256" TEXT;
|
||||
@@ -215,6 +215,7 @@ model BuildJob {
|
||||
branch String
|
||||
commitSha String? @map("commit_sha")
|
||||
artifact String?
|
||||
artifactSha256 String? @map("artifact_sha256")
|
||||
image String?
|
||||
status JobStatus @default(PENDING)
|
||||
requestedById String? @map("requested_by_id") @db.Uuid
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export function getAdminAvatarUrl(adminId: string | null | undefined, configService: ConfigService) {
|
||||
const publicBaseUrl = configService.get<string>('R2_PUBLIC_BASE_URL')?.replace(/\/+$/, '');
|
||||
if (!adminId || !publicBaseUrl) return null;
|
||||
|
||||
const prefix = configService.get<string>('R2_PUBLIC_FILE_PREFIX', 'studio-files/public');
|
||||
return `${publicBaseUrl}/${prefix.replace(/^\/+|\/+$/g, '')}/admins/${adminId}/avatar`;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { GiteaService } from '../gitea/gitea.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { getAdminAvatarUrl } from './admin-avatar';
|
||||
import { AdminRole } from './admin-role';
|
||||
import {
|
||||
CreateAdminSshKeyDto,
|
||||
@@ -334,13 +335,6 @@ export class AdminsService {
|
||||
}
|
||||
}
|
||||
|
||||
function getAdminAvatarUrl(adminId: string, configService: ConfigService) {
|
||||
const publicBaseUrl = configService.get<string>('R2_PUBLIC_BASE_URL')?.replace(/\/+$/, '');
|
||||
if (!publicBaseUrl) return null;
|
||||
const prefix = configService.get<string>('R2_PUBLIC_FILE_PREFIX', 'studio-files/public');
|
||||
return `${publicBaseUrl}/${prefix.replace(/^\/+|\/+$/g, '')}/admins/${adminId}/avatar`;
|
||||
}
|
||||
|
||||
const adminSelect = {
|
||||
id: true,
|
||||
email: true,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Controller, Delete, Get, Param, Patch, Query, Body } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
ListLauncherSshKeysQuery,
|
||||
CreateDeviceAuthorizationDto,
|
||||
ListDeviceAuthorizationUsersQuery,
|
||||
ListProvisionedDevicesQuery,
|
||||
UpdateProvisionedDeviceDto,
|
||||
} from './dto';
|
||||
@@ -38,4 +40,24 @@ export class AgentsController {
|
||||
removeSshKey(@Param('id') id: string) {
|
||||
return this.agentsService.removeSshKey(id);
|
||||
}
|
||||
|
||||
@Get('registration-users')
|
||||
listRegistrationUsers(@Query() query: ListDeviceAuthorizationUsersQuery) {
|
||||
return this.agentsService.listRegistrationUsers(query);
|
||||
}
|
||||
|
||||
@Get('device-authorizations')
|
||||
listDeviceAuthorizations() {
|
||||
return this.agentsService.listDeviceAuthorizations();
|
||||
}
|
||||
|
||||
@Post('device-authorizations')
|
||||
createDeviceAuthorization(@Body() body: CreateDeviceAuthorizationDto) {
|
||||
return this.agentsService.createDeviceAuthorization(body.userId);
|
||||
}
|
||||
|
||||
@Post('device-authorizations/:id/cancel')
|
||||
cancelDeviceAuthorization(@Param('id') id: string) {
|
||||
return this.agentsService.cancelDeviceAuthorization(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { LauncherPrismaModule } from '../launcher-prisma/launcher-prisma.module';
|
||||
import { AgentsController } from './agents.controller';
|
||||
import { AgentsService } from './agents.service';
|
||||
|
||||
@Module({
|
||||
imports: [LauncherPrismaModule],
|
||||
imports: [AuthPrismaModule, LauncherPrismaModule],
|
||||
controllers: [AgentsController],
|
||||
providers: [AgentsService],
|
||||
})
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { createHash, randomBytes } from 'node:crypto';
|
||||
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import {
|
||||
ListDeviceAuthorizationUsersQuery,
|
||||
ListLauncherSshKeysQuery,
|
||||
ListProvisionedDevicesQuery,
|
||||
UpdateProvisionedDeviceDto,
|
||||
@@ -9,7 +12,10 @@ import {
|
||||
|
||||
@Injectable()
|
||||
export class AgentsService {
|
||||
constructor(private readonly launcherPrisma: LauncherPrismaService) {}
|
||||
constructor(
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
) {}
|
||||
|
||||
async listDevices(query: ListProvisionedDevicesQuery) {
|
||||
const keyword = query.keyword?.trim();
|
||||
@@ -109,6 +115,114 @@ export class AgentsService {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
async listRegistrationUsers(query: ListDeviceAuthorizationUsersQuery) {
|
||||
const keyword = query.keyword?.trim();
|
||||
const users = await this.authPrisma.user.findMany({
|
||||
where: {
|
||||
role: 'USER',
|
||||
isActive: true,
|
||||
...(keyword
|
||||
? {
|
||||
OR: [
|
||||
{ email: { contains: keyword, mode: 'insensitive' } },
|
||||
{ name: { contains: keyword, mode: 'insensitive' } },
|
||||
],
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
orderBy: [{ name: 'asc' }, { email: 'asc' }],
|
||||
take: 20,
|
||||
select: { id: true, name: true, email: true },
|
||||
});
|
||||
|
||||
return { users };
|
||||
}
|
||||
|
||||
async listDeviceAuthorizations() {
|
||||
const now = new Date();
|
||||
const authorizations = await this.launcherPrisma.deviceAuthorization.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{ status: { in: ['APPROVED', 'CONSUMING'] } },
|
||||
{ createdAt: { gte: new Date(now.getTime() - 24 * 60 * 60 * 1000) } },
|
||||
],
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 50,
|
||||
select: {
|
||||
id: true,
|
||||
userCode: true,
|
||||
status: true,
|
||||
authUserId: true,
|
||||
accountEmail: true,
|
||||
authUserName: true,
|
||||
expiresAt: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
authorizations: authorizations.map((authorization) => ({
|
||||
...authorization,
|
||||
status: authorization.status === 'APPROVED' && authorization.expiresAt <= now ? 'EXPIRED' : authorization.status,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async createDeviceAuthorization(userId: string) {
|
||||
const user = await this.authPrisma.user.findFirst({
|
||||
where: { id: userId, role: 'USER', isActive: true },
|
||||
select: { id: true, email: true, name: true, role: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException('플랫폼 등록 대상 사용자를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const expiresAt = new Date(now.getTime() + 5 * 60 * 1000);
|
||||
await this.launcherPrisma.deviceAuthorization.updateMany({
|
||||
where: {
|
||||
authUserId: user.id,
|
||||
accountEmail: user.email,
|
||||
status: 'APPROVED',
|
||||
expiresAt: { gt: now },
|
||||
},
|
||||
data: { status: 'CANCELLED' },
|
||||
});
|
||||
|
||||
const authorization = await this.launcherPrisma.deviceAuthorization.create({
|
||||
data: {
|
||||
deviceCodeHash: createHash('sha256').update(randomBytes(32).toString('base64url')).digest('hex'),
|
||||
userCode: String(randomBytes(4).readUInt32BE() % 1_000_000).padStart(6, '0'),
|
||||
status: 'APPROVED',
|
||||
authUserId: user.id,
|
||||
accountEmail: user.email,
|
||||
authUserName: user.name,
|
||||
authUserRole: user.role,
|
||||
authUserRoles: [user.role],
|
||||
expiresAt,
|
||||
approvedAt: now,
|
||||
},
|
||||
select: { id: true, userCode: true, expiresAt: true, accountEmail: true, authUserName: true, status: true },
|
||||
});
|
||||
|
||||
return { authorization };
|
||||
}
|
||||
|
||||
async cancelDeviceAuthorization(id: string) {
|
||||
const result = await this.launcherPrisma.deviceAuthorization.updateMany({
|
||||
where: { id, status: { in: ['APPROVED', 'CONSUMING'] } },
|
||||
data: { status: 'CANCELLED' },
|
||||
});
|
||||
|
||||
if (!result.count) {
|
||||
throw new NotFoundException('취소할 플랫폼 등록 키를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
private async ensureDeviceExists(id: string) {
|
||||
const device = await this.launcherPrisma.provisionedDevice.findUnique({
|
||||
where: { id },
|
||||
|
||||
+12
-1
@@ -1,4 +1,4 @@
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
import { IsOptional, IsString, IsUUID } from 'class-validator';
|
||||
|
||||
export class ListProvisionedDevicesQuery {
|
||||
@IsOptional()
|
||||
@@ -37,3 +37,14 @@ export class ListLauncherSshKeysQuery {
|
||||
@IsString()
|
||||
keyword?: string;
|
||||
}
|
||||
|
||||
export class ListDeviceAuthorizationUsersQuery {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
keyword?: string;
|
||||
}
|
||||
|
||||
export class CreateDeviceAuthorizationDto {
|
||||
@IsUUID()
|
||||
userId!: string;
|
||||
}
|
||||
|
||||
@@ -195,6 +195,15 @@ export class AppsController {
|
||||
return this.appsService.listRuntimeResources(namespace);
|
||||
}
|
||||
|
||||
@Get('runtime-namespaces/:namespace/resources/:kind/:name/yaml')
|
||||
getRuntimeResourceYaml(
|
||||
@Param('namespace') namespace: string,
|
||||
@Param('kind') kind: string,
|
||||
@Param('name') name: string,
|
||||
) {
|
||||
return this.appsService.getRuntimeResourceYaml(namespace, kind, name);
|
||||
}
|
||||
|
||||
@Post('runtime-namespaces')
|
||||
ensureRuntimeNamespace(@Body() body: EnsureRuntimeNamespaceDto) {
|
||||
return this.appsService.ensureRuntimeNamespace(body);
|
||||
|
||||
@@ -2,13 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { LauncherModule } from '../launcher/launcher.module';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { AppsController } from './apps.controller';
|
||||
import { AppsService } from './apps.service';
|
||||
import { BuildRunnerService } from './build-runner.service';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, LauncherModule, AuthPrismaModule],
|
||||
imports: [PrismaModule, LauncherModule],
|
||||
controllers: [AppsController],
|
||||
providers: [AppsService, BuildRunnerService],
|
||||
})
|
||||
|
||||
+317
-176
@@ -8,10 +8,9 @@ import * as path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import { LinkComponentSourceDto } from '../gitea/dto';
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import { LauncherService } from '../launcher/launcher.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { getUserAvatarUrl } from '../users/users.service';
|
||||
import { BuildRunnerService } from './build-runner.service';
|
||||
import {
|
||||
CreateAppComponentDto,
|
||||
@@ -46,7 +45,6 @@ export class AppsService {
|
||||
private readonly configService: ConfigService,
|
||||
private readonly buildRunnerService: BuildRunnerService,
|
||||
private readonly launcherService: LauncherService,
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
) {}
|
||||
|
||||
private requesterData(requester?: AdminRequester) {
|
||||
@@ -59,31 +57,11 @@ export class AppsService {
|
||||
: {};
|
||||
}
|
||||
|
||||
private async withRequesterAvatars<T extends { requestedByEmail?: string | null }>(items: T[]) {
|
||||
const emails = [...new Set(items.map((item) => item.requestedByEmail).filter((email): email is string => Boolean(email)))];
|
||||
if (emails.length === 0) return items.map((item) => ({ ...item, requestedByAvatarUrl: null }));
|
||||
|
||||
const users = await this.authPrisma.user.findMany({
|
||||
where: { email: { in: emails } },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
profileImageMime: true,
|
||||
},
|
||||
});
|
||||
const userByEmail = new Map(users.map((user) => [user.email, user]));
|
||||
const authBaseUrl = this.configService.get<string>('AUTH_PUBLIC_URL')
|
||||
?? this.configService.get<string>('ATNMY_AUTH_URL')
|
||||
?? this.configService.get<string>('AUTH_EXTERNAL_URL')
|
||||
?? 'https://auth.autonomystudio.net';
|
||||
|
||||
return items.map((item) => {
|
||||
const user = item.requestedByEmail ? userByEmail.get(item.requestedByEmail) : null;
|
||||
return {
|
||||
...item,
|
||||
requestedByAvatarUrl: getUserAvatarUrl(user?.id ?? '', user?.profileImageMime, authBaseUrl),
|
||||
};
|
||||
});
|
||||
private withRequesterAvatars<T extends { requestedById?: string | null }>(items: T[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
requestedByAvatarUrl: getAdminAvatarUrl(item.requestedById, this.configService),
|
||||
}));
|
||||
}
|
||||
|
||||
async listApps() {
|
||||
@@ -531,6 +509,15 @@ export class AppsService {
|
||||
throw new Error('릴리즈 기준 빌드 작업을 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
const missingArtifactMetadata = sourceBuildJobs.find((job) => (
|
||||
job.component.type === 'ELECTRON' && (!job.artifact || !job.artifactSha256)
|
||||
));
|
||||
if (missingArtifactMetadata) {
|
||||
throw new Error(
|
||||
`${missingArtifactMetadata.component.name} 빌드에 R2 산출물 또는 SHA-256 정보가 없습니다. 새 빌드 후 릴리즈하세요.`,
|
||||
);
|
||||
}
|
||||
|
||||
for (const job of sourceBuildJobs) {
|
||||
await this.appendReleaseLog(releaseId, `[source] ${job.component.name} develop ${job.commitSha?.slice(0, 7) ?? '-'}`);
|
||||
}
|
||||
@@ -538,21 +525,10 @@ export class AppsService {
|
||||
await this.promoteReleaseBranches(sourceBuildJobs, 'develop', release.branch);
|
||||
await this.appendReleaseLog(releaseId, '[promote] completed');
|
||||
|
||||
const releaseBuildJobs = await this.createReleaseBuildJobs(sourceBuildJobs, release.branch);
|
||||
for (const job of releaseBuildJobs) {
|
||||
await this.appendReleaseLog(releaseId, `[build] queued ${job.component.name} ${job.branch} ${job.commitSha?.slice(0, 7) ?? '-'}`);
|
||||
}
|
||||
await this.appendReleaseLog(releaseId, '[wait] waiting for release build jobs');
|
||||
const completedBuildJobs = await this.waitForBuildJobs(releaseBuildJobs.map((job) => job.id));
|
||||
const failed = completedBuildJobs.find((job) => job.status !== 'SUCCEEDED');
|
||||
if (failed) {
|
||||
throw new Error(`${failed.component.name} release 빌드 실패: ${failed.status}`);
|
||||
}
|
||||
await this.appendReleaseLog(releaseId, '[build] release build jobs completed');
|
||||
|
||||
const commitShas = [...new Set(completedBuildJobs.map((job) => job.commitSha).filter(Boolean))];
|
||||
const artifact = completedBuildJobs.find((job) => job.artifact)?.artifact ?? null;
|
||||
const imageTags = createReleaseImageTags(completedBuildJobs, release.app.components);
|
||||
await this.appendReleaseLog(releaseId, '[artifact] reusing selected develop build artifacts');
|
||||
const commitShas = [...new Set(sourceBuildJobs.map((job) => job.commitSha).filter(Boolean))];
|
||||
const artifact = sourceBuildJobs.find((job) => job.artifact)?.artifact ?? null;
|
||||
const imageTags = createReleaseImageTags(sourceBuildJobs, release.app.components);
|
||||
|
||||
await this.appendReleaseLog(releaseId, '[done] release completed');
|
||||
await this.prisma.appRelease.update({
|
||||
@@ -594,87 +570,6 @@ export class AppsService {
|
||||
});
|
||||
}
|
||||
|
||||
private async createReleaseBuildJobs(
|
||||
sourceBuildJobs: Array<{
|
||||
componentId: string;
|
||||
commitSha: string | null;
|
||||
requestedById?: string | null;
|
||||
requestedByName?: string | null;
|
||||
requestedByEmail?: string | null;
|
||||
component: {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
repository: string | null;
|
||||
buildTarget: string | null;
|
||||
app: { name: string };
|
||||
};
|
||||
}>,
|
||||
branch: string,
|
||||
) {
|
||||
const jobs = [];
|
||||
for (const sourceJob of sourceBuildJobs) {
|
||||
const component = sourceJob.component;
|
||||
const artifact = getBuildArtifact(component, branch, sourceJob.commitSha);
|
||||
const image = getBuildImage(
|
||||
component,
|
||||
branch,
|
||||
sourceJob.commitSha,
|
||||
this.configService.get<string>('BUILD_REGISTRY', 'registry.local'),
|
||||
);
|
||||
const job = await this.prisma.buildJob.create({
|
||||
data: {
|
||||
componentId: component.id,
|
||||
branch,
|
||||
commitSha: sourceJob.commitSha,
|
||||
artifact,
|
||||
image,
|
||||
status: 'PENDING',
|
||||
requestedById: sourceJob.requestedById,
|
||||
requestedByName: sourceJob.requestedByName,
|
||||
requestedByEmail: sourceJob.requestedByEmail,
|
||||
logs: getBuildPlanLogs({
|
||||
appName: component.app.name,
|
||||
componentName: component.name,
|
||||
componentType: component.type,
|
||||
repository: component.repository || '',
|
||||
branch,
|
||||
commitSha: sourceJob.commitSha,
|
||||
buildTarget: component.buildTarget,
|
||||
artifact,
|
||||
image,
|
||||
giteaBaseUrl: this.configService.get<string>(
|
||||
'GITEA_BASE_URL',
|
||||
'http://localhost:3000',
|
||||
),
|
||||
}).join('\n'),
|
||||
},
|
||||
include: { component: true },
|
||||
});
|
||||
jobs.push(job);
|
||||
}
|
||||
return jobs;
|
||||
}
|
||||
|
||||
private async waitForBuildJobs(buildJobIds: string[]) {
|
||||
const timeoutMs = Number(this.configService.get<string>('RELEASE_BUILD_TIMEOUT_MS', '1800000'));
|
||||
const startedAt = Date.now();
|
||||
|
||||
while (Date.now() - startedAt < timeoutMs) {
|
||||
const jobs = await this.prisma.buildJob.findMany({
|
||||
where: { id: { in: buildJobIds } },
|
||||
include: { component: true },
|
||||
});
|
||||
if (jobs.length === buildJobIds.length && jobs.every((job) => ['SUCCEEDED', 'FAILED', 'CANCELED'].includes(job.status))) {
|
||||
return jobs;
|
||||
}
|
||||
await delay(3000);
|
||||
}
|
||||
|
||||
throw new Error('release 빌드 완료 대기 시간이 초과되었습니다.');
|
||||
}
|
||||
|
||||
|
||||
private async promoteReleaseBranches(
|
||||
buildJobs: Array<{
|
||||
id: string;
|
||||
@@ -976,55 +871,116 @@ export class AppsService {
|
||||
async createDeploymentJob(body: CreateDeploymentJobDto, requester?: AdminRequester) {
|
||||
const namespace = normalizeNamespace(body.namespace);
|
||||
const environment = body.environment.trim();
|
||||
const release = await this.prisma.appRelease.findUnique({
|
||||
where: { id: body.releaseId },
|
||||
include: {
|
||||
app: {
|
||||
include: {
|
||||
components: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (body.releaseId && body.buildJobId) {
|
||||
throw new BadRequestException('릴리즈 또는 빌드 중 하나만 배포 대상으로 선택할 수 있습니다.');
|
||||
}
|
||||
|
||||
if (!release) {
|
||||
const release = body.releaseId
|
||||
? await this.prisma.appRelease.findUnique({
|
||||
where: { id: body.releaseId },
|
||||
include: {
|
||||
app: {
|
||||
include: {
|
||||
components: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
: null;
|
||||
const quickBuild = body.buildJobId
|
||||
? await this.prisma.buildJob.findUnique({
|
||||
where: { id: body.buildJobId },
|
||||
include: {
|
||||
component: {
|
||||
include: {
|
||||
app: {
|
||||
include: { components: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
: null;
|
||||
|
||||
if (body.releaseId && !release) {
|
||||
throw new NotFoundException('릴리즈를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (release.status !== 'SUCCEEDED') {
|
||||
if (body.buildJobId && !quickBuild) {
|
||||
throw new NotFoundException('빌드 작업을 찾을 수 없습니다.');
|
||||
}
|
||||
if (!release && !quickBuild) {
|
||||
throw new BadRequestException('배포할 릴리즈 또는 빌드를 선택하세요.');
|
||||
}
|
||||
if (release && release.status !== 'SUCCEEDED') {
|
||||
throw new BadRequestException('성공한 릴리즈만 배포할 수 있습니다.');
|
||||
}
|
||||
|
||||
const imageTags = parseReleaseImageTags(release.imageTags);
|
||||
const images = imageTags.images;
|
||||
const runtimeProfile = await this.prisma.runtimeEnvProfile.findFirst({
|
||||
where: {
|
||||
appId: release.appId,
|
||||
environment,
|
||||
namespace,
|
||||
},
|
||||
include: {
|
||||
ingressRules: {
|
||||
include: { component: true },
|
||||
orderBy: { host: 'asc' },
|
||||
},
|
||||
},
|
||||
});
|
||||
if (Object.keys(images).length === 0) {
|
||||
throw new BadRequestException('릴리즈에 배포 가능한 이미지가 없습니다.');
|
||||
if (quickBuild && quickBuild.status !== 'SUCCEEDED') {
|
||||
throw new BadRequestException('성공한 빌드만 빠른 배포할 수 있습니다.');
|
||||
}
|
||||
if (quickBuild && !['CONTAINER', 'STATIC_WEB'].includes(quickBuild.component.type)) {
|
||||
throw new BadRequestException('컨테이너 이미지 빌드만 빠른 배포할 수 있습니다.');
|
||||
}
|
||||
if (quickBuild && !quickBuild.image) {
|
||||
throw new BadRequestException('배포할 컨테이너 이미지가 없습니다.');
|
||||
}
|
||||
|
||||
const namespaceExists = await this.namespaceExists(namespace);
|
||||
if (!namespaceExists) {
|
||||
throw new BadRequestException(
|
||||
`${namespace} namespace가 없습니다. 런타임 구성에서 Namespace 생성/확인을 먼저 실행하세요.`,
|
||||
);
|
||||
const app = release?.app ?? quickBuild!.component.app;
|
||||
const releaseImages = release
|
||||
? parseReleaseImageTags(release.imageTags).images
|
||||
: { [quickBuild!.component.name]: quickBuild!.image! };
|
||||
const images = Object.fromEntries(
|
||||
Object.entries(releaseImages).filter(([componentName]) => {
|
||||
const componentType = app.components.find((component) => component.name === componentName)?.type;
|
||||
return componentType === 'CONTAINER' || componentType === 'STATIC_WEB';
|
||||
}),
|
||||
);
|
||||
const hasKubernetesWorkload = Object.keys(images).length > 0;
|
||||
const isLauncherArtifactRelease = Boolean(
|
||||
release
|
||||
&& !hasKubernetesWorkload
|
||||
&& body.updateLauncherAppVersion !== false
|
||||
&& app.components.some((component) => component.type === 'ELECTRON')
|
||||
&& hasReleaseArtifact(release.artifact, release.imageTags),
|
||||
);
|
||||
const deploymentLabel = release
|
||||
? `${app.name} ${release.version}`
|
||||
: `${app.name} ${quickBuild!.component.name} ${quickBuild!.commitSha?.slice(0, 7) ?? 'quick'}`;
|
||||
const requestedResources = body.resources;
|
||||
const runtimeProfile = hasKubernetesWorkload
|
||||
? await this.prisma.runtimeEnvProfile.findFirst({
|
||||
where: {
|
||||
appId: app.id,
|
||||
environment,
|
||||
namespace,
|
||||
},
|
||||
include: {
|
||||
ingressRules: {
|
||||
include: { component: true },
|
||||
orderBy: { host: 'asc' },
|
||||
},
|
||||
},
|
||||
})
|
||||
: null;
|
||||
if (!hasKubernetesWorkload && !isLauncherArtifactRelease) {
|
||||
if (release && hasReleaseArtifact(release.artifact, release.imageTags)) {
|
||||
throw new BadRequestException('AppImage 릴리즈는 런처 앱 버전 업데이트를 선택해야 합니다.');
|
||||
}
|
||||
throw new BadRequestException('릴리즈에 배포 가능한 이미지 또는 AppImage 산출물이 없습니다.');
|
||||
}
|
||||
|
||||
if (hasKubernetesWorkload) {
|
||||
const namespaceExists = await this.namespaceExists(namespace);
|
||||
if (!namespaceExists) {
|
||||
throw new BadRequestException(
|
||||
`${namespace} namespace가 없습니다. 런타임 구성에서 Namespace 생성/확인을 먼저 실행하세요.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const deploymentJob = await this.prisma.deploymentJob.create({
|
||||
data: {
|
||||
appId: release.appId,
|
||||
releaseId: release.id,
|
||||
appId: app.id,
|
||||
releaseId: release?.id,
|
||||
environment,
|
||||
namespace,
|
||||
status: 'RUNNING',
|
||||
@@ -1032,8 +988,10 @@ export class AppsService {
|
||||
...this.requesterData(requester),
|
||||
startedAt: new Date(),
|
||||
logs: [
|
||||
`[running] deployment started: ${release.app.name} ${release.version}`,
|
||||
`[running] deployment started: ${deploymentLabel}`,
|
||||
...(quickBuild ? [`[source] quick build ${quickBuild.id} ${quickBuild.image}`] : []),
|
||||
`[target] environment=${environment} namespace=${namespace}`,
|
||||
...(isLauncherArtifactRelease ? ['[launcher] AppImage release; Kubernetes rollout skipped'] : []),
|
||||
].join('\n'),
|
||||
},
|
||||
include: {
|
||||
@@ -1047,7 +1005,7 @@ export class AppsService {
|
||||
|
||||
for (const [componentName, image] of Object.entries(images)) {
|
||||
const deploymentName = sanitizeK8sName(componentName);
|
||||
const component = release.app.components.find((item) => item.name === componentName);
|
||||
const component = app.components.find((item) => item.name === componentName);
|
||||
const workloadType = normalizeWorkloadType(component?.workloadType, component?.type);
|
||||
const deploymentExists = workloadType === 'StatefulSet'
|
||||
? await this.statefulSetExists(namespace, deploymentName)
|
||||
@@ -1075,14 +1033,25 @@ export class AppsService {
|
||||
deploymentName,
|
||||
componentName,
|
||||
image,
|
||||
replicas: component?.replicas ?? 1,
|
||||
replicas: requestedResources?.replicas ?? component?.replicas ?? 1,
|
||||
ports: getComponentPorts(component),
|
||||
resources: requestedResources,
|
||||
})
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const workloadRef = `${workloadType.toLowerCase()}/${deploymentName}`;
|
||||
if (requestedResources?.replicas) {
|
||||
logs.push(`[scale] ${workloadRef} replicas=${requestedResources.replicas}`);
|
||||
appendOutput(logs, await this.kubectl([
|
||||
'scale',
|
||||
workloadRef,
|
||||
`--replicas=${requestedResources.replicas}`,
|
||||
'-n',
|
||||
namespace,
|
||||
]));
|
||||
}
|
||||
logs.push(`[set-image] ${workloadRef} ${deploymentName}=${image}`);
|
||||
const setImageOutput = await this.kubectl([
|
||||
'set',
|
||||
@@ -1094,6 +1063,31 @@ export class AppsService {
|
||||
]);
|
||||
appendOutput(logs, setImageOutput);
|
||||
|
||||
const resourceArgs = [
|
||||
'set',
|
||||
'resources',
|
||||
workloadRef,
|
||||
`--containers=${deploymentName}`,
|
||||
'-n',
|
||||
namespace,
|
||||
...(requestedResources?.cpuRequest || requestedResources?.memoryRequest
|
||||
? [`--requests=${[
|
||||
requestedResources.cpuRequest ? `cpu=${requestedResources.cpuRequest}` : null,
|
||||
requestedResources.memoryRequest ? `memory=${requestedResources.memoryRequest}` : null,
|
||||
].filter(Boolean).join(',')}`]
|
||||
: []),
|
||||
...(requestedResources?.cpuLimit || requestedResources?.memoryLimit
|
||||
? [`--limits=${[
|
||||
requestedResources.cpuLimit ? `cpu=${requestedResources.cpuLimit}` : null,
|
||||
requestedResources.memoryLimit ? `memory=${requestedResources.memoryLimit}` : null,
|
||||
].filter(Boolean).join(',')}`]
|
||||
: []),
|
||||
];
|
||||
if (resourceArgs.length > 6) {
|
||||
logs.push(`[resources] ${workloadRef}`);
|
||||
appendOutput(logs, await this.kubectl(resourceArgs));
|
||||
}
|
||||
|
||||
logs.push(`[rollout] ${workloadRef}`);
|
||||
const rolloutOutput = await this.kubectl([
|
||||
'rollout',
|
||||
@@ -1158,7 +1152,7 @@ export class AppsService {
|
||||
}
|
||||
}
|
||||
|
||||
if (body.updateLauncherAppVersion !== false) {
|
||||
if (release && body.updateLauncherAppVersion !== false) {
|
||||
try {
|
||||
await this.launcherService.publishAppReleaseToLauncher(release.id);
|
||||
logs.push('[launcher] app version updated');
|
||||
@@ -1167,7 +1161,7 @@ export class AppsService {
|
||||
logs.push(`[launcher] app version update failed: ${launcherMessage}`);
|
||||
}
|
||||
} else {
|
||||
logs.push('[launcher] app version update skipped');
|
||||
logs.push(quickBuild ? '[launcher] app version update skipped for quick deployment' : '[launcher] app version update skipped');
|
||||
}
|
||||
|
||||
logs.push('[done] deployment completed');
|
||||
@@ -1528,7 +1522,7 @@ export class AppsService {
|
||||
{ kind: 'StatefulSet', command: 'statefulsets' },
|
||||
{ kind: 'Service', command: 'services' },
|
||||
{ kind: 'Ingress', command: 'ingress' },
|
||||
{ kind: 'PVC', command: 'pvc' },
|
||||
{ kind: 'PersistentVolumeClaim', command: 'pvc' },
|
||||
];
|
||||
const resources = [];
|
||||
|
||||
@@ -1552,12 +1546,32 @@ export class AppsService {
|
||||
deployments: resources.filter((resource) => resource.kind === 'Deployment').length,
|
||||
statefulSets: resources.filter((resource) => resource.kind === 'StatefulSet').length,
|
||||
services: resources.filter((resource) => resource.kind === 'Service').length,
|
||||
persistentVolumeClaims: resources.filter((resource) => resource.kind === 'PVC').length,
|
||||
persistentVolumeClaims: resources.filter((resource) => resource.kind === 'PersistentVolumeClaim').length,
|
||||
},
|
||||
resources,
|
||||
};
|
||||
}
|
||||
|
||||
async getRuntimeResourceYaml(namespace: string, kind: string, name: string) {
|
||||
const normalizedNamespace = normalizeNamespace(namespace);
|
||||
const resourceType = getKubectlResourceType(kind);
|
||||
if (!resourceType) {
|
||||
throw new BadRequestException('YAML 조회를 지원하지 않는 리소스 유형입니다.');
|
||||
}
|
||||
|
||||
const yaml = await this.kubectl([
|
||||
'get',
|
||||
resourceType,
|
||||
name,
|
||||
'-n',
|
||||
normalizedNamespace,
|
||||
'-o',
|
||||
'yaml',
|
||||
]);
|
||||
|
||||
return { namespace: normalizedNamespace, kind, name, yaml };
|
||||
}
|
||||
|
||||
async ensureRuntimeNamespace(body: EnsureRuntimeNamespaceDto) {
|
||||
const namespace = normalizeNamespace(body.namespace);
|
||||
const logs: string[] = [];
|
||||
@@ -1656,13 +1670,33 @@ export class AppsService {
|
||||
async deleteRuntimeProfile(profileId: string) {
|
||||
const profile = await this.prisma.runtimeEnvProfile.findUnique({
|
||||
where: { id: profileId },
|
||||
select: { id: true, name: true },
|
||||
include: {
|
||||
variables: {
|
||||
include: {
|
||||
component: {
|
||||
select: {
|
||||
name: true,
|
||||
type: true,
|
||||
workloadType: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!profile) {
|
||||
throw new NotFoundException('실행 설정 프로필을 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
for (const variable of profile.variables) {
|
||||
await this.removeRuntimeVariableFromWorkload(
|
||||
normalizeNamespace(profile.namespace),
|
||||
variable.component,
|
||||
variable.key,
|
||||
);
|
||||
}
|
||||
|
||||
await this.prisma.runtimeEnvProfile.delete({
|
||||
where: { id: profileId },
|
||||
});
|
||||
@@ -1765,13 +1799,32 @@ export class AppsService {
|
||||
async deleteRuntimeVariable(profileId: string, variableId: string) {
|
||||
const variable = await this.prisma.runtimeEnvVariable.findFirst({
|
||||
where: { id: variableId, profileId },
|
||||
select: { id: true },
|
||||
include: {
|
||||
profile: {
|
||||
select: {
|
||||
namespace: true,
|
||||
},
|
||||
},
|
||||
component: {
|
||||
select: {
|
||||
name: true,
|
||||
type: true,
|
||||
workloadType: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!variable) {
|
||||
throw new NotFoundException('환경변수를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
await this.removeRuntimeVariableFromWorkload(
|
||||
normalizeNamespace(variable.profile.namespace),
|
||||
variable.component,
|
||||
variable.key,
|
||||
);
|
||||
|
||||
await this.prisma.runtimeEnvVariable.delete({
|
||||
where: { id: variable.id },
|
||||
});
|
||||
@@ -2125,6 +2178,32 @@ export class AppsService {
|
||||
}
|
||||
}
|
||||
|
||||
private async removeRuntimeVariableFromWorkload(
|
||||
namespace: string,
|
||||
component: { name: string; type: string; workloadType: string | null } | null,
|
||||
key: string,
|
||||
) {
|
||||
if (!component || component.type === 'DATABASE') {
|
||||
return;
|
||||
}
|
||||
|
||||
const workloadType = normalizeWorkloadType(component.workloadType, component.type);
|
||||
if (workloadType === 'Job') {
|
||||
return;
|
||||
}
|
||||
|
||||
const workloadRef = `${workloadType.toLowerCase()}/${sanitizeK8sName(component.name)}`;
|
||||
try {
|
||||
await this.kubectl(['set', 'env', workloadRef, `${key}-`, '-n', namespace]);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
if (/\bnot\s*found\b/i.test(message)) {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async kubectlEnv() {
|
||||
const inClusterHost = process.env.KUBERNETES_SERVICE_HOST;
|
||||
if (inClusterHost) {
|
||||
@@ -2776,6 +2855,26 @@ function getNumber(value: unknown, fallback = 0) {
|
||||
return typeof value === 'number' ? value : fallback;
|
||||
}
|
||||
|
||||
function getKubectlResourceType(kind: string) {
|
||||
const resourceTypes: Record<string, string> = {
|
||||
Deployment: 'deployment',
|
||||
StatefulSet: 'statefulset',
|
||||
DaemonSet: 'daemonset',
|
||||
Pod: 'pod',
|
||||
Job: 'job',
|
||||
CronJob: 'cronjob',
|
||||
ReplicaSet: 'replicaset',
|
||||
Service: 'service',
|
||||
Ingress: 'ingress',
|
||||
PersistentVolumeClaim: 'pvc',
|
||||
PVC: 'pvc',
|
||||
Endpoint: 'endpoints',
|
||||
Endpoints: 'endpoints',
|
||||
};
|
||||
|
||||
return resourceTypes[kind];
|
||||
}
|
||||
|
||||
function getAge(createdAt: string) {
|
||||
const created = new Date(createdAt).getTime();
|
||||
if (!created || Number.isNaN(created)) return '-';
|
||||
@@ -2796,6 +2895,12 @@ function createDeploymentManifest(input: {
|
||||
image: string;
|
||||
replicas?: number | null;
|
||||
ports?: ComponentPort[];
|
||||
resources?: {
|
||||
cpuRequest?: string;
|
||||
cpuLimit?: string;
|
||||
memoryRequest?: string;
|
||||
memoryLimit?: string;
|
||||
};
|
||||
}) {
|
||||
const labels = {
|
||||
'app.kubernetes.io/name': input.deploymentName,
|
||||
@@ -2828,6 +2933,28 @@ function createDeploymentManifest(input: {
|
||||
name: input.deploymentName,
|
||||
image: input.image,
|
||||
imagePullPolicy: 'IfNotPresent',
|
||||
...(input.resources?.cpuRequest || input.resources?.memoryRequest || input.resources?.cpuLimit || input.resources?.memoryLimit
|
||||
? {
|
||||
resources: {
|
||||
...(input.resources.cpuRequest || input.resources.memoryRequest
|
||||
? {
|
||||
requests: {
|
||||
...(input.resources.cpuRequest ? { cpu: input.resources.cpuRequest } : {}),
|
||||
...(input.resources.memoryRequest ? { memory: input.resources.memoryRequest } : {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(input.resources.cpuLimit || input.resources.memoryLimit
|
||||
? {
|
||||
limits: {
|
||||
...(input.resources.cpuLimit ? { cpu: input.resources.cpuLimit } : {}),
|
||||
...(input.resources.memoryLimit ? { memory: input.resources.memoryLimit } : {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(input.ports?.length
|
||||
? {
|
||||
ports: input.ports.map((port) => ({
|
||||
@@ -3275,6 +3402,16 @@ function parseReleaseImageTags(value: Prisma.JsonValue | null) {
|
||||
return { images };
|
||||
}
|
||||
|
||||
function hasReleaseArtifact(artifact: string | null, imageTags: Prisma.JsonValue | null) {
|
||||
if (artifact?.trim()) return true;
|
||||
if (!imageTags || typeof imageTags !== 'object' || Array.isArray(imageTags)) return false;
|
||||
|
||||
const artifacts = (imageTags as Record<string, unknown>).artifacts;
|
||||
if (!artifacts || typeof artifacts !== 'object' || Array.isArray(artifacts)) return false;
|
||||
|
||||
return Object.values(artifacts).some((value) => typeof value === 'string' && value.trim());
|
||||
}
|
||||
|
||||
function getUsedReleaseBuildIds(releases: Array<{ imageTags: Prisma.JsonValue | null }>) {
|
||||
const ids = new Set<string>();
|
||||
for (const release of releases) {
|
||||
@@ -3344,6 +3481,7 @@ function createReleaseImageTags(
|
||||
branch: string;
|
||||
commitSha: string | null;
|
||||
artifact: string | null;
|
||||
artifactSha256: string | null;
|
||||
image: string | null;
|
||||
component: {
|
||||
id: string;
|
||||
@@ -3361,6 +3499,7 @@ function createReleaseImageTags(
|
||||
): Prisma.InputJsonObject {
|
||||
const images: Record<string, string> = {};
|
||||
const artifacts: Record<string, string> = {};
|
||||
const artifactChecksums: Record<string, string> = {};
|
||||
|
||||
for (const job of buildJobs) {
|
||||
if (job.image && !images[job.component.name]) {
|
||||
@@ -3369,13 +3508,17 @@ function createReleaseImageTags(
|
||||
if (job.artifact && !artifacts[job.component.name]) {
|
||||
artifacts[job.component.name] = job.artifact;
|
||||
}
|
||||
if (job.artifactSha256 && !artifactChecksums[job.component.name]) {
|
||||
artifactChecksums[job.component.name] = job.artifactSha256;
|
||||
}
|
||||
}
|
||||
|
||||
for (const component of components) {
|
||||
const imageSource = normalizeImageSource(component.imageSource, component.type);
|
||||
if (
|
||||
!images[component.name]
|
||||
&& (imageSource === 'EXTERNAL' || imageSource === 'DATABASE')
|
||||
&& imageSource === 'EXTERNAL'
|
||||
&& component.type !== 'DATABASE'
|
||||
&& component.externalImage?.trim()
|
||||
) {
|
||||
images[component.name] = component.externalImage.trim();
|
||||
@@ -3385,6 +3528,7 @@ function createReleaseImageTags(
|
||||
return {
|
||||
images,
|
||||
artifacts,
|
||||
artifactChecksums,
|
||||
buildJobs: buildJobs.map((job) => ({
|
||||
id: job.id,
|
||||
componentId: job.component.id,
|
||||
@@ -3394,6 +3538,7 @@ function createReleaseImageTags(
|
||||
commitSha: job.commitSha,
|
||||
image: job.image,
|
||||
artifact: job.artifact,
|
||||
artifactSha256: job.artifactSha256,
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -3483,7 +3628,3 @@ function getBuildPlanLogs(input: {
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
@@ -300,6 +300,25 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
const contextPath = this.configService.get<string>('BUILD_CONTEXT_PATH', '.');
|
||||
const contextDir = path.resolve(workDir, contextPath);
|
||||
const pushEnabled = this.configService.get<string>('BUILD_PUSH_ENABLED', 'true') !== 'false';
|
||||
const viteBuildVariables = job.component.buildVariables
|
||||
.filter((variable) => !variable.isSecret && variable.key.trim().startsWith('VITE_'));
|
||||
const buildArgs = job.component.buildVariables
|
||||
.filter((variable) => !variable.isSecret && variable.key.trim())
|
||||
.filter((variable) => !variable.key.trim().startsWith('VITE_'))
|
||||
.flatMap((variable) => ['--build-arg', `${variable.key}=${variable.value}`]);
|
||||
|
||||
if (viteBuildVariables.length > 0) {
|
||||
await fs.writeFile(
|
||||
path.join(contextDir, '.env.production.local'),
|
||||
`${viteBuildVariables.map((variable) => `${variable.key}=${JSON.stringify(variable.value)}`).join('\n')}\n`,
|
||||
'utf8',
|
||||
);
|
||||
await append(`[image] Vite build env ${viteBuildVariables.map((variable) => variable.key).join(', ')}`);
|
||||
}
|
||||
|
||||
if (buildArgs.length > 0) {
|
||||
await append(`[image] build args ${job.component.buildVariables.filter((variable) => !variable.isSecret && variable.key.trim() && !variable.key.trim().startsWith('VITE_')).map((variable) => variable.key).join(', ')}`);
|
||||
}
|
||||
|
||||
if (image !== job.image) {
|
||||
await this.prisma.buildJob.update({
|
||||
@@ -316,7 +335,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
await runCommand({
|
||||
jobId: job.id,
|
||||
command: this.configService.get<string>('NERDCTL_BIN', 'nerdctl'),
|
||||
args: [...prefix, 'build', '-t', image, '-f', dockerfile, '.'],
|
||||
args: [...prefix, 'build', ...buildArgs, '-t', image, '-f', dockerfile, '.'],
|
||||
cwd: contextDir,
|
||||
append,
|
||||
onProcess: (child) => this.activeProcesses.set(job.id, child),
|
||||
@@ -340,7 +359,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
await runCommand({
|
||||
jobId: job.id,
|
||||
command: this.configService.get<string>('DOCKER_BIN', 'docker'),
|
||||
args: ['build', '-t', image, '-f', dockerfile, '.'],
|
||||
args: ['build', ...buildArgs, '-t', image, '-f', dockerfile, '.'],
|
||||
cwd: contextDir,
|
||||
append,
|
||||
onProcess: (child) => this.activeProcesses.set(job.id, child),
|
||||
@@ -428,11 +447,13 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
const destination = path.join(artifactDir, destinationName);
|
||||
await fs.copyFile(artifact, destination);
|
||||
|
||||
const artifactSha256 = await sha256File(artifact);
|
||||
const uploadedArtifact = await this.uploadArtifactIfConfigured(
|
||||
job,
|
||||
destination,
|
||||
destinationName,
|
||||
artifactVersion,
|
||||
artifactSha256,
|
||||
append,
|
||||
);
|
||||
const publicBaseUrl = this.configService.get<string>('BUILD_ARTIFACT_BASE_URL');
|
||||
@@ -443,9 +464,10 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
await this.prisma.buildJob.update({
|
||||
where: { id: job.id },
|
||||
data: { artifact: artifactValue },
|
||||
data: { artifact: artifactValue, artifactSha256 },
|
||||
});
|
||||
job.artifact = artifactValue;
|
||||
job.artifactSha256 = artifactSha256;
|
||||
|
||||
await append(`[artifact] found ${path.relative(workDir, artifact)}`);
|
||||
await append(`[artifact] copied to ${artifactValue}`);
|
||||
@@ -456,6 +478,7 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
artifactPath: string,
|
||||
artifactName: string,
|
||||
artifactVersion: string | null,
|
||||
sha256: string,
|
||||
append: (line: string) => Promise<void>,
|
||||
) {
|
||||
const bucket = this.configService.get<string>('R2_BUCKET');
|
||||
@@ -469,7 +492,6 @@ export class BuildRunnerService implements OnModuleInit, OnModuleDestroy {
|
||||
|
||||
const key = this.createArtifactObjectKey(job, artifactName, artifactVersion);
|
||||
const stat = await fs.stat(artifactPath);
|
||||
const sha256 = await sha256File(artifactPath);
|
||||
const client = this.getR2Client(accessKeyId, secretAccessKey);
|
||||
|
||||
await append(`[r2] upload ${key}`);
|
||||
|
||||
+36
-2
@@ -1,4 +1,5 @@
|
||||
import { ArrayNotEmpty, IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, IsUUID, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { ArrayNotEmpty, IsArray, IsBoolean, IsEnum, IsInt, IsOptional, IsString, IsUUID, Min, ValidateNested } from 'class-validator';
|
||||
import { AppStatus, ComponentType } from './app-enums';
|
||||
|
||||
export class CreateAppDto {
|
||||
@@ -195,9 +196,37 @@ export class CreateAppReleaseDto {
|
||||
buildJobIds!: string[];
|
||||
}
|
||||
|
||||
export class DeploymentResourceLimitsDto {
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
replicas?: number;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
cpuRequest?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
cpuLimit?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
memoryRequest?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
memoryLimit?: string;
|
||||
}
|
||||
|
||||
export class CreateDeploymentJobDto {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
releaseId!: string;
|
||||
releaseId?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
buildJobId?: string;
|
||||
|
||||
@IsString()
|
||||
environment!: string;
|
||||
@@ -208,6 +237,11 @@ export class CreateDeploymentJobDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
updateLauncherAppVersion?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => DeploymentResourceLimitsDto)
|
||||
resources?: DeploymentResourceLimitsDto;
|
||||
}
|
||||
|
||||
export class CreateRuntimeEnvProfileDto {
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
module.exports = { ...require('.') }
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
module.exports = { ...require('#main-entry-point') }
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export * from "./default"
|
||||
File diff suppressed because one or more lines are too long
@@ -1,217 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.19.3
|
||||
* Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.19.3",
|
||||
engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
email: 'email',
|
||||
passwordHash: 'passwordHash',
|
||||
name: 'name',
|
||||
role: 'role',
|
||||
isActive: 'isActive',
|
||||
lastLoginAt: 'lastLoginAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LicenseScalarFieldEnum = {
|
||||
id: 'id',
|
||||
code: 'code',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
defaultDurationDays: 'defaultDurationDays',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.UserLicenseScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
licenseId: 'licenseId',
|
||||
startsAt: 'startsAt',
|
||||
expiresAt: 'expiresAt',
|
||||
assignedById: 'assignedById',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
exports.UserRole = exports.$Enums.UserRole = {
|
||||
ADMIN: 'ADMIN',
|
||||
USER: 'USER'
|
||||
};
|
||||
|
||||
exports.LicenseCode = exports.$Enums.LicenseCode = {
|
||||
FREE: 'FREE',
|
||||
EDUCATION: 'EDUCATION',
|
||||
PROFESSIONAL: 'PROFESSIONAL'
|
||||
};
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
User: 'User',
|
||||
License: 'License',
|
||||
UserLicense: 'UserLicense'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
Vendored
-6218
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,183 +0,0 @@
|
||||
{
|
||||
"name": "prisma-client-378612c311cf1c6fac598c21e6ea51068a0548bfbc7fdc08b65098bb7a2e5523",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "default.js",
|
||||
"exports": {
|
||||
"./client": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
},
|
||||
"./react-native": {
|
||||
"types": "./react-native.d.ts",
|
||||
"require": "./react-native.js",
|
||||
"import": "./react-native.js",
|
||||
"default": "./react-native.js"
|
||||
},
|
||||
"./extension": {
|
||||
"types": "./extension.d.ts",
|
||||
"require": "./extension.js",
|
||||
"import": "./extension.js",
|
||||
"default": "./extension.js"
|
||||
},
|
||||
"./index-browser": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index-browser.js",
|
||||
"import": "./index-browser.js",
|
||||
"default": "./index-browser.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index.js",
|
||||
"import": "./index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./wasm": {
|
||||
"types": "./wasm.d.ts",
|
||||
"require": "./wasm.js",
|
||||
"import": "./wasm.mjs",
|
||||
"default": "./wasm.mjs"
|
||||
},
|
||||
"./runtime/client": {
|
||||
"types": "./runtime/client.d.ts",
|
||||
"node": {
|
||||
"require": "./runtime/client.js",
|
||||
"default": "./runtime/client.js"
|
||||
},
|
||||
"require": "./runtime/client.js",
|
||||
"import": "./runtime/client.mjs",
|
||||
"default": "./runtime/client.mjs"
|
||||
},
|
||||
"./runtime/library": {
|
||||
"types": "./runtime/library.d.ts",
|
||||
"require": "./runtime/library.js",
|
||||
"import": "./runtime/library.mjs",
|
||||
"default": "./runtime/library.mjs"
|
||||
},
|
||||
"./runtime/binary": {
|
||||
"types": "./runtime/binary.d.ts",
|
||||
"require": "./runtime/binary.js",
|
||||
"import": "./runtime/binary.mjs",
|
||||
"default": "./runtime/binary.mjs"
|
||||
},
|
||||
"./runtime/wasm-engine-edge": {
|
||||
"types": "./runtime/wasm-engine-edge.d.ts",
|
||||
"require": "./runtime/wasm-engine-edge.js",
|
||||
"import": "./runtime/wasm-engine-edge.mjs",
|
||||
"default": "./runtime/wasm-engine-edge.mjs"
|
||||
},
|
||||
"./runtime/wasm-compiler-edge": {
|
||||
"types": "./runtime/wasm-compiler-edge.d.ts",
|
||||
"require": "./runtime/wasm-compiler-edge.js",
|
||||
"import": "./runtime/wasm-compiler-edge.mjs",
|
||||
"default": "./runtime/wasm-compiler-edge.mjs"
|
||||
},
|
||||
"./runtime/edge": {
|
||||
"types": "./runtime/edge.d.ts",
|
||||
"require": "./runtime/edge.js",
|
||||
"import": "./runtime/edge-esm.js",
|
||||
"default": "./runtime/edge-esm.js"
|
||||
},
|
||||
"./runtime/react-native": {
|
||||
"types": "./runtime/react-native.d.ts",
|
||||
"require": "./runtime/react-native.js",
|
||||
"import": "./runtime/react-native.js",
|
||||
"default": "./runtime/react-native.js"
|
||||
},
|
||||
"./runtime/index-browser": {
|
||||
"types": "./runtime/index-browser.d.ts",
|
||||
"require": "./runtime/index-browser.js",
|
||||
"import": "./runtime/index-browser.mjs",
|
||||
"default": "./runtime/index-browser.mjs"
|
||||
},
|
||||
"./generator-build": {
|
||||
"require": "./generator-build/index.js",
|
||||
"import": "./generator-build/index.js",
|
||||
"default": "./generator-build/index.js"
|
||||
},
|
||||
"./sql": {
|
||||
"require": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.js",
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.mjs",
|
||||
"default": "./sql.mjs"
|
||||
},
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "6.19.3",
|
||||
"sideEffects": false,
|
||||
"imports": {
|
||||
"#wasm-engine-loader": {
|
||||
"edge-light": "./wasm-edge-light-loader.mjs",
|
||||
"workerd": "./wasm-worker-loader.mjs",
|
||||
"worker": "./wasm-worker-loader.mjs",
|
||||
"default": "./wasm-worker-loader.mjs"
|
||||
},
|
||||
"#main-entry-point": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,370 +0,0 @@
|
||||
declare class AnyNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
declare type Args<T, F extends Operation> = T extends {
|
||||
[K: symbol]: {
|
||||
types: {
|
||||
operations: {
|
||||
[K in F]: {
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} ? T[symbol]['types']['operations'][F]['args'] : any;
|
||||
|
||||
declare class DbNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
export declare function Decimal(n: Decimal.Value): Decimal;
|
||||
|
||||
export declare namespace Decimal {
|
||||
export type Constructor = typeof Decimal;
|
||||
export type Instance = Decimal;
|
||||
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
export type Modulo = Rounding | 9;
|
||||
export type Value = string | number | Decimal;
|
||||
|
||||
// http://mikemcl.github.io/decimal.js/#constructor-properties
|
||||
export interface Config {
|
||||
precision?: number;
|
||||
rounding?: Rounding;
|
||||
toExpNeg?: number;
|
||||
toExpPos?: number;
|
||||
minE?: number;
|
||||
maxE?: number;
|
||||
crypto?: boolean;
|
||||
modulo?: Modulo;
|
||||
defaults?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Decimal {
|
||||
readonly d: number[];
|
||||
readonly e: number;
|
||||
readonly s: number;
|
||||
|
||||
constructor(n: Decimal.Value);
|
||||
|
||||
absoluteValue(): Decimal;
|
||||
abs(): Decimal;
|
||||
|
||||
ceil(): Decimal;
|
||||
|
||||
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
|
||||
comparedTo(n: Decimal.Value): number;
|
||||
cmp(n: Decimal.Value): number;
|
||||
|
||||
cosine(): Decimal;
|
||||
cos(): Decimal;
|
||||
|
||||
cubeRoot(): Decimal;
|
||||
cbrt(): Decimal;
|
||||
|
||||
decimalPlaces(): number;
|
||||
dp(): number;
|
||||
|
||||
dividedBy(n: Decimal.Value): Decimal;
|
||||
div(n: Decimal.Value): Decimal;
|
||||
|
||||
dividedToIntegerBy(n: Decimal.Value): Decimal;
|
||||
divToInt(n: Decimal.Value): Decimal;
|
||||
|
||||
equals(n: Decimal.Value): boolean;
|
||||
eq(n: Decimal.Value): boolean;
|
||||
|
||||
floor(): Decimal;
|
||||
|
||||
greaterThan(n: Decimal.Value): boolean;
|
||||
gt(n: Decimal.Value): boolean;
|
||||
|
||||
greaterThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
gte(n: Decimal.Value): boolean;
|
||||
|
||||
hyperbolicCosine(): Decimal;
|
||||
cosh(): Decimal;
|
||||
|
||||
hyperbolicSine(): Decimal;
|
||||
sinh(): Decimal;
|
||||
|
||||
hyperbolicTangent(): Decimal;
|
||||
tanh(): Decimal;
|
||||
|
||||
inverseCosine(): Decimal;
|
||||
acos(): Decimal;
|
||||
|
||||
inverseHyperbolicCosine(): Decimal;
|
||||
acosh(): Decimal;
|
||||
|
||||
inverseHyperbolicSine(): Decimal;
|
||||
asinh(): Decimal;
|
||||
|
||||
inverseHyperbolicTangent(): Decimal;
|
||||
atanh(): Decimal;
|
||||
|
||||
inverseSine(): Decimal;
|
||||
asin(): Decimal;
|
||||
|
||||
inverseTangent(): Decimal;
|
||||
atan(): Decimal;
|
||||
|
||||
isFinite(): boolean;
|
||||
|
||||
isInteger(): boolean;
|
||||
isInt(): boolean;
|
||||
|
||||
isNaN(): boolean;
|
||||
|
||||
isNegative(): boolean;
|
||||
isNeg(): boolean;
|
||||
|
||||
isPositive(): boolean;
|
||||
isPos(): boolean;
|
||||
|
||||
isZero(): boolean;
|
||||
|
||||
lessThan(n: Decimal.Value): boolean;
|
||||
lt(n: Decimal.Value): boolean;
|
||||
|
||||
lessThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
lte(n: Decimal.Value): boolean;
|
||||
|
||||
logarithm(n?: Decimal.Value): Decimal;
|
||||
log(n?: Decimal.Value): Decimal;
|
||||
|
||||
minus(n: Decimal.Value): Decimal;
|
||||
sub(n: Decimal.Value): Decimal;
|
||||
|
||||
modulo(n: Decimal.Value): Decimal;
|
||||
mod(n: Decimal.Value): Decimal;
|
||||
|
||||
naturalExponential(): Decimal;
|
||||
exp(): Decimal;
|
||||
|
||||
naturalLogarithm(): Decimal;
|
||||
ln(): Decimal;
|
||||
|
||||
negated(): Decimal;
|
||||
neg(): Decimal;
|
||||
|
||||
plus(n: Decimal.Value): Decimal;
|
||||
add(n: Decimal.Value): Decimal;
|
||||
|
||||
precision(includeZeros?: boolean): number;
|
||||
sd(includeZeros?: boolean): number;
|
||||
|
||||
round(): Decimal;
|
||||
|
||||
sine() : Decimal;
|
||||
sin() : Decimal;
|
||||
|
||||
squareRoot(): Decimal;
|
||||
sqrt(): Decimal;
|
||||
|
||||
tangent() : Decimal;
|
||||
tan() : Decimal;
|
||||
|
||||
times(n: Decimal.Value): Decimal;
|
||||
mul(n: Decimal.Value) : Decimal;
|
||||
|
||||
toBinary(significantDigits?: number): string;
|
||||
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toDecimalPlaces(decimalPlaces?: number): Decimal;
|
||||
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
toDP(decimalPlaces?: number): Decimal;
|
||||
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toExponential(decimalPlaces?: number): string;
|
||||
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFixed(decimalPlaces?: number): string;
|
||||
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFraction(max_denominator?: Decimal.Value): Decimal[];
|
||||
|
||||
toHexadecimal(significantDigits?: number): string;
|
||||
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
toHex(significantDigits?: number): string;
|
||||
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
|
||||
|
||||
toJSON(): string;
|
||||
|
||||
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
|
||||
|
||||
toNumber(): number;
|
||||
|
||||
toOctal(significantDigits?: number): string;
|
||||
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toPower(n: Decimal.Value): Decimal;
|
||||
pow(n: Decimal.Value): Decimal;
|
||||
|
||||
toPrecision(significantDigits?: number): string;
|
||||
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toSignificantDigits(significantDigits?: number): Decimal;
|
||||
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
toSD(significantDigits?: number): Decimal;
|
||||
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toString(): string;
|
||||
|
||||
truncated(): Decimal;
|
||||
trunc(): Decimal;
|
||||
|
||||
valueOf(): string;
|
||||
|
||||
static abs(n: Decimal.Value): Decimal;
|
||||
static acos(n: Decimal.Value): Decimal;
|
||||
static acosh(n: Decimal.Value): Decimal;
|
||||
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static asin(n: Decimal.Value): Decimal;
|
||||
static asinh(n: Decimal.Value): Decimal;
|
||||
static atan(n: Decimal.Value): Decimal;
|
||||
static atanh(n: Decimal.Value): Decimal;
|
||||
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
|
||||
static cbrt(n: Decimal.Value): Decimal;
|
||||
static ceil(n: Decimal.Value): Decimal;
|
||||
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
static clone(object?: Decimal.Config): Decimal.Constructor;
|
||||
static config(object: Decimal.Config): Decimal.Constructor;
|
||||
static cos(n: Decimal.Value): Decimal;
|
||||
static cosh(n: Decimal.Value): Decimal;
|
||||
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static exp(n: Decimal.Value): Decimal;
|
||||
static floor(n: Decimal.Value): Decimal;
|
||||
static hypot(...n: Decimal.Value[]): Decimal;
|
||||
static isDecimal(object: any): object is Decimal;
|
||||
static ln(n: Decimal.Value): Decimal;
|
||||
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
|
||||
static log2(n: Decimal.Value): Decimal;
|
||||
static log10(n: Decimal.Value): Decimal;
|
||||
static max(...n: Decimal.Value[]): Decimal;
|
||||
static min(...n: Decimal.Value[]): Decimal;
|
||||
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static noConflict(): Decimal.Constructor; // Browser only
|
||||
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
|
||||
static random(significantDigits?: number): Decimal;
|
||||
static round(n: Decimal.Value): Decimal;
|
||||
static set(object: Decimal.Config): Decimal.Constructor;
|
||||
static sign(n: Decimal.Value): number;
|
||||
static sin(n: Decimal.Value): Decimal;
|
||||
static sinh(n: Decimal.Value): Decimal;
|
||||
static sqrt(n: Decimal.Value): Decimal;
|
||||
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static sum(...n: Decimal.Value[]): Decimal;
|
||||
static tan(n: Decimal.Value): Decimal;
|
||||
static tanh(n: Decimal.Value): Decimal;
|
||||
static trunc(n: Decimal.Value): Decimal;
|
||||
|
||||
static readonly default?: Decimal.Constructor;
|
||||
static readonly Decimal?: Decimal.Constructor;
|
||||
|
||||
static readonly precision: number;
|
||||
static readonly rounding: Decimal.Rounding;
|
||||
static readonly toExpNeg: number;
|
||||
static readonly toExpPos: number;
|
||||
static readonly minE: number;
|
||||
static readonly maxE: number;
|
||||
static readonly crypto: boolean;
|
||||
static readonly modulo: Decimal.Modulo;
|
||||
|
||||
static readonly ROUND_UP: 0;
|
||||
static readonly ROUND_DOWN: 1;
|
||||
static readonly ROUND_CEIL: 2;
|
||||
static readonly ROUND_FLOOR: 3;
|
||||
static readonly ROUND_HALF_UP: 4;
|
||||
static readonly ROUND_HALF_DOWN: 5;
|
||||
static readonly ROUND_HALF_EVEN: 6;
|
||||
static readonly ROUND_HALF_CEIL: 7;
|
||||
static readonly ROUND_HALF_FLOOR: 8;
|
||||
static readonly EUCLID: 9;
|
||||
}
|
||||
|
||||
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
|
||||
[K in keyof A]: Exact<A[K], W[K]>;
|
||||
} : W) : never) | (A extends Narrowable ? A : never);
|
||||
|
||||
export declare function getRuntime(): GetRuntimeOutput;
|
||||
|
||||
declare type GetRuntimeOutput = {
|
||||
id: RuntimeName;
|
||||
prettyName: string;
|
||||
isEdge: boolean;
|
||||
};
|
||||
|
||||
declare class JsonNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates more strict variant of an enum which, unlike regular enum,
|
||||
* throws on non-existing property access. This can be useful in following situations:
|
||||
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
|
||||
* - enum values are generated dynamically from DMMF.
|
||||
*
|
||||
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
|
||||
* will result in `undefined` value being used, which will be accepted. Using strict enum
|
||||
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
|
||||
*
|
||||
* Note: if you need to check for existence of a value in the enum you can still use either
|
||||
* `in` operator or `hasOwnProperty` function.
|
||||
*
|
||||
* @param definition
|
||||
* @returns
|
||||
*/
|
||||
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
|
||||
|
||||
declare type Narrowable = string | number | bigint | boolean | [];
|
||||
|
||||
declare class NullTypesEnumValue extends ObjectEnumValue {
|
||||
_getNamespace(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for unique values of object-valued enums.
|
||||
*/
|
||||
declare abstract class ObjectEnumValue {
|
||||
constructor(arg?: symbol);
|
||||
abstract _getNamespace(): string;
|
||||
_getName(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export declare const objectEnumValues: {
|
||||
classes: {
|
||||
DbNull: typeof DbNull;
|
||||
JsonNull: typeof JsonNull;
|
||||
AnyNull: typeof AnyNull;
|
||||
};
|
||||
instances: {
|
||||
DbNull: DbNull;
|
||||
JsonNull: JsonNull;
|
||||
AnyNull: AnyNull;
|
||||
};
|
||||
};
|
||||
|
||||
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
|
||||
|
||||
declare namespace Public {
|
||||
export {
|
||||
validator
|
||||
}
|
||||
}
|
||||
export { Public }
|
||||
|
||||
declare type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '';
|
||||
|
||||
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
|
||||
|
||||
export { }
|
||||
File diff suppressed because one or more lines are too long
-3982
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,66 +0,0 @@
|
||||
generator authClient {
|
||||
provider = "prisma-client-js"
|
||||
output = "../src/generated/auth-client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("AUTH_DATABASE_URL")
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
USER
|
||||
}
|
||||
|
||||
enum LicenseCode {
|
||||
FREE
|
||||
EDUCATION
|
||||
PROFESSIONAL
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
email String @unique
|
||||
passwordHash String @map("password_hash")
|
||||
name String?
|
||||
role UserRole @default(USER)
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
lastLoginAt DateTime? @map("last_login_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
userLicenses UserLicense[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
model License {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code LicenseCode @unique
|
||||
name String
|
||||
description String?
|
||||
defaultDurationDays Int? @default(365) @map("default_duration_days")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
userLicenses UserLicense[]
|
||||
|
||||
@@index([isActive])
|
||||
@@map("licenses")
|
||||
}
|
||||
|
||||
model UserLicense {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
userId String @map("user_id") @db.Uuid
|
||||
licenseId String @map("license_id") @db.Uuid
|
||||
startsAt DateTime @default(now()) @map("starts_at") @db.Timestamptz(3)
|
||||
expiresAt DateTime? @map("expires_at") @db.Timestamptz(3)
|
||||
assignedById String? @map("assigned_by") @db.Uuid
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
license License @relation(fields: [licenseId], references: [id], onDelete: Restrict)
|
||||
|
||||
@@index([userId, startsAt])
|
||||
@@index([licenseId])
|
||||
@@map("user_licenses")
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_engine_bg.wasm?module')
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_engine_bg.wasm')
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export * from "./default"
|
||||
@@ -1,238 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
PrismaClientKnownRequestError,
|
||||
PrismaClientUnknownRequestError,
|
||||
PrismaClientRustPanicError,
|
||||
PrismaClientInitializationError,
|
||||
PrismaClientValidationError,
|
||||
getPrismaClient,
|
||||
sqltag,
|
||||
empty,
|
||||
join,
|
||||
raw,
|
||||
skip,
|
||||
Decimal,
|
||||
Debug,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Extensions,
|
||||
warnOnce,
|
||||
defineDmmfProperty,
|
||||
Public,
|
||||
getRuntime,
|
||||
createParam,
|
||||
} = require('./runtime/wasm-engine-edge.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.19.3
|
||||
* Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.19.3",
|
||||
engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
|
||||
Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError
|
||||
Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError
|
||||
Prisma.PrismaClientInitializationError = PrismaClientInitializationError
|
||||
Prisma.PrismaClientValidationError = PrismaClientValidationError
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = sqltag
|
||||
Prisma.empty = empty
|
||||
Prisma.join = join
|
||||
Prisma.raw = raw
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = Extensions.getExtensionContext
|
||||
Prisma.defineExtension = Extensions.defineExtension
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.UserScalarFieldEnum = {
|
||||
id: 'id',
|
||||
email: 'email',
|
||||
passwordHash: 'passwordHash',
|
||||
name: 'name',
|
||||
role: 'role',
|
||||
isActive: 'isActive',
|
||||
lastLoginAt: 'lastLoginAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LicenseScalarFieldEnum = {
|
||||
id: 'id',
|
||||
code: 'code',
|
||||
name: 'name',
|
||||
description: 'description',
|
||||
defaultDurationDays: 'defaultDurationDays',
|
||||
isActive: 'isActive',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.UserLicenseScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
licenseId: 'licenseId',
|
||||
startsAt: 'startsAt',
|
||||
expiresAt: 'expiresAt',
|
||||
assignedById: 'assignedById',
|
||||
createdAt: 'createdAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
exports.UserRole = exports.$Enums.UserRole = {
|
||||
ADMIN: 'ADMIN',
|
||||
USER: 'USER'
|
||||
};
|
||||
|
||||
exports.LicenseCode = exports.$Enums.LicenseCode = {
|
||||
FREE: 'FREE',
|
||||
EDUCATION: 'EDUCATION',
|
||||
PROFESSIONAL: 'PROFESSIONAL'
|
||||
};
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
User: 'User',
|
||||
License: 'License',
|
||||
UserLicense: 'UserLicense'
|
||||
};
|
||||
/**
|
||||
* Create the Client
|
||||
*/
|
||||
const config = {
|
||||
"generator": {
|
||||
"name": "authClient",
|
||||
"provider": {
|
||||
"fromEnvVar": null,
|
||||
"value": "prisma-client-js"
|
||||
},
|
||||
"output": {
|
||||
"value": "/home/chyoo/tmp/atnmy-stdo-v2/atnmy-stdo-adm-v2-be/src/generated/auth-client",
|
||||
"fromEnvVar": null
|
||||
},
|
||||
"config": {
|
||||
"engineType": "library"
|
||||
},
|
||||
"binaryTargets": [
|
||||
{
|
||||
"fromEnvVar": null,
|
||||
"value": "debian-openssl-3.0.x",
|
||||
"native": true
|
||||
}
|
||||
],
|
||||
"previewFeatures": [],
|
||||
"sourceFilePath": "/home/chyoo/tmp/atnmy-stdo-v2/atnmy-stdo-adm-v2-be/prisma/auth.schema.prisma",
|
||||
"isCustomOutput": true
|
||||
},
|
||||
"relativeEnvPaths": {
|
||||
"rootEnvPath": null,
|
||||
"schemaEnvPath": "../../../.env"
|
||||
},
|
||||
"relativePath": "../../../prisma",
|
||||
"clientVersion": "6.19.3",
|
||||
"engineVersion": "c2990dca591cba766e3b7ef5d9e8a84796e47ab7",
|
||||
"datasourceNames": [
|
||||
"db"
|
||||
],
|
||||
"activeProvider": "postgresql",
|
||||
"postinstall": false,
|
||||
"inlineDatasources": {
|
||||
"db": {
|
||||
"url": {
|
||||
"fromEnvVar": "AUTH_DATABASE_URL",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"inlineSchema": "generator authClient {\n provider = \"prisma-client-js\"\n output = \"../src/generated/auth-client\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"AUTH_DATABASE_URL\")\n}\n\nenum UserRole {\n ADMIN\n USER\n}\n\nenum LicenseCode {\n FREE\n EDUCATION\n PROFESSIONAL\n}\n\nmodel User {\n id String @id @default(uuid()) @db.Uuid\n email String @unique\n passwordHash String @map(\"password_hash\")\n name String?\n role UserRole @default(USER)\n isActive Boolean @default(true) @map(\"is_active\")\n lastLoginAt DateTime? @map(\"last_login_at\") @db.Timestamptz(3)\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n updatedAt DateTime @updatedAt @map(\"updated_at\") @db.Timestamptz(3)\n userLicenses UserLicense[]\n\n @@map(\"users\")\n}\n\nmodel License {\n id String @id @default(uuid()) @db.Uuid\n code LicenseCode @unique\n name String\n description String?\n defaultDurationDays Int? @default(365) @map(\"default_duration_days\")\n isActive Boolean @default(true) @map(\"is_active\")\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n updatedAt DateTime @updatedAt @map(\"updated_at\") @db.Timestamptz(3)\n userLicenses UserLicense[]\n\n @@index([isActive])\n @@map(\"licenses\")\n}\n\nmodel UserLicense {\n id String @id @default(uuid()) @db.Uuid\n userId String @map(\"user_id\") @db.Uuid\n licenseId String @map(\"license_id\") @db.Uuid\n startsAt DateTime @default(now()) @map(\"starts_at\") @db.Timestamptz(3)\n expiresAt DateTime? @map(\"expires_at\") @db.Timestamptz(3)\n assignedById String? @map(\"assigned_by\") @db.Uuid\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n license License @relation(fields: [licenseId], references: [id], onDelete: Restrict)\n\n @@index([userId, startsAt])\n @@index([licenseId])\n @@map(\"user_licenses\")\n}\n",
|
||||
"inlineSchemaHash": "b41ead22c04f404adbe239bd44c2751b9ed9adf3c5b7b7013be05252086f79d7",
|
||||
"copyEngine": true
|
||||
}
|
||||
config.dirname = '/'
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"passwordHash\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"password_hash\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"UserRole\"},{\"name\":\"isActive\",\"kind\":\"scalar\",\"type\":\"Boolean\",\"dbName\":\"is_active\"},{\"name\":\"lastLoginAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"last_login_at\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"updated_at\"},{\"name\":\"userLicenses\",\"kind\":\"object\",\"type\":\"UserLicense\",\"relationName\":\"UserToUserLicense\"}],\"dbName\":\"users\"},\"License\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"code\",\"kind\":\"enum\",\"type\":\"LicenseCode\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"defaultDurationDays\",\"kind\":\"scalar\",\"type\":\"Int\",\"dbName\":\"default_duration_days\"},{\"name\":\"isActive\",\"kind\":\"scalar\",\"type\":\"Boolean\",\"dbName\":\"is_active\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"updated_at\"},{\"name\":\"userLicenses\",\"kind\":\"object\",\"type\":\"UserLicense\",\"relationName\":\"LicenseToUserLicense\"}],\"dbName\":\"licenses\"},\"UserLicense\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"user_id\"},{\"name\":\"licenseId\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"license_id\"},{\"name\":\"startsAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"starts_at\"},{\"name\":\"expiresAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"expires_at\"},{\"name\":\"assignedById\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"assigned_by\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"UserToUserLicense\"},{\"name\":\"license\",\"kind\":\"object\",\"type\":\"License\",\"relationName\":\"LicenseToUserLicense\"}],\"dbName\":\"user_licenses\"}},\"enums\":{},\"types\":{}}")
|
||||
defineDmmfProperty(exports.Prisma, config.runtimeDataModel)
|
||||
config.engineWasm = {
|
||||
getRuntime: async () => require('./query_engine_bg.js'),
|
||||
getQueryEngineWasmModule: async () => {
|
||||
const loader = (await import('#wasm-engine-loader')).default
|
||||
const engine = (await loader).default
|
||||
return engine
|
||||
}
|
||||
}
|
||||
config.compilerWasm = undefined
|
||||
|
||||
config.injectableEdgeEnv = () => ({
|
||||
parsed: {
|
||||
AUTH_DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['AUTH_DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.AUTH_DATABASE_URL || undefined
|
||||
}
|
||||
})
|
||||
|
||||
if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) {
|
||||
Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined)
|
||||
}
|
||||
|
||||
const PrismaClient = getPrismaClient(config)
|
||||
exports.PrismaClient = PrismaClient
|
||||
Object.assign(exports, Prisma)
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
module.exports = { ...require('.') }
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./index"
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
module.exports = { ...require('#main-entry-point') }
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./default"
|
||||
File diff suppressed because one or more lines are too long
@@ -1,233 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
Decimal,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Public,
|
||||
getRuntime,
|
||||
skip
|
||||
} = require('./runtime/index-browser.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.19.3
|
||||
* Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.19.3",
|
||||
engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientKnownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)};
|
||||
Prisma.PrismaClientUnknownRequestError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientUnknownRequestError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientRustPanicError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientRustPanicError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientInitializationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientInitializationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.PrismaClientValidationError = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`PrismaClientValidationError is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`sqltag is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.empty = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`empty is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.join = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`join is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.raw = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`raw is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.getExtensionContext is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
Prisma.defineExtension = () => {
|
||||
const runtimeName = getRuntime().prettyName;
|
||||
throw new Error(`Extensions.defineExtension is unable to run in this browser environment, or has been bundled for the browser (running in ${runtimeName}).
|
||||
In case this error is unexpected for you, please report it in https://pris.ly/prisma-prisma-bug-report`,
|
||||
)}
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.LauncherNoticeScalarFieldEnum = {
|
||||
id: 'id',
|
||||
appKey: 'appKey',
|
||||
title: 'title',
|
||||
body: 'body',
|
||||
linkUrl: 'linkUrl',
|
||||
isActive: 'isActive',
|
||||
startsAt: 'startsAt',
|
||||
endsAt: 'endsAt',
|
||||
priority: 'priority',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.ProvisionedDeviceScalarFieldEnum = {
|
||||
id: 'id',
|
||||
accountEmail: 'accountEmail',
|
||||
authUserId: 'authUserId',
|
||||
hostname: 'hostname',
|
||||
tailscaleHostname: 'tailscaleHostname',
|
||||
sshUser: 'sshUser',
|
||||
workspaceRoot: 'workspaceRoot',
|
||||
usageType: 'usageType',
|
||||
os: 'os',
|
||||
arch: 'arch',
|
||||
kernel: 'kernel',
|
||||
distro: 'distro',
|
||||
device: 'device',
|
||||
installedAt: 'installedAt',
|
||||
lastProvisionedAt: 'lastProvisionedAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LauncherSshKeyScalarFieldEnum = {
|
||||
id: 'id',
|
||||
accountEmail: 'accountEmail',
|
||||
authUserId: 'authUserId',
|
||||
publicKey: 'publicKey',
|
||||
publicKeyHash: 'publicKeyHash',
|
||||
keyType: 'keyType',
|
||||
label: 'label',
|
||||
lastProvisionedAt: 'lastProvisionedAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.NullableJsonNullValueInput = {
|
||||
DbNull: Prisma.DbNull,
|
||||
JsonNull: Prisma.JsonNull
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
|
||||
exports.Prisma.JsonNullValueFilter = {
|
||||
DbNull: Prisma.DbNull,
|
||||
JsonNull: Prisma.JsonNull,
|
||||
AnyNull: Prisma.AnyNull
|
||||
};
|
||||
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
LauncherNotice: 'LauncherNotice',
|
||||
ProvisionedDevice: 'ProvisionedDevice',
|
||||
LauncherSshKey: 'LauncherSshKey'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stub Prisma Client that will error at runtime if called.
|
||||
*/
|
||||
class PrismaClient {
|
||||
constructor() {
|
||||
return new Proxy(this, {
|
||||
get(target, prop) {
|
||||
let message
|
||||
const runtime = getRuntime()
|
||||
if (runtime.isEdge) {
|
||||
message = `PrismaClient is not configured to run in ${runtime.prettyName}. In order to run Prisma Client on edge runtime, either:
|
||||
- Use Prisma Accelerate: https://pris.ly/d/accelerate
|
||||
- Use Driver Adapters: https://pris.ly/d/driver-adapters
|
||||
`;
|
||||
} else {
|
||||
message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in `' + runtime.prettyName + '`).'
|
||||
}
|
||||
|
||||
message += `
|
||||
If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report`
|
||||
|
||||
throw new Error(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.PrismaClient = PrismaClient
|
||||
|
||||
Object.assign(exports, Prisma)
|
||||
-5870
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,183 +0,0 @@
|
||||
{
|
||||
"name": "prisma-client-2cc4fd701019d0254ce12699ae25121c6ed85eba27006e31abbdac7779ae92f0",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"browser": "default.js",
|
||||
"exports": {
|
||||
"./client": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./edge": {
|
||||
"types": "./edge.d.ts",
|
||||
"require": "./edge.js",
|
||||
"import": "./edge.js",
|
||||
"default": "./edge.js"
|
||||
},
|
||||
"./react-native": {
|
||||
"types": "./react-native.d.ts",
|
||||
"require": "./react-native.js",
|
||||
"import": "./react-native.js",
|
||||
"default": "./react-native.js"
|
||||
},
|
||||
"./extension": {
|
||||
"types": "./extension.d.ts",
|
||||
"require": "./extension.js",
|
||||
"import": "./extension.js",
|
||||
"default": "./extension.js"
|
||||
},
|
||||
"./index-browser": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index-browser.js",
|
||||
"import": "./index-browser.js",
|
||||
"default": "./index-browser.js"
|
||||
},
|
||||
"./index": {
|
||||
"types": "./index.d.ts",
|
||||
"require": "./index.js",
|
||||
"import": "./index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"./wasm": {
|
||||
"types": "./wasm.d.ts",
|
||||
"require": "./wasm.js",
|
||||
"import": "./wasm.mjs",
|
||||
"default": "./wasm.mjs"
|
||||
},
|
||||
"./runtime/client": {
|
||||
"types": "./runtime/client.d.ts",
|
||||
"node": {
|
||||
"require": "./runtime/client.js",
|
||||
"default": "./runtime/client.js"
|
||||
},
|
||||
"require": "./runtime/client.js",
|
||||
"import": "./runtime/client.mjs",
|
||||
"default": "./runtime/client.mjs"
|
||||
},
|
||||
"./runtime/library": {
|
||||
"types": "./runtime/library.d.ts",
|
||||
"require": "./runtime/library.js",
|
||||
"import": "./runtime/library.mjs",
|
||||
"default": "./runtime/library.mjs"
|
||||
},
|
||||
"./runtime/binary": {
|
||||
"types": "./runtime/binary.d.ts",
|
||||
"require": "./runtime/binary.js",
|
||||
"import": "./runtime/binary.mjs",
|
||||
"default": "./runtime/binary.mjs"
|
||||
},
|
||||
"./runtime/wasm-engine-edge": {
|
||||
"types": "./runtime/wasm-engine-edge.d.ts",
|
||||
"require": "./runtime/wasm-engine-edge.js",
|
||||
"import": "./runtime/wasm-engine-edge.mjs",
|
||||
"default": "./runtime/wasm-engine-edge.mjs"
|
||||
},
|
||||
"./runtime/wasm-compiler-edge": {
|
||||
"types": "./runtime/wasm-compiler-edge.d.ts",
|
||||
"require": "./runtime/wasm-compiler-edge.js",
|
||||
"import": "./runtime/wasm-compiler-edge.mjs",
|
||||
"default": "./runtime/wasm-compiler-edge.mjs"
|
||||
},
|
||||
"./runtime/edge": {
|
||||
"types": "./runtime/edge.d.ts",
|
||||
"require": "./runtime/edge.js",
|
||||
"import": "./runtime/edge-esm.js",
|
||||
"default": "./runtime/edge-esm.js"
|
||||
},
|
||||
"./runtime/react-native": {
|
||||
"types": "./runtime/react-native.d.ts",
|
||||
"require": "./runtime/react-native.js",
|
||||
"import": "./runtime/react-native.js",
|
||||
"default": "./runtime/react-native.js"
|
||||
},
|
||||
"./runtime/index-browser": {
|
||||
"types": "./runtime/index-browser.d.ts",
|
||||
"require": "./runtime/index-browser.js",
|
||||
"import": "./runtime/index-browser.mjs",
|
||||
"default": "./runtime/index-browser.mjs"
|
||||
},
|
||||
"./generator-build": {
|
||||
"require": "./generator-build/index.js",
|
||||
"import": "./generator-build/index.js",
|
||||
"default": "./generator-build/index.js"
|
||||
},
|
||||
"./sql": {
|
||||
"require": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.js",
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./sql.d.ts",
|
||||
"node": "./sql.mjs",
|
||||
"default": "./sql.mjs"
|
||||
},
|
||||
"default": "./sql.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"version": "6.19.3",
|
||||
"sideEffects": false,
|
||||
"imports": {
|
||||
"#wasm-engine-loader": {
|
||||
"edge-light": "./wasm-edge-light-loader.mjs",
|
||||
"workerd": "./wasm-worker-loader.mjs",
|
||||
"worker": "./wasm-worker-loader.mjs",
|
||||
"default": "./wasm-worker-loader.mjs"
|
||||
},
|
||||
"#main-entry-point": {
|
||||
"require": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"import": {
|
||||
"node": "./index.js",
|
||||
"edge-light": "./wasm.js",
|
||||
"workerd": "./wasm.js",
|
||||
"worker": "./wasm.js",
|
||||
"browser": "./index-browser.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"default": "./index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,370 +0,0 @@
|
||||
declare class AnyNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
declare type Args<T, F extends Operation> = T extends {
|
||||
[K: symbol]: {
|
||||
types: {
|
||||
operations: {
|
||||
[K in F]: {
|
||||
args: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} ? T[symbol]['types']['operations'][F]['args'] : any;
|
||||
|
||||
declare class DbNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
export declare function Decimal(n: Decimal.Value): Decimal;
|
||||
|
||||
export declare namespace Decimal {
|
||||
export type Constructor = typeof Decimal;
|
||||
export type Instance = Decimal;
|
||||
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
|
||||
export type Modulo = Rounding | 9;
|
||||
export type Value = string | number | Decimal;
|
||||
|
||||
// http://mikemcl.github.io/decimal.js/#constructor-properties
|
||||
export interface Config {
|
||||
precision?: number;
|
||||
rounding?: Rounding;
|
||||
toExpNeg?: number;
|
||||
toExpPos?: number;
|
||||
minE?: number;
|
||||
maxE?: number;
|
||||
crypto?: boolean;
|
||||
modulo?: Modulo;
|
||||
defaults?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
export declare class Decimal {
|
||||
readonly d: number[];
|
||||
readonly e: number;
|
||||
readonly s: number;
|
||||
|
||||
constructor(n: Decimal.Value);
|
||||
|
||||
absoluteValue(): Decimal;
|
||||
abs(): Decimal;
|
||||
|
||||
ceil(): Decimal;
|
||||
|
||||
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
|
||||
comparedTo(n: Decimal.Value): number;
|
||||
cmp(n: Decimal.Value): number;
|
||||
|
||||
cosine(): Decimal;
|
||||
cos(): Decimal;
|
||||
|
||||
cubeRoot(): Decimal;
|
||||
cbrt(): Decimal;
|
||||
|
||||
decimalPlaces(): number;
|
||||
dp(): number;
|
||||
|
||||
dividedBy(n: Decimal.Value): Decimal;
|
||||
div(n: Decimal.Value): Decimal;
|
||||
|
||||
dividedToIntegerBy(n: Decimal.Value): Decimal;
|
||||
divToInt(n: Decimal.Value): Decimal;
|
||||
|
||||
equals(n: Decimal.Value): boolean;
|
||||
eq(n: Decimal.Value): boolean;
|
||||
|
||||
floor(): Decimal;
|
||||
|
||||
greaterThan(n: Decimal.Value): boolean;
|
||||
gt(n: Decimal.Value): boolean;
|
||||
|
||||
greaterThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
gte(n: Decimal.Value): boolean;
|
||||
|
||||
hyperbolicCosine(): Decimal;
|
||||
cosh(): Decimal;
|
||||
|
||||
hyperbolicSine(): Decimal;
|
||||
sinh(): Decimal;
|
||||
|
||||
hyperbolicTangent(): Decimal;
|
||||
tanh(): Decimal;
|
||||
|
||||
inverseCosine(): Decimal;
|
||||
acos(): Decimal;
|
||||
|
||||
inverseHyperbolicCosine(): Decimal;
|
||||
acosh(): Decimal;
|
||||
|
||||
inverseHyperbolicSine(): Decimal;
|
||||
asinh(): Decimal;
|
||||
|
||||
inverseHyperbolicTangent(): Decimal;
|
||||
atanh(): Decimal;
|
||||
|
||||
inverseSine(): Decimal;
|
||||
asin(): Decimal;
|
||||
|
||||
inverseTangent(): Decimal;
|
||||
atan(): Decimal;
|
||||
|
||||
isFinite(): boolean;
|
||||
|
||||
isInteger(): boolean;
|
||||
isInt(): boolean;
|
||||
|
||||
isNaN(): boolean;
|
||||
|
||||
isNegative(): boolean;
|
||||
isNeg(): boolean;
|
||||
|
||||
isPositive(): boolean;
|
||||
isPos(): boolean;
|
||||
|
||||
isZero(): boolean;
|
||||
|
||||
lessThan(n: Decimal.Value): boolean;
|
||||
lt(n: Decimal.Value): boolean;
|
||||
|
||||
lessThanOrEqualTo(n: Decimal.Value): boolean;
|
||||
lte(n: Decimal.Value): boolean;
|
||||
|
||||
logarithm(n?: Decimal.Value): Decimal;
|
||||
log(n?: Decimal.Value): Decimal;
|
||||
|
||||
minus(n: Decimal.Value): Decimal;
|
||||
sub(n: Decimal.Value): Decimal;
|
||||
|
||||
modulo(n: Decimal.Value): Decimal;
|
||||
mod(n: Decimal.Value): Decimal;
|
||||
|
||||
naturalExponential(): Decimal;
|
||||
exp(): Decimal;
|
||||
|
||||
naturalLogarithm(): Decimal;
|
||||
ln(): Decimal;
|
||||
|
||||
negated(): Decimal;
|
||||
neg(): Decimal;
|
||||
|
||||
plus(n: Decimal.Value): Decimal;
|
||||
add(n: Decimal.Value): Decimal;
|
||||
|
||||
precision(includeZeros?: boolean): number;
|
||||
sd(includeZeros?: boolean): number;
|
||||
|
||||
round(): Decimal;
|
||||
|
||||
sine() : Decimal;
|
||||
sin() : Decimal;
|
||||
|
||||
squareRoot(): Decimal;
|
||||
sqrt(): Decimal;
|
||||
|
||||
tangent() : Decimal;
|
||||
tan() : Decimal;
|
||||
|
||||
times(n: Decimal.Value): Decimal;
|
||||
mul(n: Decimal.Value) : Decimal;
|
||||
|
||||
toBinary(significantDigits?: number): string;
|
||||
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toDecimalPlaces(decimalPlaces?: number): Decimal;
|
||||
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
toDP(decimalPlaces?: number): Decimal;
|
||||
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toExponential(decimalPlaces?: number): string;
|
||||
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFixed(decimalPlaces?: number): string;
|
||||
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toFraction(max_denominator?: Decimal.Value): Decimal[];
|
||||
|
||||
toHexadecimal(significantDigits?: number): string;
|
||||
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
toHex(significantDigits?: number): string;
|
||||
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
|
||||
|
||||
toJSON(): string;
|
||||
|
||||
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
|
||||
|
||||
toNumber(): number;
|
||||
|
||||
toOctal(significantDigits?: number): string;
|
||||
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toPower(n: Decimal.Value): Decimal;
|
||||
pow(n: Decimal.Value): Decimal;
|
||||
|
||||
toPrecision(significantDigits?: number): string;
|
||||
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
|
||||
|
||||
toSignificantDigits(significantDigits?: number): Decimal;
|
||||
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
toSD(significantDigits?: number): Decimal;
|
||||
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
|
||||
|
||||
toString(): string;
|
||||
|
||||
truncated(): Decimal;
|
||||
trunc(): Decimal;
|
||||
|
||||
valueOf(): string;
|
||||
|
||||
static abs(n: Decimal.Value): Decimal;
|
||||
static acos(n: Decimal.Value): Decimal;
|
||||
static acosh(n: Decimal.Value): Decimal;
|
||||
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static asin(n: Decimal.Value): Decimal;
|
||||
static asinh(n: Decimal.Value): Decimal;
|
||||
static atan(n: Decimal.Value): Decimal;
|
||||
static atanh(n: Decimal.Value): Decimal;
|
||||
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
|
||||
static cbrt(n: Decimal.Value): Decimal;
|
||||
static ceil(n: Decimal.Value): Decimal;
|
||||
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
|
||||
static clone(object?: Decimal.Config): Decimal.Constructor;
|
||||
static config(object: Decimal.Config): Decimal.Constructor;
|
||||
static cos(n: Decimal.Value): Decimal;
|
||||
static cosh(n: Decimal.Value): Decimal;
|
||||
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static exp(n: Decimal.Value): Decimal;
|
||||
static floor(n: Decimal.Value): Decimal;
|
||||
static hypot(...n: Decimal.Value[]): Decimal;
|
||||
static isDecimal(object: any): object is Decimal;
|
||||
static ln(n: Decimal.Value): Decimal;
|
||||
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
|
||||
static log2(n: Decimal.Value): Decimal;
|
||||
static log10(n: Decimal.Value): Decimal;
|
||||
static max(...n: Decimal.Value[]): Decimal;
|
||||
static min(...n: Decimal.Value[]): Decimal;
|
||||
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static noConflict(): Decimal.Constructor; // Browser only
|
||||
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
|
||||
static random(significantDigits?: number): Decimal;
|
||||
static round(n: Decimal.Value): Decimal;
|
||||
static set(object: Decimal.Config): Decimal.Constructor;
|
||||
static sign(n: Decimal.Value): number;
|
||||
static sin(n: Decimal.Value): Decimal;
|
||||
static sinh(n: Decimal.Value): Decimal;
|
||||
static sqrt(n: Decimal.Value): Decimal;
|
||||
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
|
||||
static sum(...n: Decimal.Value[]): Decimal;
|
||||
static tan(n: Decimal.Value): Decimal;
|
||||
static tanh(n: Decimal.Value): Decimal;
|
||||
static trunc(n: Decimal.Value): Decimal;
|
||||
|
||||
static readonly default?: Decimal.Constructor;
|
||||
static readonly Decimal?: Decimal.Constructor;
|
||||
|
||||
static readonly precision: number;
|
||||
static readonly rounding: Decimal.Rounding;
|
||||
static readonly toExpNeg: number;
|
||||
static readonly toExpPos: number;
|
||||
static readonly minE: number;
|
||||
static readonly maxE: number;
|
||||
static readonly crypto: boolean;
|
||||
static readonly modulo: Decimal.Modulo;
|
||||
|
||||
static readonly ROUND_UP: 0;
|
||||
static readonly ROUND_DOWN: 1;
|
||||
static readonly ROUND_CEIL: 2;
|
||||
static readonly ROUND_FLOOR: 3;
|
||||
static readonly ROUND_HALF_UP: 4;
|
||||
static readonly ROUND_HALF_DOWN: 5;
|
||||
static readonly ROUND_HALF_EVEN: 6;
|
||||
static readonly ROUND_HALF_CEIL: 7;
|
||||
static readonly ROUND_HALF_FLOOR: 8;
|
||||
static readonly EUCLID: 9;
|
||||
}
|
||||
|
||||
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
|
||||
[K in keyof A]: Exact<A[K], W[K]>;
|
||||
} : W) : never) | (A extends Narrowable ? A : never);
|
||||
|
||||
export declare function getRuntime(): GetRuntimeOutput;
|
||||
|
||||
declare type GetRuntimeOutput = {
|
||||
id: RuntimeName;
|
||||
prettyName: string;
|
||||
isEdge: boolean;
|
||||
};
|
||||
|
||||
declare class JsonNull extends NullTypesEnumValue {
|
||||
#private;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates more strict variant of an enum which, unlike regular enum,
|
||||
* throws on non-existing property access. This can be useful in following situations:
|
||||
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
|
||||
* - enum values are generated dynamically from DMMF.
|
||||
*
|
||||
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
|
||||
* will result in `undefined` value being used, which will be accepted. Using strict enum
|
||||
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
|
||||
*
|
||||
* Note: if you need to check for existence of a value in the enum you can still use either
|
||||
* `in` operator or `hasOwnProperty` function.
|
||||
*
|
||||
* @param definition
|
||||
* @returns
|
||||
*/
|
||||
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
|
||||
|
||||
declare type Narrowable = string | number | bigint | boolean | [];
|
||||
|
||||
declare class NullTypesEnumValue extends ObjectEnumValue {
|
||||
_getNamespace(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for unique values of object-valued enums.
|
||||
*/
|
||||
declare abstract class ObjectEnumValue {
|
||||
constructor(arg?: symbol);
|
||||
abstract _getNamespace(): string;
|
||||
_getName(): string;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export declare const objectEnumValues: {
|
||||
classes: {
|
||||
DbNull: typeof DbNull;
|
||||
JsonNull: typeof JsonNull;
|
||||
AnyNull: typeof AnyNull;
|
||||
};
|
||||
instances: {
|
||||
DbNull: DbNull;
|
||||
JsonNull: JsonNull;
|
||||
AnyNull: AnyNull;
|
||||
};
|
||||
};
|
||||
|
||||
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'updateManyAndReturn' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
|
||||
|
||||
declare namespace Public {
|
||||
export {
|
||||
validator
|
||||
}
|
||||
}
|
||||
export { Public }
|
||||
|
||||
declare type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '';
|
||||
|
||||
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
|
||||
|
||||
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
|
||||
|
||||
export { }
|
||||
File diff suppressed because one or more lines are too long
-3982
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,68 +0,0 @@
|
||||
generator launcherClient {
|
||||
provider = "prisma-client-js"
|
||||
output = "../src/generated/launcher-client"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("LAUNCHER_DATABASE_URL")
|
||||
}
|
||||
|
||||
model LauncherNotice {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
appKey String @default("login") @map("app_key")
|
||||
title String
|
||||
body String
|
||||
linkUrl String? @map("link_url")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
startsAt DateTime? @map("starts_at") @db.Timestamptz(3)
|
||||
endsAt DateTime? @map("ends_at") @db.Timestamptz(3)
|
||||
priority Int @default(0)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
|
||||
@@index([appKey, isActive, priority])
|
||||
@@map("launcher_notices")
|
||||
}
|
||||
|
||||
model ProvisionedDevice {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
accountEmail String @map("account_email")
|
||||
authUserId String? @map("auth_user_id") @db.Uuid
|
||||
hostname String
|
||||
tailscaleHostname String @map("tailscale_hostname")
|
||||
sshUser String? @map("ssh_user")
|
||||
workspaceRoot String? @map("workspace_root")
|
||||
usageType String @default("personal") @map("usage_type")
|
||||
os String?
|
||||
arch String?
|
||||
kernel String?
|
||||
distro String?
|
||||
device Json?
|
||||
installedAt DateTime @default(now()) @map("installed_at") @db.Timestamptz(3)
|
||||
lastProvisionedAt DateTime @default(now()) @map("last_provisioned_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
|
||||
@@unique([accountEmail, tailscaleHostname])
|
||||
@@index([accountEmail])
|
||||
@@index([tailscaleHostname])
|
||||
@@map("provisioned_devices")
|
||||
}
|
||||
|
||||
model LauncherSshKey {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
accountEmail String @map("account_email")
|
||||
authUserId String? @map("auth_user_id") @db.Uuid
|
||||
publicKey String @map("public_key")
|
||||
publicKeyHash String @map("public_key_hash")
|
||||
keyType String? @map("key_type")
|
||||
label String?
|
||||
lastProvisionedAt DateTime @default(now()) @map("last_provisioned_at") @db.Timestamptz(3)
|
||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
|
||||
updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz(3)
|
||||
|
||||
@@unique([accountEmail, publicKeyHash])
|
||||
@@index([accountEmail])
|
||||
@@map("launcher_ssh_keys")
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_engine_bg.wasm?module')
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
export default import('./query_engine_bg.wasm')
|
||||
-1
@@ -1 +0,0 @@
|
||||
export * from "./default"
|
||||
@@ -1,254 +0,0 @@
|
||||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!!
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const {
|
||||
PrismaClientKnownRequestError,
|
||||
PrismaClientUnknownRequestError,
|
||||
PrismaClientRustPanicError,
|
||||
PrismaClientInitializationError,
|
||||
PrismaClientValidationError,
|
||||
getPrismaClient,
|
||||
sqltag,
|
||||
empty,
|
||||
join,
|
||||
raw,
|
||||
skip,
|
||||
Decimal,
|
||||
Debug,
|
||||
objectEnumValues,
|
||||
makeStrictEnum,
|
||||
Extensions,
|
||||
warnOnce,
|
||||
defineDmmfProperty,
|
||||
Public,
|
||||
getRuntime,
|
||||
createParam,
|
||||
} = require('./runtime/wasm-engine-edge.js')
|
||||
|
||||
|
||||
const Prisma = {}
|
||||
|
||||
exports.Prisma = Prisma
|
||||
exports.$Enums = {}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 6.19.3
|
||||
* Query Engine version: c2990dca591cba766e3b7ef5d9e8a84796e47ab7
|
||||
*/
|
||||
Prisma.prismaVersion = {
|
||||
client: "6.19.3",
|
||||
engine: "c2990dca591cba766e3b7ef5d9e8a84796e47ab7"
|
||||
}
|
||||
|
||||
Prisma.PrismaClientKnownRequestError = PrismaClientKnownRequestError;
|
||||
Prisma.PrismaClientUnknownRequestError = PrismaClientUnknownRequestError
|
||||
Prisma.PrismaClientRustPanicError = PrismaClientRustPanicError
|
||||
Prisma.PrismaClientInitializationError = PrismaClientInitializationError
|
||||
Prisma.PrismaClientValidationError = PrismaClientValidationError
|
||||
Prisma.Decimal = Decimal
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
Prisma.sql = sqltag
|
||||
Prisma.empty = empty
|
||||
Prisma.join = join
|
||||
Prisma.raw = raw
|
||||
Prisma.validator = Public.validator
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
Prisma.getExtensionContext = Extensions.getExtensionContext
|
||||
Prisma.defineExtension = Extensions.defineExtension
|
||||
|
||||
/**
|
||||
* Shorthand utilities for JSON filtering
|
||||
*/
|
||||
Prisma.DbNull = objectEnumValues.instances.DbNull
|
||||
Prisma.JsonNull = objectEnumValues.instances.JsonNull
|
||||
Prisma.AnyNull = objectEnumValues.instances.AnyNull
|
||||
|
||||
Prisma.NullTypes = {
|
||||
DbNull: objectEnumValues.classes.DbNull,
|
||||
JsonNull: objectEnumValues.classes.JsonNull,
|
||||
AnyNull: objectEnumValues.classes.AnyNull
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
exports.Prisma.TransactionIsolationLevel = makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
});
|
||||
|
||||
exports.Prisma.LauncherNoticeScalarFieldEnum = {
|
||||
id: 'id',
|
||||
appKey: 'appKey',
|
||||
title: 'title',
|
||||
body: 'body',
|
||||
linkUrl: 'linkUrl',
|
||||
isActive: 'isActive',
|
||||
startsAt: 'startsAt',
|
||||
endsAt: 'endsAt',
|
||||
priority: 'priority',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.ProvisionedDeviceScalarFieldEnum = {
|
||||
id: 'id',
|
||||
accountEmail: 'accountEmail',
|
||||
authUserId: 'authUserId',
|
||||
hostname: 'hostname',
|
||||
tailscaleHostname: 'tailscaleHostname',
|
||||
sshUser: 'sshUser',
|
||||
workspaceRoot: 'workspaceRoot',
|
||||
usageType: 'usageType',
|
||||
os: 'os',
|
||||
arch: 'arch',
|
||||
kernel: 'kernel',
|
||||
distro: 'distro',
|
||||
device: 'device',
|
||||
installedAt: 'installedAt',
|
||||
lastProvisionedAt: 'lastProvisionedAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.LauncherSshKeyScalarFieldEnum = {
|
||||
id: 'id',
|
||||
accountEmail: 'accountEmail',
|
||||
authUserId: 'authUserId',
|
||||
publicKey: 'publicKey',
|
||||
publicKeyHash: 'publicKeyHash',
|
||||
keyType: 'keyType',
|
||||
label: 'label',
|
||||
lastProvisionedAt: 'lastProvisionedAt',
|
||||
createdAt: 'createdAt',
|
||||
updatedAt: 'updatedAt'
|
||||
};
|
||||
|
||||
exports.Prisma.SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
};
|
||||
|
||||
exports.Prisma.NullableJsonNullValueInput = {
|
||||
DbNull: Prisma.DbNull,
|
||||
JsonNull: Prisma.JsonNull
|
||||
};
|
||||
|
||||
exports.Prisma.QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
};
|
||||
|
||||
exports.Prisma.NullsOrder = {
|
||||
first: 'first',
|
||||
last: 'last'
|
||||
};
|
||||
|
||||
exports.Prisma.JsonNullValueFilter = {
|
||||
DbNull: Prisma.DbNull,
|
||||
JsonNull: Prisma.JsonNull,
|
||||
AnyNull: Prisma.AnyNull
|
||||
};
|
||||
|
||||
|
||||
exports.Prisma.ModelName = {
|
||||
LauncherNotice: 'LauncherNotice',
|
||||
ProvisionedDevice: 'ProvisionedDevice',
|
||||
LauncherSshKey: 'LauncherSshKey'
|
||||
};
|
||||
/**
|
||||
* Create the Client
|
||||
*/
|
||||
const config = {
|
||||
"generator": {
|
||||
"name": "launcherClient",
|
||||
"provider": {
|
||||
"fromEnvVar": null,
|
||||
"value": "prisma-client-js"
|
||||
},
|
||||
"output": {
|
||||
"value": "/home/chyoo/tmp/atnmy-stdo-v2/atnmy-stdo-adm-v2-be/src/generated/launcher-client",
|
||||
"fromEnvVar": null
|
||||
},
|
||||
"config": {
|
||||
"engineType": "library"
|
||||
},
|
||||
"binaryTargets": [
|
||||
{
|
||||
"fromEnvVar": null,
|
||||
"value": "debian-openssl-3.0.x",
|
||||
"native": true
|
||||
}
|
||||
],
|
||||
"previewFeatures": [],
|
||||
"sourceFilePath": "/home/chyoo/tmp/atnmy-stdo-v2/atnmy-stdo-adm-v2-be/prisma/launcher.schema.prisma",
|
||||
"isCustomOutput": true
|
||||
},
|
||||
"relativeEnvPaths": {
|
||||
"rootEnvPath": null,
|
||||
"schemaEnvPath": "../../../.env"
|
||||
},
|
||||
"relativePath": "../../../prisma",
|
||||
"clientVersion": "6.19.3",
|
||||
"engineVersion": "c2990dca591cba766e3b7ef5d9e8a84796e47ab7",
|
||||
"datasourceNames": [
|
||||
"db"
|
||||
],
|
||||
"activeProvider": "postgresql",
|
||||
"postinstall": false,
|
||||
"inlineDatasources": {
|
||||
"db": {
|
||||
"url": {
|
||||
"fromEnvVar": "LAUNCHER_DATABASE_URL",
|
||||
"value": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"inlineSchema": "generator launcherClient {\n provider = \"prisma-client-js\"\n output = \"../src/generated/launcher-client\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"LAUNCHER_DATABASE_URL\")\n}\n\nmodel LauncherNotice {\n id String @id @default(uuid()) @db.Uuid\n appKey String @default(\"login\") @map(\"app_key\")\n title String\n body String\n linkUrl String? @map(\"link_url\")\n isActive Boolean @default(true) @map(\"is_active\")\n startsAt DateTime? @map(\"starts_at\") @db.Timestamptz(3)\n endsAt DateTime? @map(\"ends_at\") @db.Timestamptz(3)\n priority Int @default(0)\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n updatedAt DateTime @updatedAt @map(\"updated_at\") @db.Timestamptz(3)\n\n @@index([appKey, isActive, priority])\n @@map(\"launcher_notices\")\n}\n\nmodel ProvisionedDevice {\n id String @id @default(uuid()) @db.Uuid\n accountEmail String @map(\"account_email\")\n authUserId String? @map(\"auth_user_id\") @db.Uuid\n hostname String\n tailscaleHostname String @map(\"tailscale_hostname\")\n sshUser String? @map(\"ssh_user\")\n workspaceRoot String? @map(\"workspace_root\")\n usageType String @default(\"personal\") @map(\"usage_type\")\n os String?\n arch String?\n kernel String?\n distro String?\n device Json?\n installedAt DateTime @default(now()) @map(\"installed_at\") @db.Timestamptz(3)\n lastProvisionedAt DateTime @default(now()) @map(\"last_provisioned_at\") @db.Timestamptz(3)\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n updatedAt DateTime @updatedAt @map(\"updated_at\") @db.Timestamptz(3)\n\n @@unique([accountEmail, tailscaleHostname])\n @@index([accountEmail])\n @@index([tailscaleHostname])\n @@map(\"provisioned_devices\")\n}\n\nmodel LauncherSshKey {\n id String @id @default(uuid()) @db.Uuid\n accountEmail String @map(\"account_email\")\n authUserId String? @map(\"auth_user_id\") @db.Uuid\n publicKey String @map(\"public_key\")\n publicKeyHash String @map(\"public_key_hash\")\n keyType String? @map(\"key_type\")\n label String?\n lastProvisionedAt DateTime @default(now()) @map(\"last_provisioned_at\") @db.Timestamptz(3)\n createdAt DateTime @default(now()) @map(\"created_at\") @db.Timestamptz(3)\n updatedAt DateTime @updatedAt @map(\"updated_at\") @db.Timestamptz(3)\n\n @@unique([accountEmail, publicKeyHash])\n @@index([accountEmail])\n @@map(\"launcher_ssh_keys\")\n}\n",
|
||||
"inlineSchemaHash": "ad20160732d203c5e1ea82cbcac0488ce94e47432c3136a3833df4661c0a049b",
|
||||
"copyEngine": true
|
||||
}
|
||||
config.dirname = '/'
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"LauncherNotice\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"appKey\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"app_key\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"body\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"linkUrl\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"link_url\"},{\"name\":\"isActive\",\"kind\":\"scalar\",\"type\":\"Boolean\",\"dbName\":\"is_active\"},{\"name\":\"startsAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"starts_at\"},{\"name\":\"endsAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"ends_at\"},{\"name\":\"priority\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"updated_at\"}],\"dbName\":\"launcher_notices\"},\"ProvisionedDevice\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accountEmail\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"account_email\"},{\"name\":\"authUserId\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"auth_user_id\"},{\"name\":\"hostname\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"tailscaleHostname\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"tailscale_hostname\"},{\"name\":\"sshUser\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"ssh_user\"},{\"name\":\"workspaceRoot\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"workspace_root\"},{\"name\":\"usageType\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"usage_type\"},{\"name\":\"os\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"arch\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"kernel\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"distro\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"device\",\"kind\":\"scalar\",\"type\":\"Json\"},{\"name\":\"installedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"installed_at\"},{\"name\":\"lastProvisionedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"last_provisioned_at\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"updated_at\"}],\"dbName\":\"provisioned_devices\"},\"LauncherSshKey\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"accountEmail\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"account_email\"},{\"name\":\"authUserId\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"auth_user_id\"},{\"name\":\"publicKey\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"public_key\"},{\"name\":\"publicKeyHash\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"public_key_hash\"},{\"name\":\"keyType\",\"kind\":\"scalar\",\"type\":\"String\",\"dbName\":\"key_type\"},{\"name\":\"label\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastProvisionedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"last_provisioned_at\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"created_at\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\",\"dbName\":\"updated_at\"}],\"dbName\":\"launcher_ssh_keys\"}},\"enums\":{},\"types\":{}}")
|
||||
defineDmmfProperty(exports.Prisma, config.runtimeDataModel)
|
||||
config.engineWasm = {
|
||||
getRuntime: async () => require('./query_engine_bg.js'),
|
||||
getQueryEngineWasmModule: async () => {
|
||||
const loader = (await import('#wasm-engine-loader')).default
|
||||
const engine = (await loader).default
|
||||
return engine
|
||||
}
|
||||
}
|
||||
config.compilerWasm = undefined
|
||||
|
||||
config.injectableEdgeEnv = () => ({
|
||||
parsed: {
|
||||
LAUNCHER_DATABASE_URL: typeof globalThis !== 'undefined' && globalThis['LAUNCHER_DATABASE_URL'] || typeof process !== 'undefined' && process.env && process.env.LAUNCHER_DATABASE_URL || undefined
|
||||
}
|
||||
})
|
||||
|
||||
if (typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined) {
|
||||
Debug.enable(typeof globalThis !== 'undefined' && globalThis['DEBUG'] || typeof process !== 'undefined' && process.env && process.env.DEBUG || undefined)
|
||||
}
|
||||
|
||||
const PrismaClient = getPrismaClient(config)
|
||||
exports.PrismaClient = PrismaClient
|
||||
Object.assign(exports, Prisma)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
BadGatewayException,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
@@ -118,6 +119,10 @@ export class GiteaService {
|
||||
params.set('page', String(page));
|
||||
if (query.sha) {
|
||||
params.set('sha', query.sha);
|
||||
const { branches } = await this.listBranches(owner, repo) as { branches: Array<{ name?: string }> };
|
||||
if (!branches.some((branch) => branch.name === query.sha)) {
|
||||
throw new BadRequestException('해당 브랜치가 없습니다.');
|
||||
}
|
||||
}
|
||||
if (query.since) {
|
||||
params.set('since', query.since);
|
||||
|
||||
@@ -2,12 +2,11 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { LauncherPrismaModule } from '../launcher-prisma/launcher-prisma.module';
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { LauncherController } from './launcher.controller';
|
||||
import { LauncherService } from './launcher.service';
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, LauncherPrismaModule, AuthPrismaModule],
|
||||
imports: [PrismaModule, LauncherPrismaModule],
|
||||
controllers: [LauncherController],
|
||||
providers: [LauncherService],
|
||||
exports: [LauncherService],
|
||||
|
||||
@@ -10,8 +10,7 @@ import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
||||
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { getUserAvatarUrl } from '../users/users.service';
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import {
|
||||
CreateLauncherAppLinkDto,
|
||||
CreateLauncherBuildJobDto,
|
||||
@@ -63,7 +62,6 @@ export class LauncherService {
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
) {}
|
||||
|
||||
async listVersions() {
|
||||
@@ -453,31 +451,11 @@ export class LauncherService {
|
||||
});
|
||||
}
|
||||
|
||||
private async withLauncherBuildRequesters<T extends { requestedByEmail?: string | null }>(jobs: T[]) {
|
||||
const emails = [...new Set(jobs.map((job) => job.requestedByEmail).filter((email): email is string => Boolean(email)))];
|
||||
if (emails.length === 0) return jobs.map((job) => ({ ...job, requestedByAvatarUrl: null }));
|
||||
|
||||
const users = await this.authPrisma.user.findMany({
|
||||
where: { email: { in: emails } },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
profileImageMime: true,
|
||||
},
|
||||
});
|
||||
const userByEmail = new Map(users.map((user) => [user.email, user]));
|
||||
const authBaseUrl = this.configService.get<string>('AUTH_PUBLIC_URL')
|
||||
?? this.configService.get<string>('ATNMY_AUTH_URL')
|
||||
?? this.configService.get<string>('AUTH_EXTERNAL_URL')
|
||||
?? 'https://auth.autonomystudio.net';
|
||||
|
||||
return jobs.map((job) => {
|
||||
const user = job.requestedByEmail ? userByEmail.get(job.requestedByEmail) : null;
|
||||
return {
|
||||
...job,
|
||||
requestedByAvatarUrl: getUserAvatarUrl(user?.id ?? '', user?.profileImageMime, authBaseUrl),
|
||||
};
|
||||
});
|
||||
private withLauncherBuildRequesters<T extends { requestedById?: string | null }>(jobs: T[]) {
|
||||
return jobs.map((job) => ({
|
||||
...job,
|
||||
requestedByAvatarUrl: getAdminAvatarUrl(job.requestedById, this.configService),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Put, Query, Req } from '@nestjs/common';
|
||||
|
||||
import { AssignLicenseDto, ListUserLicensesQuery, UpdateLicenseAppPermissionsDto, UpdateLicensePlanDto } from './dto';
|
||||
import { LicensesService } from './licenses.service';
|
||||
@@ -38,13 +38,21 @@ export class LicensesController {
|
||||
}
|
||||
|
||||
@Post('users/:userId')
|
||||
assign(@Param('userId') userId: string, @Body() body: AssignLicenseDto) {
|
||||
return this.licensesService.assign(userId, body);
|
||||
assign(
|
||||
@Param('userId') userId: string,
|
||||
@Body() body: AssignLicenseDto,
|
||||
@Req() request: { admin?: { id: string } },
|
||||
) {
|
||||
return this.licensesService.assign(userId, body, request.admin?.id);
|
||||
}
|
||||
|
||||
@Patch('user-licenses/:id')
|
||||
update(@Param('id') id: string, @Body() body: AssignLicenseDto) {
|
||||
return this.licensesService.update(id, body);
|
||||
update(
|
||||
@Param('id') id: string,
|
||||
@Body() body: AssignLicenseDto,
|
||||
@Req() request: { admin?: { id: string } },
|
||||
) {
|
||||
return this.licensesService.update(id, body, request.admin?.id);
|
||||
}
|
||||
|
||||
@Delete('user-licenses/:id')
|
||||
|
||||
@@ -2,11 +2,12 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { LauncherPrismaModule } from '../launcher-prisma/launcher-prisma.module';
|
||||
import { PrismaModule } from '../prisma/prisma.module';
|
||||
import { LicensesController } from './licenses.controller';
|
||||
import { LicensesService } from './licenses.service';
|
||||
|
||||
@Module({
|
||||
imports: [AuthPrismaModule, LauncherPrismaModule],
|
||||
imports: [AuthPrismaModule, LauncherPrismaModule, PrismaModule],
|
||||
controllers: [LicensesController],
|
||||
providers: [LicensesService],
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import { BadRequestException, ConflictException, Injectable, NotFoundException }
|
||||
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { AssignLicenseDto, ListUserLicensesQuery, UpdateLicenseAppPermissionsDto, UpdateLicensePlanDto } from './dto';
|
||||
|
||||
type LauncherAppPermissionRow = {
|
||||
@@ -18,6 +19,7 @@ export class LicensesService {
|
||||
constructor(
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
private readonly prisma: PrismaService,
|
||||
) {}
|
||||
|
||||
async listPlans() {
|
||||
@@ -141,6 +143,15 @@ export class LicensesService {
|
||||
this.authPrisma.userLicense.count({ where }),
|
||||
]);
|
||||
|
||||
const assignedByIds = [...new Set(items.flatMap((item) => item.assignedById ? [item.assignedById] : []))];
|
||||
const admins = assignedByIds.length
|
||||
? await this.prisma.admin.findMany({
|
||||
where: { id: { in: assignedByIds } },
|
||||
select: { id: true, name: true },
|
||||
})
|
||||
: [];
|
||||
const assignedByName = new Map(admins.map((admin) => [admin.id, admin.name]));
|
||||
|
||||
return {
|
||||
assignments: items.map((userLicense, index) => ({
|
||||
id: userLicense.id,
|
||||
@@ -153,7 +164,9 @@ export class LicensesService {
|
||||
licenseName: userLicense.license.name,
|
||||
startsAt: userLicense.startsAt,
|
||||
expiresAt: userLicense.expiresAt,
|
||||
assignedBy: userLicense.assignedById,
|
||||
assignedBy: userLicense.assignedById
|
||||
? assignedByName.get(userLicense.assignedById) ?? '-'
|
||||
: '-',
|
||||
status: isActiveLicense(userLicense.startsAt, userLicense.expiresAt, now) ? '활성' : '만료',
|
||||
})),
|
||||
total,
|
||||
@@ -279,7 +292,7 @@ export class LicensesService {
|
||||
return userIds.length;
|
||||
}
|
||||
|
||||
async assign(userId: string, body: AssignLicenseDto) {
|
||||
async assign(userId: string, body: AssignLicenseDto, assignedById?: string) {
|
||||
const user = await this.authPrisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: { id: true },
|
||||
@@ -321,7 +334,7 @@ export class LicensesService {
|
||||
licenseId: license.id,
|
||||
startsAt,
|
||||
expiresAt,
|
||||
assignedById: body.assignedById,
|
||||
assignedById,
|
||||
},
|
||||
include: { license: true, user: true },
|
||||
});
|
||||
@@ -331,7 +344,7 @@ export class LicensesService {
|
||||
return { userLicense };
|
||||
}
|
||||
|
||||
async update(id: string, body: AssignLicenseDto) {
|
||||
async update(id: string, body: AssignLicenseDto, assignedById?: string) {
|
||||
const current = await this.authPrisma.userLicense.findUnique({
|
||||
where: { id },
|
||||
select: { id: true },
|
||||
@@ -360,7 +373,7 @@ export class LicensesService {
|
||||
licenseId: license.id,
|
||||
startsAt,
|
||||
expiresAt,
|
||||
assignedById: body.assignedById,
|
||||
assignedById,
|
||||
},
|
||||
include: { license: true, user: true },
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, Req } from '@nestjs/common';
|
||||
|
||||
import { Public } from '../admin-auth/decorators/admin-auth.decorators';
|
||||
import { CreateManualDocumentDto, ListManualDocumentsQuery, UpdateManualDocumentDto } from './dto';
|
||||
@@ -20,8 +20,11 @@ export class ManualsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
create(@Body() body: CreateManualDocumentDto) {
|
||||
return this.manualsService.create(body);
|
||||
create(
|
||||
@Body() body: CreateManualDocumentDto,
|
||||
@Req() request: { admin?: { id: string; name: string; email: string } },
|
||||
) {
|
||||
return this.manualsService.create(body, request.admin);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Prisma } from '@prisma/launcher-client';
|
||||
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import { CreateManualDocumentDto, ListManualDocumentsQuery, UpdateManualDocumentDto } from './dto';
|
||||
|
||||
@Injectable()
|
||||
export class ManualsService {
|
||||
constructor(private readonly launcherPrisma: LauncherPrismaService) {}
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
) {}
|
||||
|
||||
private creatorData(requester?: AdminRequester) {
|
||||
return requester
|
||||
? {
|
||||
createdById: requester.id,
|
||||
createdByName: requester.name,
|
||||
createdByEmail: requester.email,
|
||||
}
|
||||
: {};
|
||||
}
|
||||
|
||||
private withCreatorAvatars<T extends { createdById?: string | null }>(items: T[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
createdByAvatarUrl: getAdminAvatarUrl(item.createdById, this.configService),
|
||||
}));
|
||||
}
|
||||
|
||||
async list(query: ListManualDocumentsQuery) {
|
||||
const page = toPositiveInt(query.page, 1);
|
||||
@@ -35,10 +57,10 @@ export class ManualsService {
|
||||
]);
|
||||
|
||||
return {
|
||||
documents: documents.map((document, index) => ({
|
||||
documents: await this.withCreatorAvatars(documents.map((document, index) => ({
|
||||
...document,
|
||||
no: total - ((page - 1) * limit + index),
|
||||
})),
|
||||
}))),
|
||||
total,
|
||||
page,
|
||||
limit,
|
||||
@@ -61,7 +83,7 @@ export class ManualsService {
|
||||
return { documents };
|
||||
}
|
||||
|
||||
async create(body: CreateManualDocumentDto) {
|
||||
async create(body: CreateManualDocumentDto, requester?: AdminRequester) {
|
||||
const document = await this.launcherPrisma.launcherManualDocument.create({
|
||||
data: {
|
||||
appKey: body.appKey.trim(),
|
||||
@@ -69,6 +91,7 @@ export class ManualsService {
|
||||
body: body.body.trim(),
|
||||
isPublished: body.isPublished ?? true,
|
||||
sortOrder: body.sortOrder ?? 0,
|
||||
...this.creatorData(requester),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -105,6 +128,12 @@ export class ManualsService {
|
||||
|
||||
}
|
||||
|
||||
type AdminRequester = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
function toPositiveInt(value: string | undefined, fallback: number) {
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { LauncherPrismaModule } from '../launcher-prisma/launcher-prisma.module';
|
||||
import { NoticesController } from './notices.controller';
|
||||
import { NoticesService } from './notices.service';
|
||||
|
||||
@Module({
|
||||
imports: [AuthPrismaModule, LauncherPrismaModule],
|
||||
imports: [LauncherPrismaModule],
|
||||
controllers: [NoticesController],
|
||||
providers: [NoticesService],
|
||||
})
|
||||
|
||||
@@ -2,9 +2,8 @@ import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { Prisma } from '@prisma/launcher-client';
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import { getUserAvatarUrl } from '../users/users.service';
|
||||
import {
|
||||
CreateLauncherNoticeDto,
|
||||
ListLauncherNoticesQuery,
|
||||
@@ -20,7 +19,6 @@ type AdminRequester = {
|
||||
@Injectable()
|
||||
export class NoticesService {
|
||||
constructor(
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
) {}
|
||||
@@ -35,31 +33,11 @@ export class NoticesService {
|
||||
: {};
|
||||
}
|
||||
|
||||
private async withCreatorAvatars<T extends { createdByEmail?: string | null }>(items: T[]) {
|
||||
const emails = [...new Set(items.map((item) => item.createdByEmail).filter((email): email is string => Boolean(email)))];
|
||||
if (emails.length === 0) return items.map((item) => ({ ...item, createdByAvatarUrl: null }));
|
||||
|
||||
const users = await this.authPrisma.user.findMany({
|
||||
where: { email: { in: emails } },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
profileImageMime: true,
|
||||
},
|
||||
});
|
||||
const userByEmail = new Map(users.map((user) => [user.email, user]));
|
||||
const authBaseUrl = this.configService.get<string>('AUTH_PUBLIC_URL')
|
||||
?? this.configService.get<string>('ATNMY_AUTH_URL')
|
||||
?? this.configService.get<string>('AUTH_EXTERNAL_URL')
|
||||
?? 'https://auth.autonomystudio.net';
|
||||
|
||||
return items.map((item) => {
|
||||
const user = item.createdByEmail ? userByEmail.get(item.createdByEmail) : null;
|
||||
return {
|
||||
...item,
|
||||
createdByAvatarUrl: getUserAvatarUrl(user?.id ?? '', user?.profileImageMime, authBaseUrl),
|
||||
};
|
||||
});
|
||||
private withCreatorAvatars<T extends { createdById?: string | null }>(items: T[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
createdByAvatarUrl: getAdminAvatarUrl(item.createdById, this.configService),
|
||||
}));
|
||||
}
|
||||
|
||||
async list(query: ListLauncherNoticesQuery) {
|
||||
|
||||
@@ -13,8 +13,11 @@ export class OrganizationsController {
|
||||
}
|
||||
|
||||
@Post()
|
||||
create(@Body() body: CreateOrganizationDto) {
|
||||
return this.organizationsService.create(body);
|
||||
create(
|
||||
@Body() body: CreateOrganizationDto,
|
||||
@Req() request: { admin?: { id: string; name: string; email: string } },
|
||||
) {
|
||||
return this.organizationsService.create(body, request.admin);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Prisma } from '@prisma/auth-client';
|
||||
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { CreateOrganizationDto, ListOrganizationsQuery, UpdateOrganizationDto, UpdateOrganizationLicenseDto } from './dto';
|
||||
|
||||
type AdminRequester = {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationsService {
|
||||
constructor(private readonly authPrisma: AuthPrismaService) {}
|
||||
constructor(
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async list(query: ListOrganizationsQuery = {}) {
|
||||
const page = toPositiveInt(query.page, 1);
|
||||
@@ -37,6 +49,10 @@ export class OrganizationsService {
|
||||
type: true,
|
||||
domain: true,
|
||||
defaultLicenseCode: true,
|
||||
instructorInviteCode: true,
|
||||
createdById: true,
|
||||
createdByName: true,
|
||||
createdByEmail: true,
|
||||
createdAt: true,
|
||||
},
|
||||
}),
|
||||
@@ -51,6 +67,7 @@ export class OrganizationsService {
|
||||
organizations: organizations.map((organization, index) => ({
|
||||
...organization,
|
||||
defaultLicenseName: organization.defaultLicenseCode ? licenseNameByCode.get(organization.defaultLicenseCode) ?? organization.defaultLicenseCode : null,
|
||||
createdByAvatarUrl: getAdminAvatarUrl(organization.createdById, this.configService),
|
||||
no: total - ((page - 1) * limit + index),
|
||||
})),
|
||||
total,
|
||||
@@ -59,13 +76,22 @@ export class OrganizationsService {
|
||||
};
|
||||
}
|
||||
|
||||
async create(body: CreateOrganizationDto) {
|
||||
async create(body: CreateOrganizationDto, requester?: AdminRequester) {
|
||||
try {
|
||||
const instructorInviteCode = await this.createInstructorInviteCode();
|
||||
const organization = await this.authPrisma.organization.create({
|
||||
data: {
|
||||
name: body.name.trim(),
|
||||
type: body.type,
|
||||
domain: body.domain?.trim() || null,
|
||||
instructorInviteCode,
|
||||
...(requester
|
||||
? {
|
||||
createdById: requester.id,
|
||||
createdByName: requester.name,
|
||||
createdByEmail: requester.email,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
@@ -73,11 +99,20 @@ export class OrganizationsService {
|
||||
type: true,
|
||||
domain: true,
|
||||
defaultLicenseCode: true,
|
||||
instructorInviteCode: true,
|
||||
createdById: true,
|
||||
createdByName: true,
|
||||
createdByEmail: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
return { organization };
|
||||
return {
|
||||
organization: {
|
||||
...organization,
|
||||
createdByAvatarUrl: getAdminAvatarUrl(organization.createdById, this.configService),
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof Prisma.PrismaClientKnownRequestError &&
|
||||
@@ -105,6 +140,10 @@ export class OrganizationsService {
|
||||
type: true,
|
||||
domain: true,
|
||||
defaultLicenseCode: true,
|
||||
instructorInviteCode: true,
|
||||
createdById: true,
|
||||
createdByName: true,
|
||||
createdByEmail: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
@@ -229,6 +268,21 @@ export class OrganizationsService {
|
||||
updatedUserCount: license ? targetUserIds.length : 0,
|
||||
};
|
||||
}
|
||||
|
||||
private async createInstructorInviteCode(): Promise<string> {
|
||||
const alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||
for (let attempt = 0; attempt < 10; attempt += 1) {
|
||||
const bytes = randomBytes(6);
|
||||
const code = Array.from(bytes, (byte) => alphabet[byte % alphabet.length]).join('');
|
||||
const existing = await this.authPrisma.organization.findUnique({
|
||||
where: { instructorInviteCode: code },
|
||||
select: { id: true },
|
||||
});
|
||||
if (!existing) return code;
|
||||
}
|
||||
|
||||
throw new ConflictException('강사 가입 코드 생성에 실패했습니다. 다시 시도해주세요.');
|
||||
}
|
||||
}
|
||||
|
||||
function toPositiveInt(value: string | number | undefined, fallback: number) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Controller, Delete, Get, Param } from '@nestjs/common';
|
||||
|
||||
import { TailscaleService } from './tailscale.service';
|
||||
|
||||
@@ -11,6 +11,11 @@ export class TailscaleController {
|
||||
return this.tailscaleService.listNodes();
|
||||
}
|
||||
|
||||
@Delete('nodes/:nodeId')
|
||||
deleteNode(@Param('nodeId') nodeId: string) {
|
||||
return this.tailscaleService.deleteNode(nodeId);
|
||||
}
|
||||
|
||||
@Get('routes')
|
||||
listRoutes() {
|
||||
return this.tailscaleService.listRoutes();
|
||||
|
||||
@@ -63,6 +63,22 @@ export class TailscaleService {
|
||||
}
|
||||
}
|
||||
|
||||
async deleteNode(nodeId: string) {
|
||||
const normalizedNodeId = nodeId.trim();
|
||||
if (!normalizedNodeId) {
|
||||
throw new BadGatewayException('삭제할 Headscale 노드 ID가 없습니다.');
|
||||
}
|
||||
if (!this.gatewayUrl || !this.gatewayToken) {
|
||||
throw new BadGatewayException('PLATFORM_GATEWAY_URL 또는 PLATFORM_GATEWAY_TOKEN이 설정되어 있지 않습니다.');
|
||||
}
|
||||
|
||||
await this.request<{ deleted?: boolean }>(`/api/admin/tailscale/nodes/${encodeURIComponent(normalizedNodeId)}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
return { deleted: true, nodeId: normalizedNodeId };
|
||||
}
|
||||
|
||||
async listRoutes() {
|
||||
if (!this.gatewayUrl || !this.gatewayToken) {
|
||||
return {
|
||||
@@ -118,11 +134,13 @@ export class TailscaleService {
|
||||
}
|
||||
}
|
||||
|
||||
private async request<T>(path: string): Promise<T> {
|
||||
private async request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const response = await fetch(`${this.gatewayUrl}${path}`, {
|
||||
...init,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'x-platform-gateway-token': this.gatewayToken ?? '',
|
||||
...(init?.headers ?? {}),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AuthPrismaModule } from '../auth-prisma/auth-prisma.module';
|
||||
import { LauncherPrismaModule } from '../launcher-prisma/launcher-prisma.module';
|
||||
import { TermsController } from './terms.controller';
|
||||
import { TermsService } from './terms.service';
|
||||
|
||||
@Module({
|
||||
imports: [AuthPrismaModule, LauncherPrismaModule],
|
||||
imports: [LauncherPrismaModule],
|
||||
controllers: [TermsController],
|
||||
providers: [TermsService],
|
||||
})
|
||||
|
||||
@@ -2,9 +2,8 @@ import { ConflictException, Injectable, NotFoundException } from '@nestjs/common
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { Prisma } from '@prisma/launcher-client';
|
||||
import { AuthPrismaService } from '../auth-prisma/auth-prisma.service';
|
||||
import { getAdminAvatarUrl } from '../admins/admin-avatar';
|
||||
import { LauncherPrismaService } from '../launcher-prisma/launcher-prisma.service';
|
||||
import { getUserAvatarUrl } from '../users/users.service';
|
||||
import { CreateTermDto, ListTermsQuery, UpdateTermDto } from './dto';
|
||||
|
||||
type AdminRequester = {
|
||||
@@ -16,7 +15,6 @@ type AdminRequester = {
|
||||
@Injectable()
|
||||
export class TermsService {
|
||||
constructor(
|
||||
private readonly authPrisma: AuthPrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly launcherPrisma: LauncherPrismaService,
|
||||
) {}
|
||||
@@ -115,31 +113,11 @@ export class TermsService {
|
||||
: {};
|
||||
}
|
||||
|
||||
private async withCreatorAvatars<T extends { createdByEmail?: string | null }>(items: T[]) {
|
||||
const emails = [...new Set(items.map((item) => item.createdByEmail).filter((email): email is string => Boolean(email)))];
|
||||
if (emails.length === 0) return items.map((item) => ({ ...item, createdByAvatarUrl: null }));
|
||||
|
||||
const users = await this.authPrisma.user.findMany({
|
||||
where: { email: { in: emails } },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
profileImageMime: true,
|
||||
},
|
||||
});
|
||||
const userByEmail = new Map(users.map((user) => [user.email, user]));
|
||||
const authBaseUrl = this.configService.get<string>('AUTH_PUBLIC_URL')
|
||||
?? this.configService.get<string>('ATNMY_AUTH_URL')
|
||||
?? this.configService.get<string>('AUTH_EXTERNAL_URL')
|
||||
?? 'https://auth.autonomystudio.net';
|
||||
|
||||
return items.map((item) => {
|
||||
const user = item.createdByEmail ? userByEmail.get(item.createdByEmail) : null;
|
||||
return {
|
||||
...item,
|
||||
createdByAvatarUrl: getUserAvatarUrl(user?.id ?? '', user?.profileImageMime, authBaseUrl),
|
||||
};
|
||||
});
|
||||
private withCreatorAvatars<T extends { createdById?: string | null }>(items: T[]) {
|
||||
return items.map((item) => ({
|
||||
...item,
|
||||
createdByAvatarUrl: getAdminAvatarUrl(item.createdById, this.configService),
|
||||
}));
|
||||
}
|
||||
|
||||
private async ensureExists(id: string) {
|
||||
|
||||
+6
-1
@@ -1,4 +1,4 @@
|
||||
import { IsEmail, IsIn, IsOptional, IsString, IsUUID, MinLength } from 'class-validator';
|
||||
import { IsBoolean, IsEmail, IsIn, IsOptional, IsString, IsUUID, MinLength } from 'class-validator';
|
||||
|
||||
export class ListUserSessionsQuery {
|
||||
@IsOptional()
|
||||
@@ -45,3 +45,8 @@ export class CreateManagedUserDto {
|
||||
@IsIn(['FREE', 'EDU', 'PRO'])
|
||||
licenseCode?: 'FREE' | 'EDU' | 'PRO';
|
||||
}
|
||||
|
||||
export class UpdateLmsInstructorDto {
|
||||
@IsBoolean()
|
||||
isInstructor!: boolean;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';
|
||||
|
||||
import { CreateManagedUserDto, ListUserSessionsQuery } from './dto';
|
||||
import { CreateManagedUserDto, ListUserSessionsQuery, UpdateLmsInstructorDto } from './dto';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
@Controller('users')
|
||||
@@ -27,6 +27,14 @@ export class UsersController {
|
||||
return this.usersService.unlockUser(userId);
|
||||
}
|
||||
|
||||
@Patch(':userId/lms-instructor')
|
||||
updateLmsInstructor(
|
||||
@Param('userId') userId: string,
|
||||
@Body() body: UpdateLmsInstructorDto,
|
||||
) {
|
||||
return this.usersService.updateLmsInstructor(userId, body.isInstructor);
|
||||
}
|
||||
|
||||
@Delete('sessions/:sessionId')
|
||||
terminateSession(@Param('sessionId') sessionId: string) {
|
||||
return this.usersService.terminateSession(sessionId);
|
||||
|
||||
@@ -22,6 +22,7 @@ type UserSessionRow = {
|
||||
expiresAt: Date | null;
|
||||
lastSeen: Date | null;
|
||||
state: string;
|
||||
isLmsInstructor: boolean;
|
||||
primaryAffiliation: {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
@@ -82,6 +83,13 @@ export class UsersService {
|
||||
},
|
||||
},
|
||||
},
|
||||
appRoles: {
|
||||
where: {
|
||||
appKey: 'LMS',
|
||||
roleCode: 'INSTRUCTOR',
|
||||
},
|
||||
select: { id: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -104,6 +112,7 @@ export class UsersService {
|
||||
position: user.affiliations[0].position,
|
||||
}
|
||||
: null;
|
||||
const isLmsInstructor = user.appRoles.length > 0;
|
||||
|
||||
if (user.refreshTokens.length === 0) {
|
||||
return [
|
||||
@@ -120,6 +129,7 @@ export class UsersService {
|
||||
expiresAt: null,
|
||||
lastSeen: user.lastLoginAt,
|
||||
state: user.isActive ? '세션 없음' : '잠김',
|
||||
isLmsInstructor,
|
||||
primaryAffiliation,
|
||||
},
|
||||
];
|
||||
@@ -138,6 +148,7 @@ export class UsersService {
|
||||
expiresAt: token.expiresAt,
|
||||
lastSeen: user.lastLoginAt ?? token.createdAt,
|
||||
state: getSessionState(user.isActive, token.revokedAt, token.expiresAt, now),
|
||||
isLmsInstructor,
|
||||
primaryAffiliation,
|
||||
}));
|
||||
});
|
||||
@@ -260,6 +271,45 @@ export class UsersService {
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
async updateLmsInstructor(userId: string, isInstructor: boolean) {
|
||||
const user = await this.authPrisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new NotFoundException('사용자를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
if (isInstructor) {
|
||||
await this.authPrisma.userAppRole.upsert({
|
||||
where: {
|
||||
userId_appKey_roleCode: {
|
||||
userId,
|
||||
appKey: 'LMS',
|
||||
roleCode: 'INSTRUCTOR',
|
||||
},
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
appKey: 'LMS',
|
||||
roleCode: 'INSTRUCTOR',
|
||||
},
|
||||
update: { endsAt: null },
|
||||
});
|
||||
} else {
|
||||
await this.authPrisma.userAppRole.deleteMany({
|
||||
where: {
|
||||
userId,
|
||||
appKey: 'LMS',
|
||||
roleCode: 'INSTRUCTOR',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return { userId, isInstructor };
|
||||
}
|
||||
|
||||
async terminateSession(sessionId: string) {
|
||||
const session = await this.authPrisma.refreshToken.findUnique({
|
||||
where: { id: sessionId },
|
||||
|
||||
Reference in New Issue
Block a user