mirror of
https://github.com/nestriness/nestri.git
synced 2026-08-01 09:24:15 +03:00
feat: Add types and IDE comments to session
This commit is contained in:
@@ -1,189 +1,38 @@
|
||||
import { z } from "zod/v4";
|
||||
import { Identifier } from "../id.js";
|
||||
import { Examples } from "../examples.js";
|
||||
import { fn } from "../utils/fn.js";
|
||||
import { sessionTable } from "./session.sql.js";
|
||||
import {
|
||||
MachinePresetName,
|
||||
ScreenResolutionPresetName,
|
||||
VideoCodecName,
|
||||
AudioCodecName,
|
||||
RetryOptions,
|
||||
SessionInfo,
|
||||
type SessionInfo as SessionInfoType,
|
||||
type Session as SessionInterface,
|
||||
type Config as SessionConfig,
|
||||
} from "./types.js";
|
||||
|
||||
// Basic types we need
|
||||
export const MachinePresetName = z.enum([
|
||||
"ns3-micro",
|
||||
"ns3-mini",
|
||||
"ns3-small",
|
||||
"ns3-medium",
|
||||
"ns3-large",
|
||||
]);
|
||||
// Re-export all types and schemas from types.ts
|
||||
export {
|
||||
MachinePresetName,
|
||||
ScreenResolutionPresetName,
|
||||
VideoCodecName,
|
||||
AudioCodecName,
|
||||
RetryOptions,
|
||||
SessionInfo,
|
||||
};
|
||||
|
||||
export const ScreenResolutionPresetName = z.enum([
|
||||
"1280x720",
|
||||
"1080x1920",
|
||||
"1440x2560",
|
||||
"2160x3840",
|
||||
]);
|
||||
|
||||
export const VideoCodecName = z.enum(["h264", "h265", "vp8", "vp9", "av1"]);
|
||||
|
||||
export const AudioCodecName = z.enum(["opus", "aac", "mp3", "pcm"]);
|
||||
|
||||
export const RetryOptions = z.object({
|
||||
maxAttempts: z.number().int().optional(),
|
||||
factor: z.number().optional(),
|
||||
minTimeoutInMs: z.number().int().optional(),
|
||||
maxTimeoutInMs: z.number().int().optional(),
|
||||
randomize: z.boolean().optional(),
|
||||
outOfMemory: z
|
||||
.object({
|
||||
machine: MachinePresetName.optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
export type {
|
||||
SessionInfoType,
|
||||
SessionInterface as Session,
|
||||
SessionConfig as SessionConfigType,
|
||||
};
|
||||
|
||||
// Maintain backward compatibility with existing namespace structure
|
||||
export namespace Session {
|
||||
export const Info = z
|
||||
.object({
|
||||
id: Identifier.schema("session").meta({
|
||||
description: "The unique identifier of the session",
|
||||
example: Examples.Session.id,
|
||||
}),
|
||||
description: z.string().optional().meta({
|
||||
description: "Description of what the session does",
|
||||
example: Examples.Session.description,
|
||||
}),
|
||||
retry: RetryOptions.optional().meta({
|
||||
description: "Retry configuration for failed session attempts",
|
||||
example: Examples.Session.retry,
|
||||
}),
|
||||
queue: z
|
||||
.object({
|
||||
name: z.string().optional(),
|
||||
concurrencyLimit: z.number().optional(),
|
||||
})
|
||||
.optional()
|
||||
.meta({
|
||||
description: "Queue configuration for concurrent session execution",
|
||||
example: Examples.Session.queue,
|
||||
}),
|
||||
machine: MachinePresetName.optional().meta({
|
||||
description: "Machine preset for the session",
|
||||
example: Examples.Session.machine,
|
||||
}),
|
||||
maxDuration: z.number().optional().meta({
|
||||
description: "Maximum duration in seconds the session can run",
|
||||
example: Examples.Session.maxDuration,
|
||||
}),
|
||||
relayUrl: z.url().optional().meta({
|
||||
description: "Nestri relay URL for streaming and signaling",
|
||||
example: Examples.Session.relayUrl,
|
||||
}),
|
||||
resolution: ScreenResolutionPresetName.optional().meta({
|
||||
description: "Display or stream resolution in 'WxH' format",
|
||||
example: Examples.Session.resolution,
|
||||
}),
|
||||
framerate: z.number().optional().meta({
|
||||
description: "Display or stream framerate",
|
||||
example: Examples.Session.framerate,
|
||||
}),
|
||||
room: z.string().optional().meta({
|
||||
description: "Room name or identifier for multiplayer sessions",
|
||||
example: Examples.Session.room,
|
||||
}),
|
||||
gpuVendor: z.string().optional().meta({
|
||||
description: "Preferred GPU vendor",
|
||||
example: Examples.Session.gpuVendor,
|
||||
}),
|
||||
gpuName: z.string().optional().meta({
|
||||
description: "Preferred GPU name",
|
||||
example: Examples.Session.gpuName,
|
||||
}),
|
||||
gpuIndex: z.number().optional().meta({
|
||||
description: "Specific GPU index to use",
|
||||
example: Examples.Session.gpuIndex,
|
||||
}),
|
||||
gpuCardPath: z.string().optional().meta({
|
||||
description: "Force specific GPU card by /dev/dri path",
|
||||
example: Examples.Session.gpuCardPath,
|
||||
}),
|
||||
videoCodec: VideoCodecName.optional().meta({
|
||||
description: "Preferred video codec for streaming",
|
||||
example: Examples.Session.videoCodec,
|
||||
}),
|
||||
videoEncoder: z.string().optional().meta({
|
||||
description: "Override video encoder implementation",
|
||||
example: Examples.Session.videoEncoder,
|
||||
}),
|
||||
videoRateControl: z
|
||||
.enum(["cbr", "vbr", "cq", "lossless"])
|
||||
.optional()
|
||||
.meta({
|
||||
description: "Video rate control method",
|
||||
example: Examples.Session.videoRateControl,
|
||||
}),
|
||||
videoCqp: z.number().min(1).max(51).optional().meta({
|
||||
description: "Constant Quantization Parameter for quality control",
|
||||
example: Examples.Session.videoCqp,
|
||||
}),
|
||||
videoBitrate: z.number().min(1).optional().meta({
|
||||
description: "Target video bitrate in kbps",
|
||||
example: Examples.Session.videoBitrate,
|
||||
}),
|
||||
videoBitrateMax: z.number().min(1).optional().meta({
|
||||
description: "Maximum video bitrate in kbps",
|
||||
example: Examples.Session.videoBitrateMax,
|
||||
}),
|
||||
videoEncoderType: z.enum(["hardware", "software"]).optional().meta({
|
||||
description: "Encoder type: hardware or software",
|
||||
example: Examples.Session.videoEncoderType,
|
||||
}),
|
||||
videoBitDepth: z
|
||||
.union([z.literal(8), z.literal(10)])
|
||||
.optional()
|
||||
.meta({
|
||||
description: "Video bit depth (8 or 10)",
|
||||
example: Examples.Session.videoBitDepth,
|
||||
}),
|
||||
audioCaptureMethod: z
|
||||
.enum(["pipewire", "pulse", "alsa"])
|
||||
.optional()
|
||||
.meta({
|
||||
description: "Audio capture method",
|
||||
example: Examples.Session.audioCaptureMethod,
|
||||
}),
|
||||
audioCodec: AudioCodecName.optional().meta({
|
||||
description: "Preferred audio codec for streaming",
|
||||
example: Examples.Session.audioCodec,
|
||||
}),
|
||||
audioEncoder: z.string().optional().meta({
|
||||
description: "Override audio encoder binary",
|
||||
example: Examples.Session.audioEncoder,
|
||||
}),
|
||||
audioRateControl: z.enum(["cbr", "vbr"]).optional().meta({
|
||||
description: "Audio rate control method",
|
||||
example: Examples.Session.audioRateControl,
|
||||
}),
|
||||
audioBitrate: z.number().min(1).optional().meta({
|
||||
description: "Target audio bitrate in kbps",
|
||||
example: Examples.Session.audioBitrate,
|
||||
}),
|
||||
audioBitrateMax: z.number().optional().meta({
|
||||
description: "Maximum audio bitrate in kbps",
|
||||
example: Examples.Session.audioBitrateMax,
|
||||
}),
|
||||
zeroCopy: z.boolean().optional().meta({
|
||||
description: "Whether to use DMA-BUF for zero-copy video pipelines",
|
||||
example: Examples.Session.zeroCopy,
|
||||
}),
|
||||
verbose: z.boolean().optional().meta({
|
||||
description: "Enable verbose output for debugging",
|
||||
example: Examples.Session.verbose,
|
||||
}),
|
||||
})
|
||||
.meta({
|
||||
ref: "Session",
|
||||
description:
|
||||
"Represents a session configuration with streaming and execution options",
|
||||
example: Examples.Session,
|
||||
});
|
||||
|
||||
export type Info = z.infer<typeof Info>;
|
||||
|
||||
// Session interface that matches the SDK session object
|
||||
export const Info = SessionInfo;
|
||||
export type Info = SessionInfoType;
|
||||
export interface Session {
|
||||
/** Optional description of the session */
|
||||
description?: string;
|
||||
@@ -195,9 +44,49 @@ export namespace Session {
|
||||
startAndWait: (options?: any) => any;
|
||||
}
|
||||
|
||||
// Session configuration type that includes the run function
|
||||
export type Config = Omit<Info, "id"> & {
|
||||
export type Config = Omit<SessionInfoType, "id"> & {
|
||||
/** The function that executes when the session is started */
|
||||
run: (ctx: any) => Promise<any>;
|
||||
};
|
||||
|
||||
export const list = fn(z.void(), () => {
|
||||
// Placeholder implementation
|
||||
});
|
||||
|
||||
export function serialize(
|
||||
input: typeof sessionTable.$inferSelect,
|
||||
): z.infer<typeof SessionInfo> {
|
||||
return {
|
||||
id: input.id,
|
||||
room: input.room || undefined,
|
||||
retry: input.retry || undefined,
|
||||
queue: input.queue || undefined,
|
||||
machine: input.machine || undefined,
|
||||
description: input.description || undefined,
|
||||
maxDuration: input.maxDuration || undefined,
|
||||
relayUrl: input.relayUrl || undefined,
|
||||
resolution: input.resolution || undefined,
|
||||
framerate: input.framerate || undefined,
|
||||
gpuVendor: input.gpuVendor || undefined,
|
||||
gpuName: input.gpuName || undefined,
|
||||
gpuIndex: input.gpuIndex || undefined,
|
||||
gpuCardPath: input.gpuCardPath || undefined,
|
||||
videoCodec: input.videoCodec || undefined,
|
||||
videoEncoder: input.videoEncoder || undefined,
|
||||
videoRateControl: input.videoRateControl || undefined,
|
||||
videoCqp: input.videoCqp || undefined,
|
||||
videoBitrate: input.videoBitrate || undefined,
|
||||
videoBitrateMax: input.videoBitrateMax || undefined,
|
||||
videoEncoderType: input.videoEncoderType || undefined,
|
||||
videoBitDepth: input.videoBitDepth || undefined,
|
||||
audioCaptureMethod: input.audioCaptureMethod || undefined,
|
||||
audioCodec: input.audioCodec || undefined,
|
||||
audioEncoder: input.audioEncoder || undefined,
|
||||
audioRateControl: input.audioRateControl || undefined,
|
||||
audioBitrate: input.audioBitrate || undefined,
|
||||
audioBitrateMax: input.audioBitrateMax || undefined,
|
||||
zeroCopy: input.zeroCopy || undefined,
|
||||
verbose: input.verbose || undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
66
packages/core/src/session/session.sql.ts
Normal file
66
packages/core/src/session/session.sql.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { id, timestamps } from "../drizzle/types.js";
|
||||
import {
|
||||
pgTable,
|
||||
varchar,
|
||||
text,
|
||||
integer,
|
||||
boolean,
|
||||
jsonb,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import {
|
||||
type Queue,
|
||||
type RetryOptions,
|
||||
type VideoCodecName,
|
||||
type AudioCodecName,
|
||||
type MachinePresetName,
|
||||
type ScreenResolutionPresetName,
|
||||
VideoEncoderType,
|
||||
VideoRateControl,
|
||||
AudioCaptureMethod,
|
||||
AudioRateControl,
|
||||
VideoBitDepth,
|
||||
} from "./types.js";
|
||||
|
||||
export const sessionTable = pgTable("sessions", {
|
||||
...id,
|
||||
...timestamps,
|
||||
description: text("description"),
|
||||
retry: jsonb("retry").$type<RetryOptions>(),
|
||||
queue: jsonb("queue").$type<Queue>(),
|
||||
machine: varchar("machine", { length: 200 }).$type<MachinePresetName>(),
|
||||
maxDuration: integer("max_duration"),
|
||||
relayUrl: varchar("relay_url", { length: 500 }),
|
||||
resolution: varchar("resolution", {
|
||||
length: 20,
|
||||
}).$type<ScreenResolutionPresetName>(),
|
||||
framerate: integer("framerate"),
|
||||
room: varchar("room", { length: 255 }),
|
||||
gpuVendor: varchar("gpu_vendor", { length: 100 }),
|
||||
gpuName: varchar("gpu_name", { length: 255 }),
|
||||
gpuIndex: integer("gpu_index"),
|
||||
gpuCardPath: varchar("gpu_card_path", { length: 500 }),
|
||||
videoCodec: varchar("video_codec", { length: 20 }).$type<VideoCodecName>(),
|
||||
videoEncoder: varchar("video_encoder", { length: 100 }),
|
||||
videoRateControl: varchar("video_rate_control", {
|
||||
length: 20,
|
||||
}).$type<VideoRateControl>(),
|
||||
videoCqp: integer("video_cqp"),
|
||||
videoBitrate: integer("video_bitrate"),
|
||||
videoBitrateMax: integer("video_bitrate_max"),
|
||||
videoEncoderType: varchar("video_encoder_type", {
|
||||
length: 20,
|
||||
}).$type<VideoEncoderType>(),
|
||||
videoBitDepth: integer("video_bit_depth").$type<VideoBitDepth>(),
|
||||
audioCaptureMethod: varchar("audio_capture_method", {
|
||||
length: 20,
|
||||
}).$type<AudioCaptureMethod>(),
|
||||
audioCodec: varchar("audio_codec", { length: 20 }).$type<AudioCodecName>(),
|
||||
audioEncoder: varchar("audio_encoder", { length: 100 }),
|
||||
audioRateControl: varchar("audio_rate_control", {
|
||||
length: 20,
|
||||
}).$type<AudioRateControl>(),
|
||||
audioBitrate: integer("audio_bitrate"),
|
||||
audioBitrateMax: integer("audio_bitrate_max"),
|
||||
zeroCopy: boolean("zero_copy"),
|
||||
verbose: boolean("verbose"),
|
||||
});
|
||||
286
packages/core/src/session/types.ts
Normal file
286
packages/core/src/session/types.ts
Normal file
@@ -0,0 +1,286 @@
|
||||
import { z } from "zod/v4";
|
||||
import { Identifier } from "../id.js";
|
||||
import { Examples } from "../examples.js";
|
||||
|
||||
/**
|
||||
* Available machine preset sizes for session execution
|
||||
*/
|
||||
export const MachinePresetName = z.enum([
|
||||
"ns3-micro",
|
||||
"ns3-mini",
|
||||
"ns3-small",
|
||||
"ns3-medium",
|
||||
"ns3-large",
|
||||
]);
|
||||
|
||||
export type MachinePresetName = z.infer<typeof MachinePresetName>;
|
||||
|
||||
/**
|
||||
* Available screen resolution presets in 'WxH' format
|
||||
*/
|
||||
export const ScreenResolutionPresetName = z.enum([
|
||||
"1280x720",
|
||||
"1080x1920",
|
||||
"1440x2560",
|
||||
"2160x3840",
|
||||
]);
|
||||
|
||||
export type ScreenResolutionPresetName = z.infer<
|
||||
typeof ScreenResolutionPresetName
|
||||
>;
|
||||
|
||||
/**
|
||||
* Supported video codecs for streaming
|
||||
*/
|
||||
export const VideoCodecName = z.enum(["h264", "h265", "vp8", "vp9", "av1"]);
|
||||
|
||||
export type VideoCodecName = z.infer<typeof VideoCodecName>;
|
||||
|
||||
/**
|
||||
* Supported audio codecs for streaming
|
||||
*/
|
||||
export const AudioCodecName = z.enum(["opus", "aac", "mp3", "pcm"]);
|
||||
|
||||
export type AudioCodecName = z.infer<typeof AudioCodecName>;
|
||||
|
||||
/**
|
||||
* Retry configuration for failed operations
|
||||
*/
|
||||
export const RetryOptions = z.object({
|
||||
/** Maximum number of retry attempts */
|
||||
maxAttempts: z.number().int().optional(),
|
||||
/** Exponential backoff factor for retry delays */
|
||||
factor: z.number().optional(),
|
||||
/** Minimum timeout between retries in milliseconds */
|
||||
minTimeoutInMs: z.number().int().optional(),
|
||||
/** Maximum timeout between retries in milliseconds */
|
||||
maxTimeoutInMs: z.number().int().optional(),
|
||||
/** Whether to randomize retry delays to avoid thundering herd */
|
||||
randomize: z.boolean().optional(),
|
||||
/** Configuration for handling out of memory errors */
|
||||
outOfMemory: z
|
||||
.object({
|
||||
/** Machine preset to upgrade to on out of memory errors */
|
||||
machine: MachinePresetName.optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type RetryOptions = z.infer<typeof RetryOptions>;
|
||||
|
||||
export const Queue = z.object({
|
||||
/** Queue name for organizing sessions */
|
||||
name: z.string().optional(),
|
||||
/** Maximum number of concurrent sessions in queue */
|
||||
concurrencyLimit: z.number().optional(),
|
||||
});
|
||||
|
||||
export type Queue = z.infer<typeof Queue>;
|
||||
|
||||
export const VideoRateControl = z.enum(["cbr", "vbr", "cq", "lossless"]);
|
||||
|
||||
export type VideoRateControl = z.infer<typeof VideoRateControl>;
|
||||
|
||||
export const VideoEncoderType = z.enum(["hardware", "software"]);
|
||||
|
||||
export type VideoEncoderType = z.infer<typeof VideoEncoderType>;
|
||||
|
||||
export const AudioCaptureMethod = z.enum(["pipewire", "pulse", "alsa"]);
|
||||
|
||||
export type AudioCaptureMethod = z.infer<typeof AudioCaptureMethod>;
|
||||
|
||||
export const AudioRateControl = z.enum(["cbr", "vbr"]);
|
||||
|
||||
export type AudioRateControl = z.infer<typeof AudioRateControl>;
|
||||
|
||||
export const VideoBitDepth = z.union([z.literal(8), z.literal(10)]);
|
||||
|
||||
export type VideoBitDepth = z.infer<typeof VideoBitDepth>;
|
||||
|
||||
/**
|
||||
* Represents a session configuration with streaming and execution options
|
||||
*/
|
||||
export const SessionInfo = z
|
||||
.object({
|
||||
/** The unique identifier of the session */
|
||||
id: Identifier.schema("session").meta({
|
||||
description: "The unique identifier of the session",
|
||||
example: Examples.Session.id,
|
||||
}),
|
||||
/** Description of what the session does */
|
||||
description: z.string().optional().meta({
|
||||
description: "Description of what the session does",
|
||||
example: Examples.Session.description,
|
||||
}),
|
||||
/** Retry configuration for failed session attempts */
|
||||
retry: RetryOptions.optional().meta({
|
||||
description: "Retry configuration for failed session attempts",
|
||||
example: Examples.Session.retry,
|
||||
}),
|
||||
/** Queue configuration for concurrent session execution */
|
||||
queue: Queue.optional().meta({
|
||||
description: "Queue configuration for concurrent session execution",
|
||||
example: Examples.Session.queue,
|
||||
}),
|
||||
/** Machine preset for the session */
|
||||
machine: MachinePresetName.optional().meta({
|
||||
description: "Machine preset for the session",
|
||||
example: Examples.Session.machine,
|
||||
}),
|
||||
/** Maximum duration in seconds the session can run */
|
||||
maxDuration: z.number().optional().meta({
|
||||
description: "Maximum duration in seconds the session can run",
|
||||
example: Examples.Session.maxDuration,
|
||||
}),
|
||||
/** Nestri relay URL for streaming and signaling */
|
||||
relayUrl: z.url().optional().meta({
|
||||
description: "Nestri relay URL for streaming and signaling",
|
||||
example: Examples.Session.relayUrl,
|
||||
}),
|
||||
/** Display or stream resolution in 'WxH' format */
|
||||
resolution: ScreenResolutionPresetName.optional().meta({
|
||||
description: "Display or stream resolution in 'WxH' format",
|
||||
example: Examples.Session.resolution,
|
||||
}),
|
||||
/** Display or stream framerate */
|
||||
framerate: z.number().optional().meta({
|
||||
description: "Display or stream framerate",
|
||||
example: Examples.Session.framerate,
|
||||
}),
|
||||
/** Room name or identifier for multiplayer sessions */
|
||||
room: z.string().optional().meta({
|
||||
description: "Room name or identifier for multiplayer sessions",
|
||||
example: Examples.Session.room,
|
||||
}),
|
||||
/** Preferred GPU vendor */
|
||||
gpuVendor: z.string().optional().meta({
|
||||
description: "Preferred GPU vendor",
|
||||
example: Examples.Session.gpuVendor,
|
||||
}),
|
||||
/** Preferred GPU name */
|
||||
gpuName: z.string().optional().meta({
|
||||
description: "Preferred GPU name",
|
||||
example: Examples.Session.gpuName,
|
||||
}),
|
||||
/** Specific GPU index to use */
|
||||
gpuIndex: z.number().optional().meta({
|
||||
description: "Specific GPU index to use",
|
||||
example: Examples.Session.gpuIndex,
|
||||
}),
|
||||
/** Force specific GPU card by /dev/dri path */
|
||||
gpuCardPath: z.string().optional().meta({
|
||||
description: "Force specific GPU card by /dev/dri path",
|
||||
example: Examples.Session.gpuCardPath,
|
||||
}),
|
||||
/** Preferred video codec for streaming */
|
||||
videoCodec: VideoCodecName.optional().meta({
|
||||
description: "Preferred video codec for streaming",
|
||||
example: Examples.Session.videoCodec,
|
||||
}),
|
||||
/** Override video encoder implementation */
|
||||
videoEncoder: z.string().optional().meta({
|
||||
description: "Override video encoder implementation",
|
||||
example: Examples.Session.videoEncoder,
|
||||
}),
|
||||
/** Video rate control method */
|
||||
videoRateControl: VideoRateControl.optional().meta({
|
||||
description: "Video rate control method",
|
||||
example: Examples.Session.videoRateControl,
|
||||
}),
|
||||
/** Constant Quantization Parameter for quality control */
|
||||
videoCqp: z.number().min(1).max(51).optional().meta({
|
||||
description: "Constant Quantization Parameter for quality control",
|
||||
example: Examples.Session.videoCqp,
|
||||
}),
|
||||
/** Target video bitrate in kbps */
|
||||
videoBitrate: z.number().min(1).optional().meta({
|
||||
description: "Target video bitrate in kbps",
|
||||
example: Examples.Session.videoBitrate,
|
||||
}),
|
||||
/** Maximum video bitrate in kbps */
|
||||
videoBitrateMax: z.number().min(1).optional().meta({
|
||||
description: "Maximum video bitrate in kbps",
|
||||
example: Examples.Session.videoBitrateMax,
|
||||
}),
|
||||
/** Encoder type: hardware or software */
|
||||
videoEncoderType: VideoEncoderType.optional().meta({
|
||||
description: "Encoder type: hardware or software",
|
||||
example: Examples.Session.videoEncoderType,
|
||||
}),
|
||||
/** Video bit depth (8 or 10) */
|
||||
videoBitDepth: VideoBitDepth.optional().meta({
|
||||
description: "Video bit depth (8 or 10)",
|
||||
example: Examples.Session.videoBitDepth,
|
||||
}),
|
||||
/** Audio capture method */
|
||||
audioCaptureMethod: AudioCaptureMethod.optional().meta({
|
||||
description: "Audio capture method",
|
||||
example: Examples.Session.audioCaptureMethod,
|
||||
}),
|
||||
/** Preferred audio codec for streaming */
|
||||
audioCodec: AudioCodecName.optional().meta({
|
||||
description: "Preferred audio codec for streaming",
|
||||
example: Examples.Session.audioCodec,
|
||||
}),
|
||||
/** Override audio encoder binary */
|
||||
audioEncoder: z.string().optional().meta({
|
||||
description: "Override audio encoder binary",
|
||||
example: Examples.Session.audioEncoder,
|
||||
}),
|
||||
/** Audio rate control method */
|
||||
audioRateControl: AudioRateControl.optional().meta({
|
||||
description: "Audio rate control method",
|
||||
example: Examples.Session.audioRateControl,
|
||||
}),
|
||||
/** Target audio bitrate in kbps */
|
||||
audioBitrate: z.number().min(1).optional().meta({
|
||||
description: "Target audio bitrate in kbps",
|
||||
example: Examples.Session.audioBitrate,
|
||||
}),
|
||||
/** Maximum audio bitrate in kbps */
|
||||
audioBitrateMax: z.number().optional().meta({
|
||||
description: "Maximum audio bitrate in kbps",
|
||||
example: Examples.Session.audioBitrateMax,
|
||||
}),
|
||||
/** Whether to use DMA-BUF for zero-copy video pipelines */
|
||||
zeroCopy: z.boolean().optional().meta({
|
||||
description: "Whether to use DMA-BUF for zero-copy video pipelines",
|
||||
example: Examples.Session.zeroCopy,
|
||||
}),
|
||||
/** Enable verbose output for debugging */
|
||||
verbose: z.boolean().optional().meta({
|
||||
description: "Enable verbose output for debugging",
|
||||
example: Examples.Session.verbose,
|
||||
}),
|
||||
})
|
||||
.meta({
|
||||
ref: "Session",
|
||||
description:
|
||||
"Represents a session configuration with streaming and execution options",
|
||||
example: Examples.Session,
|
||||
});
|
||||
|
||||
/** Inferred type from SessionInfo schema */
|
||||
export type SessionInfo = z.infer<typeof SessionInfo>;
|
||||
|
||||
/**
|
||||
* Session interface that matches the SDK session object
|
||||
*/
|
||||
export interface Session {
|
||||
/** Optional description of the session */
|
||||
description?: string;
|
||||
|
||||
/** Start a session without waiting for the result */
|
||||
start: (options?: any, requestOptions?: any) => Promise<any>;
|
||||
|
||||
/** Start a session and wait for the result */
|
||||
startAndWait: (options?: any) => any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Session configuration type that includes the run function
|
||||
*/
|
||||
export type Config = Omit<SessionInfo, "id"> & {
|
||||
/** The function that executes when the session is started */
|
||||
run: (ctx: any) => Promise<any>;
|
||||
};
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Hono } from "hono";
|
||||
import { describeRoute, resolver } from "hono-openapi";
|
||||
import { notPublic } from "../utils/auth.js";
|
||||
import { ErrorResponses } from "../utils/error.js";
|
||||
import { Session } from "@nestri/core/session/index";
|
||||
import { describeRoute, resolver } from "hono-openapi";
|
||||
|
||||
export namespace SessionRoute {
|
||||
export const route = new Hono().get(
|
||||
export const route = new Hono().use(notPublic).get(
|
||||
"/",
|
||||
describeRoute({
|
||||
tags: ["Session"],
|
||||
@@ -19,7 +21,14 @@ export namespace SessionRoute {
|
||||
},
|
||||
},
|
||||
},
|
||||
401: ErrorResponses[401],
|
||||
403: ErrorResponses[403],
|
||||
429: ErrorResponses[429],
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const sessions = await Session.list();
|
||||
return c.json(sessions);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,17 @@ const client = createClient({
|
||||
subjects,
|
||||
});
|
||||
|
||||
export const notPublic: MiddlewareHandler = async (c, next) => {
|
||||
const actor = Actor.use();
|
||||
if (actor.type === "public")
|
||||
throw new VisibleError(
|
||||
"authentication",
|
||||
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||
"Missing authorization header",
|
||||
);
|
||||
return next();
|
||||
};
|
||||
|
||||
export const auth: MiddlewareHandler = async (c, next) => {
|
||||
const authHeader =
|
||||
c.req.query("authorization") ?? c.req.header("authorization");
|
||||
|
||||
138
packages/function/src/api/utils/error.ts
Normal file
138
packages/function/src/api/utils/error.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import { resolver } from "hono-openapi";
|
||||
import { ErrorResponse } from "@nestri/core/error";
|
||||
|
||||
export const ErrorResponses = {
|
||||
/**Validation error*/
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Validation error",
|
||||
example: {
|
||||
type: "validation",
|
||||
code: "invalid_parameter",
|
||||
message: "The request was invalid",
|
||||
param: "email",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description:
|
||||
"Bad Request - The request could not be understood or was missing required parameters.",
|
||||
},
|
||||
/**Authentication Error*/
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Authentication error",
|
||||
example: {
|
||||
type: "authentication",
|
||||
code: "unauthorized",
|
||||
message: "Authentication required",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description:
|
||||
"Unauthorized - Authentication is required and has failed or has not been provided.",
|
||||
},
|
||||
/**Permission Error*/
|
||||
403: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Permission error",
|
||||
example: {
|
||||
type: "forbidden",
|
||||
code: "permission_denied",
|
||||
message: "You do not have permission to access this resource",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description:
|
||||
"Forbidden - You do not have permission to access this resource.",
|
||||
},
|
||||
/**Not Found Error*/
|
||||
404: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Not found error",
|
||||
example: {
|
||||
type: "not_found",
|
||||
code: "resource_not_found",
|
||||
message: "The requested resource could not be found",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description: "Not Found - The requested resource does not exist.",
|
||||
},
|
||||
/**Conflict Error*/
|
||||
409: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Conflict Error",
|
||||
example: {
|
||||
type: "already_exists",
|
||||
code: "resource_already_exists",
|
||||
message:
|
||||
"The resource could not be created because it already exists",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description:
|
||||
"Conflict - The resource could not be created because it already exists.",
|
||||
},
|
||||
/**Rate Limit Error*/
|
||||
429: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Rate limit error",
|
||||
example: {
|
||||
type: "rate_limit",
|
||||
code: "too_many_requests",
|
||||
message: "Rate limit exceeded",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description:
|
||||
"Too Many Requests - You have made too many requests in a short period of time.",
|
||||
},
|
||||
/**Internal Server Error*/
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(
|
||||
ErrorResponse.meta({
|
||||
description: "Server error",
|
||||
example: {
|
||||
type: "internal",
|
||||
code: "internal_error",
|
||||
message: "Internal server error",
|
||||
},
|
||||
}),
|
||||
),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error - Something went wrong on our end.",
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user