mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-12-19 04:55:29 +00:00
Compare commits
15 Commits
renovate/p
...
renovate/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b92d16c5ab | ||
| 82ede32aa7 | |||
| ab5da0d5c6 | |||
| 333dc46ebf | |||
| 3b6234de46 | |||
| a855004fd2 | |||
| fd29c6f682 | |||
| 86f4ce2bd8 | |||
|
|
16058b92b3 | ||
|
|
29ac70420e | ||
|
|
c136ece0c1 | ||
|
|
1aa15ed569 | ||
|
|
918a0eeab5 | ||
|
|
31d4befb3d | ||
|
|
6563e15123 |
@@ -33,6 +33,17 @@ const Jwt = t.Object({
|
|||||||
type Jwt = typeof Jwt.static;
|
type Jwt = typeof Jwt.static;
|
||||||
const validator = TypeCompiler.Compile(Jwt);
|
const validator = TypeCompiler.Compile(Jwt);
|
||||||
|
|
||||||
|
export async function verifyJwt(bearer: string) {
|
||||||
|
// @ts-expect-error ts can't understand that there's two overload idk why
|
||||||
|
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
|
||||||
|
issuer: process.env.JWT_ISSUER,
|
||||||
|
});
|
||||||
|
const raw = validator.Decode(payload);
|
||||||
|
const jwt = Value.Default(Jwt, raw) as Prettify<Jwt & { settings: Settings }>;
|
||||||
|
|
||||||
|
return { jwt };
|
||||||
|
}
|
||||||
|
|
||||||
export const auth = new Elysia({ name: "auth" })
|
export const auth = new Elysia({ name: "auth" })
|
||||||
.guard({
|
.guard({
|
||||||
headers: t.Object(
|
headers: t.Object(
|
||||||
@@ -50,18 +61,8 @@ export const auth = new Elysia({ name: "auth" })
|
|||||||
message: "No authorization header was found.",
|
message: "No authorization header was found.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// @ts-expect-error ts can't understand that there's two overload idk why
|
return await verifyJwt(bearer);
|
||||||
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
|
|
||||||
issuer: process.env.JWT_ISSUER,
|
|
||||||
});
|
|
||||||
const raw = validator.Decode(payload);
|
|
||||||
const jwt = Value.Default(Jwt, raw) as Prettify<
|
|
||||||
Jwt & { settings: Settings }
|
|
||||||
>;
|
|
||||||
|
|
||||||
return { jwt };
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return status(403, {
|
return status(403, {
|
||||||
status: 403,
|
status: 403,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { videosReadH, videosWriteH } from "./controllers/videos";
|
|||||||
import { db } from "./db";
|
import { db } from "./db";
|
||||||
import type { KError } from "./models/error";
|
import type { KError } from "./models/error";
|
||||||
import { otel } from "./otel";
|
import { otel } from "./otel";
|
||||||
|
import { appWs } from "./websockets";
|
||||||
|
|
||||||
export const base = new Elysia({ name: "base" })
|
export const base = new Elysia({ name: "base" })
|
||||||
.onError(({ code, error }) => {
|
.onError(({ code, error }) => {
|
||||||
@@ -91,8 +92,9 @@ export const base = new Elysia({ name: "base" })
|
|||||||
export const prefix = "/api";
|
export const prefix = "/api";
|
||||||
export const handlers = new Elysia({ prefix })
|
export const handlers = new Elysia({ prefix })
|
||||||
.use(base)
|
.use(base)
|
||||||
.use(auth)
|
|
||||||
.use(otel)
|
.use(otel)
|
||||||
|
.use(appWs)
|
||||||
|
.use(auth)
|
||||||
.guard(
|
.guard(
|
||||||
{
|
{
|
||||||
// Those are not applied for now. See https://github.com/elysiajs/elysia/issues/1139
|
// Those are not applied for now. See https://github.com/elysiajs/elysia/issues/1139
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
import { and, count, eq, exists, gt, isNotNull, ne, sql } from "drizzle-orm";
|
import {
|
||||||
|
and,
|
||||||
|
count,
|
||||||
|
eq,
|
||||||
|
exists,
|
||||||
|
gt,
|
||||||
|
isNotNull,
|
||||||
|
lte,
|
||||||
|
ne,
|
||||||
|
sql,
|
||||||
|
TransactionRollbackError,
|
||||||
|
} from "drizzle-orm";
|
||||||
import { alias } from "drizzle-orm/pg-core";
|
import { alias } from "drizzle-orm/pg-core";
|
||||||
import Elysia, { t } from "elysia";
|
import Elysia, { t } from "elysia";
|
||||||
import { auth, getUserInfo } from "~/auth";
|
import { auth, getUserInfo } from "~/auth";
|
||||||
import { db } from "~/db";
|
import { db, type Transaction } from "~/db";
|
||||||
import { entries, history, profiles, shows, videos } from "~/db/schema";
|
import { entries, history, profiles, shows, videos } from "~/db/schema";
|
||||||
import { watchlist } from "~/db/schema/watchlist";
|
import { watchlist } from "~/db/schema/watchlist";
|
||||||
import { coalesce, values } from "~/db/utils";
|
import { coalesce, sqlarr } from "~/db/utils";
|
||||||
import { Entry } from "~/models/entry";
|
import { Entry } from "~/models/entry";
|
||||||
import { KError } from "~/models/error";
|
import { KError } from "~/models/error";
|
||||||
import { SeedHistory } from "~/models/history";
|
import { SeedHistory } from "~/models/history";
|
||||||
@@ -19,6 +30,7 @@ import {
|
|||||||
} from "~/models/utils";
|
} from "~/models/utils";
|
||||||
import { desc } from "~/models/utils/descriptions";
|
import { desc } from "~/models/utils/descriptions";
|
||||||
import type { WatchlistStatus } from "~/models/watchlist";
|
import type { WatchlistStatus } from "~/models/watchlist";
|
||||||
|
import { traverse } from "~/utils";
|
||||||
import {
|
import {
|
||||||
entryFilters,
|
entryFilters,
|
||||||
entryProgressQ,
|
entryProgressQ,
|
||||||
@@ -27,6 +39,275 @@ import {
|
|||||||
} from "../entries";
|
} from "../entries";
|
||||||
import { getOrCreateProfile } from "./profile";
|
import { getOrCreateProfile } from "./profile";
|
||||||
|
|
||||||
|
export async function updateProgress(userPk: number, progress: SeedHistory[]) {
|
||||||
|
try {
|
||||||
|
return await db.transaction(async (tx) => {
|
||||||
|
const hist = await updateHistory(tx, userPk, progress);
|
||||||
|
if (hist.created.length + hist.updated.length !== progress.length) {
|
||||||
|
tx.rollback();
|
||||||
|
}
|
||||||
|
// only return new and entries whose status has changed.
|
||||||
|
// we don't need to update the watchlist every 10s when watching a video.
|
||||||
|
await updateWatchlist(tx, userPk, [
|
||||||
|
...hist.created,
|
||||||
|
...hist.updated.filter((x) => x.percent >= 95),
|
||||||
|
]);
|
||||||
|
return { status: 201, inserted: hist.created.length } as const;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
if (!(e instanceof TransactionRollbackError)) throw e;
|
||||||
|
return {
|
||||||
|
status: 404,
|
||||||
|
message: "Invalid entry id/slug in progress array",
|
||||||
|
} as const;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateHistory(
|
||||||
|
dbTx: Transaction,
|
||||||
|
userPk: number,
|
||||||
|
progress: SeedHistory[],
|
||||||
|
) {
|
||||||
|
return dbTx.transaction(async (tx) => {
|
||||||
|
// `for("update", { of: history })` will put the `kyoo.history` instead
|
||||||
|
// of `history` in the sql and that triggers a sql error.
|
||||||
|
const existing = (
|
||||||
|
await tx
|
||||||
|
.select({ videoId: videos.id })
|
||||||
|
.from(history)
|
||||||
|
.for("update", { of: sql`history` as any })
|
||||||
|
.leftJoin(videos, eq(videos.pk, history.videoPk))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(history.profilePk, userPk),
|
||||||
|
lte(sql`now() - ${history.playedDate}`, sql`interval '1 day'`),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
).map((x) => x.videoId);
|
||||||
|
|
||||||
|
const toUpdate = traverse(
|
||||||
|
progress.filter((x) => existing.includes(x.videoId)),
|
||||||
|
);
|
||||||
|
const newEntries = traverse(
|
||||||
|
progress
|
||||||
|
.filter((x) => !existing.includes(x.videoId))
|
||||||
|
.map((x) => ({ ...x, entryUseid: isUuid(x.entry) })),
|
||||||
|
);
|
||||||
|
|
||||||
|
const updated =
|
||||||
|
toUpdate === null
|
||||||
|
? []
|
||||||
|
: await tx
|
||||||
|
.update(history)
|
||||||
|
.set({
|
||||||
|
time: sql`hist.ts`,
|
||||||
|
percent: sql`hist.percent`,
|
||||||
|
playedDate: coalesce(sql`hist.played_date`, sql`now()`),
|
||||||
|
})
|
||||||
|
.from(sql`unnest(
|
||||||
|
${sqlarr(toUpdate.videoId)}::uuid[],
|
||||||
|
${sqlarr(toUpdate.time)}::integer[],
|
||||||
|
${sqlarr(toUpdate.percent)}::integer[],
|
||||||
|
${sqlarr(toUpdate.playedDate)}::timestamp[]
|
||||||
|
) as hist(video_id, ts, percent, played_date)`)
|
||||||
|
.innerJoin(videos, eq(videos.id, sql`hist.video_id`))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(history.profilePk, userPk),
|
||||||
|
eq(history.videoPk, videos.pk),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.returning({
|
||||||
|
entryPk: history.entryPk,
|
||||||
|
videoPk: history.videoPk,
|
||||||
|
percent: history.percent,
|
||||||
|
playedDate: history.playedDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
const created =
|
||||||
|
newEntries === null
|
||||||
|
? []
|
||||||
|
: await tx
|
||||||
|
.insert(history)
|
||||||
|
.select(
|
||||||
|
db
|
||||||
|
.select({
|
||||||
|
profilePk: sql`${userPk}`.as("profilePk"),
|
||||||
|
videoPk: videos.pk,
|
||||||
|
entryPk: entries.pk,
|
||||||
|
percent: sql`hist.percent`.as("percent"),
|
||||||
|
time: sql`hist.ts`.as("time"),
|
||||||
|
playedDate: coalesce(sql`hist.played_date`, sql`now()`).as(
|
||||||
|
"playedDate",
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.from(sql`unnest(
|
||||||
|
${sqlarr(newEntries.entry)}::text[],
|
||||||
|
${sqlarr(newEntries.entryUseid)}::boolean[],
|
||||||
|
${sqlarr(newEntries.videoId)}::uuid[],
|
||||||
|
${sqlarr(newEntries.time)}::integer[],
|
||||||
|
${sqlarr(newEntries.percent)}::integer[],
|
||||||
|
${sqlarr(newEntries.playedDate)}::timestamptz[]
|
||||||
|
) as hist(entry, entry_use_id, video_id, ts, percent, played_date)`)
|
||||||
|
.innerJoin(
|
||||||
|
entries,
|
||||||
|
sql`
|
||||||
|
case
|
||||||
|
when hist.entry_use_id then ${entries.id} = hist.entry::uuid
|
||||||
|
else ${entries.slug} = hist.entry
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.leftJoin(videos, eq(videos.id, sql`hist.video_id`)),
|
||||||
|
)
|
||||||
|
.returning({
|
||||||
|
entryPk: history.entryPk,
|
||||||
|
videoPk: history.videoPk,
|
||||||
|
percent: history.percent,
|
||||||
|
playedDate: history.playedDate,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { created, updated };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateWatchlist(
|
||||||
|
tx: Transaction,
|
||||||
|
userPk: number,
|
||||||
|
histArr: {
|
||||||
|
entryPk: number;
|
||||||
|
percent: number;
|
||||||
|
playedDate: string;
|
||||||
|
}[],
|
||||||
|
) {
|
||||||
|
if (histArr.length === 0) return;
|
||||||
|
|
||||||
|
const nextEntry = alias(entries, "next_entry");
|
||||||
|
const nextEntryQ = tx
|
||||||
|
.select({
|
||||||
|
pk: nextEntry.pk,
|
||||||
|
})
|
||||||
|
.from(nextEntry)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(nextEntry.showPk, entries.showPk),
|
||||||
|
ne(nextEntry.kind, "extra"),
|
||||||
|
gt(nextEntry.order, entries.order),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.orderBy(nextEntry.order)
|
||||||
|
.limit(1)
|
||||||
|
.as("nextEntryQ");
|
||||||
|
|
||||||
|
const seenCountQ = tx
|
||||||
|
.select({ c: count() })
|
||||||
|
.from(entries)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(entries.showPk, sql`excluded.show_pk`),
|
||||||
|
exists(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(history)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(history.profilePk, userPk),
|
||||||
|
eq(history.entryPk, entries.pk),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const showKindQ = tx
|
||||||
|
.select({ k: shows.kind })
|
||||||
|
.from(shows)
|
||||||
|
.where(eq(shows.pk, sql`excluded.show_pk`));
|
||||||
|
|
||||||
|
const hist = traverse(histArr)!;
|
||||||
|
await tx
|
||||||
|
.insert(watchlist)
|
||||||
|
.select(
|
||||||
|
db
|
||||||
|
.selectDistinctOn([entries.showPk], {
|
||||||
|
profilePk: sql`${userPk}`.as("profilePk"),
|
||||||
|
showPk: entries.showPk,
|
||||||
|
status: sql<WatchlistStatus>`
|
||||||
|
case
|
||||||
|
when
|
||||||
|
hist.percent >= 95
|
||||||
|
and ${nextEntryQ.pk} is null
|
||||||
|
then 'completed'::watchlist_status
|
||||||
|
else 'watching'::watchlist_status
|
||||||
|
end
|
||||||
|
`.as("status"),
|
||||||
|
seenCount: sql`
|
||||||
|
case
|
||||||
|
when ${entries.kind} = 'movie' then hist.percent
|
||||||
|
when hist.percent >= 95 then 1
|
||||||
|
else 0
|
||||||
|
end
|
||||||
|
`.as("seen_count"),
|
||||||
|
nextEntry: sql`
|
||||||
|
case
|
||||||
|
when hist.percent >= 95 then ${nextEntryQ.pk}
|
||||||
|
else ${entries.pk}
|
||||||
|
end
|
||||||
|
`.as("next_entry"),
|
||||||
|
score: sql`null`.as("score"),
|
||||||
|
startedAt: sql`hist.played_date`.as("startedAt"),
|
||||||
|
lastPlayedAt: sql`hist.played_date`.as("lastPlayedAt"),
|
||||||
|
completedAt: sql`
|
||||||
|
case
|
||||||
|
when ${nextEntryQ.pk} is null then hist.played_date
|
||||||
|
else null
|
||||||
|
end
|
||||||
|
`.as("completedAt"),
|
||||||
|
// see https://github.com/drizzle-team/drizzle-orm/issues/3608
|
||||||
|
updatedAt: sql`now()`.as("updatedAt"),
|
||||||
|
})
|
||||||
|
.from(sql`unnest(
|
||||||
|
${sqlarr(hist.entryPk)}::integer[],
|
||||||
|
${sqlarr(hist.percent)}::integer[],
|
||||||
|
${sqlarr(hist.playedDate)}::timestamptz[]
|
||||||
|
) as hist(entry_pk, percent, played_date)`)
|
||||||
|
.innerJoin(entries, eq(entries.pk, sql`hist.entry_pk`))
|
||||||
|
.leftJoinLateral(nextEntryQ, sql`true`),
|
||||||
|
)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [watchlist.profilePk, watchlist.showPk],
|
||||||
|
set: {
|
||||||
|
status: sql`
|
||||||
|
case
|
||||||
|
when excluded.status = 'completed' then excluded.status
|
||||||
|
when
|
||||||
|
${watchlist.status} != 'completed'
|
||||||
|
and ${watchlist.status} != 'rewatching'
|
||||||
|
then excluded.status
|
||||||
|
else ${watchlist.status}
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
seenCount: sql`
|
||||||
|
case
|
||||||
|
when ${showKindQ} = 'movie' then excluded.seen_count
|
||||||
|
else ${seenCountQ}
|
||||||
|
end`,
|
||||||
|
nextEntry: sql`
|
||||||
|
case
|
||||||
|
when ${watchlist.status} = 'completed' then null
|
||||||
|
else excluded.next_entry
|
||||||
|
end
|
||||||
|
`,
|
||||||
|
lastPlayedAt: sql`excluded.last_played_at`,
|
||||||
|
completedAt: coalesce(
|
||||||
|
watchlist.completedAt,
|
||||||
|
sql`excluded.completed_at`,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// this one is different than the normal progressQ because we want duplicates
|
||||||
const historyProgressQ: typeof entryProgressQ = db
|
const historyProgressQ: typeof entryProgressQ = db
|
||||||
.select({
|
.select({
|
||||||
percent: history.percent,
|
percent: history.percent,
|
||||||
@@ -37,7 +318,7 @@ const historyProgressQ: typeof entryProgressQ = db
|
|||||||
})
|
})
|
||||||
.from(history)
|
.from(history)
|
||||||
.leftJoin(videos, eq(history.videoPk, videos.pk))
|
.leftJoin(videos, eq(history.videoPk, videos.pk))
|
||||||
.leftJoin(profiles, eq(history.profilePk, profiles.pk))
|
.innerJoin(profiles, eq(history.profilePk, profiles.pk))
|
||||||
.where(eq(profiles.id, sql.placeholder("userId")))
|
.where(eq(profiles.id, sql.placeholder("userId")))
|
||||||
.as("progress");
|
.as("progress");
|
||||||
|
|
||||||
@@ -170,162 +451,8 @@ export const historyH = new Elysia({ tags: ["profiles"] })
|
|||||||
async ({ body, jwt: { sub }, status }) => {
|
async ({ body, jwt: { sub }, status }) => {
|
||||||
const profilePk = await getOrCreateProfile(sub);
|
const profilePk = await getOrCreateProfile(sub);
|
||||||
|
|
||||||
const hist = values(
|
const ret = await updateProgress(profilePk, body);
|
||||||
body.map((x) => ({ ...x, entryUseId: isUuid(x.entry) })),
|
return status(ret.status, ret);
|
||||||
{
|
|
||||||
percent: "integer",
|
|
||||||
time: "integer",
|
|
||||||
playedDate: "timestamptz",
|
|
||||||
videoId: "uuid",
|
|
||||||
},
|
|
||||||
).as("hist");
|
|
||||||
const valEqEntries = sql`
|
|
||||||
case
|
|
||||||
when hist.entryUseId::boolean then ${entries.id} = hist.entry::uuid
|
|
||||||
else ${entries.slug} = hist.entry
|
|
||||||
end
|
|
||||||
`;
|
|
||||||
|
|
||||||
const rows = await db
|
|
||||||
.insert(history)
|
|
||||||
.select(
|
|
||||||
db
|
|
||||||
.select({
|
|
||||||
profilePk: sql`${profilePk}`.as("profilePk"),
|
|
||||||
entryPk: entries.pk,
|
|
||||||
videoPk: videos.pk,
|
|
||||||
percent: sql`hist.percent`.as("percent"),
|
|
||||||
time: sql`hist.time`.as("time"),
|
|
||||||
playedDate: sql`hist.playedDate`.as("playedDate"),
|
|
||||||
})
|
|
||||||
.from(hist)
|
|
||||||
.innerJoin(entries, valEqEntries)
|
|
||||||
.leftJoin(videos, eq(videos.id, sql`hist.videoId`)),
|
|
||||||
)
|
|
||||||
.returning({ pk: history.pk });
|
|
||||||
|
|
||||||
// automatically update watchlist with this new info
|
|
||||||
|
|
||||||
const nextEntry = alias(entries, "next_entry");
|
|
||||||
const nextEntryQ = db
|
|
||||||
.select({
|
|
||||||
pk: nextEntry.pk,
|
|
||||||
})
|
|
||||||
.from(nextEntry)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(nextEntry.showPk, entries.showPk),
|
|
||||||
ne(nextEntry.kind, "extra"),
|
|
||||||
gt(nextEntry.order, entries.order),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.orderBy(nextEntry.order)
|
|
||||||
.limit(1)
|
|
||||||
.as("nextEntryQ");
|
|
||||||
|
|
||||||
const seenCountQ = db
|
|
||||||
.select({ c: count() })
|
|
||||||
.from(entries)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(entries.showPk, sql`excluded.show_pk`),
|
|
||||||
exists(
|
|
||||||
db
|
|
||||||
.select()
|
|
||||||
.from(history)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(history.profilePk, profilePk),
|
|
||||||
eq(history.entryPk, entries.pk),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
const showKindQ = db
|
|
||||||
.select({ k: shows.kind })
|
|
||||||
.from(shows)
|
|
||||||
.where(eq(shows.pk, sql`excluded.show_pk`));
|
|
||||||
|
|
||||||
await db
|
|
||||||
.insert(watchlist)
|
|
||||||
.select(
|
|
||||||
db
|
|
||||||
.select({
|
|
||||||
profilePk: sql`${profilePk}`.as("profilePk"),
|
|
||||||
showPk: entries.showPk,
|
|
||||||
status: sql<WatchlistStatus>`
|
|
||||||
case
|
|
||||||
when
|
|
||||||
hist.percent >= 95
|
|
||||||
and ${nextEntryQ.pk} is null
|
|
||||||
then 'completed'::watchlist_status
|
|
||||||
else 'watching'::watchlist_status
|
|
||||||
end
|
|
||||||
`.as("status"),
|
|
||||||
seenCount: sql`
|
|
||||||
case
|
|
||||||
when ${entries.kind} = 'movie' then hist.percent
|
|
||||||
when hist.percent >= 95 then 1
|
|
||||||
else 0
|
|
||||||
end
|
|
||||||
`.as("seen_count"),
|
|
||||||
nextEntry: sql`
|
|
||||||
case
|
|
||||||
when hist.percent >= 95 then ${nextEntryQ.pk}
|
|
||||||
else ${entries.pk}
|
|
||||||
end
|
|
||||||
`.as("next_entry"),
|
|
||||||
score: sql`null`.as("score"),
|
|
||||||
startedAt: sql`hist.playedDate`.as("startedAt"),
|
|
||||||
lastPlayedAt: sql`hist.playedDate`.as("lastPlayedAt"),
|
|
||||||
completedAt: sql`
|
|
||||||
case
|
|
||||||
when ${nextEntryQ.pk} is null then hist.playedDate
|
|
||||||
else null
|
|
||||||
end
|
|
||||||
`.as("completedAt"),
|
|
||||||
// see https://github.com/drizzle-team/drizzle-orm/issues/3608
|
|
||||||
updatedAt: sql`now()`.as("updatedAt"),
|
|
||||||
})
|
|
||||||
.from(hist)
|
|
||||||
.leftJoin(entries, valEqEntries)
|
|
||||||
.leftJoinLateral(nextEntryQ, sql`true`),
|
|
||||||
)
|
|
||||||
.onConflictDoUpdate({
|
|
||||||
target: [watchlist.profilePk, watchlist.showPk],
|
|
||||||
set: {
|
|
||||||
status: sql`
|
|
||||||
case
|
|
||||||
when excluded.status = 'completed' then excluded.status
|
|
||||||
when
|
|
||||||
${watchlist.status} != 'completed'
|
|
||||||
and ${watchlist.status} != 'rewatching'
|
|
||||||
then excluded.status
|
|
||||||
else ${watchlist.status}
|
|
||||||
end
|
|
||||||
`,
|
|
||||||
seenCount: sql`
|
|
||||||
case
|
|
||||||
when ${showKindQ} = 'movie' then excluded.seen_count
|
|
||||||
else ${seenCountQ}
|
|
||||||
end`,
|
|
||||||
nextEntry: sql`
|
|
||||||
case
|
|
||||||
when ${watchlist.status} = 'completed' then null
|
|
||||||
else excluded.next_entry
|
|
||||||
end
|
|
||||||
`,
|
|
||||||
lastPlayedAt: sql`excluded.last_played_at`,
|
|
||||||
completedAt: coalesce(
|
|
||||||
watchlist.completedAt,
|
|
||||||
sql`excluded.completed_at`,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return status(201, { status: 201, inserted: rows.length });
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
detail: { description: "Bulk add entries/movies to your watch history." },
|
detail: { description: "Bulk add entries/movies to your watch history." },
|
||||||
@@ -338,6 +465,10 @@ export const historyH = new Elysia({ tags: ["profiles"] })
|
|||||||
description: "The number of history entry inserted",
|
description: "The number of history entry inserted",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
404: {
|
||||||
|
...KError,
|
||||||
|
description: "No entry found with the given id or slug.",
|
||||||
|
},
|
||||||
422: KError,
|
422: KError,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export const history = schema.table(
|
|||||||
profilePk: integer()
|
profilePk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => profiles.pk, { onDelete: "cascade" }),
|
.references(() => profiles.pk, { onDelete: "cascade" }),
|
||||||
|
// we need to attach an history to an entry because we want to keep history
|
||||||
|
// when we delete a video file
|
||||||
entryPk: integer()
|
entryPk: integer()
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => entries.pk, { onDelete: "cascade" }),
|
.references(() => entries.pk, { onDelete: "cascade" }),
|
||||||
|
|||||||
@@ -92,36 +92,6 @@ export function sqlarr(array: unknown[]): string {
|
|||||||
.join(", ")}}`;
|
.join(", ")}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://github.com/drizzle-team/drizzle-orm/issues/4044
|
|
||||||
export function values<K extends string>(
|
|
||||||
items: Record<K, unknown>[],
|
|
||||||
typeInfo: Partial<Record<K, string>> = {},
|
|
||||||
) {
|
|
||||||
if (items[0] === undefined)
|
|
||||||
throw new Error("Invalid values, expecting at least one items");
|
|
||||||
const [firstProp, ...props] = Object.keys(items[0]) as K[];
|
|
||||||
const values = items
|
|
||||||
.map((x, i) => {
|
|
||||||
let ret = sql`(${x[firstProp]}`;
|
|
||||||
if (i === 0 && typeInfo[firstProp])
|
|
||||||
ret = sql`${ret}::${sql.raw(typeInfo[firstProp])}`;
|
|
||||||
for (const val of props) {
|
|
||||||
ret = sql`${ret}, ${x[val]}`;
|
|
||||||
if (i === 0 && typeInfo[val])
|
|
||||||
ret = sql`${ret}::${sql.raw(typeInfo[val])}`;
|
|
||||||
}
|
|
||||||
return sql`${ret})`;
|
|
||||||
})
|
|
||||||
.reduce((acc, x) => sql`${acc}, ${x}`);
|
|
||||||
const valueNames = [firstProp, ...props].join(", ");
|
|
||||||
|
|
||||||
return {
|
|
||||||
as: (name: string) => {
|
|
||||||
return sql`(values ${values}) as ${sql.raw(name)}(${sql.raw(valueNames)})`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* goal:
|
/* goal:
|
||||||
* unnestValues([{a: 1, b: 2}, {a: 3, b: 4}], tbl)
|
* unnestValues([{a: 1, b: 2}, {a: 3, b: 4}], tbl)
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ export const Progress = t.Object({
|
|||||||
export type Progress = typeof Progress.static;
|
export type Progress = typeof Progress.static;
|
||||||
|
|
||||||
export const SeedHistory = t.Intersect([
|
export const SeedHistory = t.Intersect([
|
||||||
|
Progress,
|
||||||
t.Object({
|
t.Object({
|
||||||
entry: t.String({
|
entry: t.String({
|
||||||
description: "Id or slug of the entry/movie you watched",
|
description: "Id or slug of the entry/movie you watched",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
Progress,
|
|
||||||
]);
|
]);
|
||||||
export type SeedHistory = typeof SeedHistory.static;
|
export type SeedHistory = typeof SeedHistory.static;
|
||||||
|
|||||||
@@ -38,3 +38,21 @@ export function uniqBy<T>(a: T[], key: (val: T) => string): T[] {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function traverse<T extends Record<string, any>>(
|
||||||
|
arr: T[],
|
||||||
|
): { [K in keyof T]: T[K][] } | null {
|
||||||
|
if (arr.length === 0) return null;
|
||||||
|
|
||||||
|
const result = {} as { [K in keyof T]: T[K][] };
|
||||||
|
arr.forEach((obj, i) => {
|
||||||
|
for (const key in obj) {
|
||||||
|
if (!result[key]) {
|
||||||
|
result[key] = new Array(i).fill(null);
|
||||||
|
}
|
||||||
|
result[key].push(obj[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
102
api/src/websockets.ts
Normal file
102
api/src/websockets.ts
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import type { TObject, TString } from "@sinclair/typebox";
|
||||||
|
import Elysia, { type TSchema, t } from "elysia";
|
||||||
|
import { verifyJwt } from "./auth";
|
||||||
|
import { updateProgress } from "./controllers/profiles/history";
|
||||||
|
import { getOrCreateProfile } from "./controllers/profiles/profile";
|
||||||
|
import { SeedHistory } from "./models/history";
|
||||||
|
|
||||||
|
const actionMap = {
|
||||||
|
ping: handler({
|
||||||
|
message(ws) {
|
||||||
|
ws.send({ response: "pong" });
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
watch: handler({
|
||||||
|
body: t.Omit(SeedHistory, ["playedDate"]),
|
||||||
|
permissions: ["core.read"],
|
||||||
|
async message(ws, body) {
|
||||||
|
const profilePk = await getOrCreateProfile(ws.data.jwt.sub);
|
||||||
|
|
||||||
|
const ret = await updateProgress(profilePk, [
|
||||||
|
{ ...body, playedDate: null },
|
||||||
|
]);
|
||||||
|
ws.send(ret);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const baseWs = new Elysia()
|
||||||
|
.guard({
|
||||||
|
headers: t.Object(
|
||||||
|
{
|
||||||
|
authorization: t.Optional(t.TemplateLiteral("Bearer ${string}")),
|
||||||
|
"Sec-WebSocket-Protocol": t.Optional(
|
||||||
|
t.Array(
|
||||||
|
t.Union([t.Literal("kyoo"), t.TemplateLiteral("Bearer ${string}")]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{ additionalProperties: true },
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.resolve(
|
||||||
|
async ({
|
||||||
|
headers: { authorization, "Sec-WebSocket-Protocol": wsProtocol },
|
||||||
|
status,
|
||||||
|
}) => {
|
||||||
|
const auth =
|
||||||
|
authorization ??
|
||||||
|
(wsProtocol?.length === 2 &&
|
||||||
|
wsProtocol[0] === "kyoo" &&
|
||||||
|
wsProtocol[1].startsWith("Bearer ")
|
||||||
|
? wsProtocol[1]
|
||||||
|
: null);
|
||||||
|
const bearer = auth?.slice(7);
|
||||||
|
if (!bearer) {
|
||||||
|
return status(403, {
|
||||||
|
status: 403,
|
||||||
|
message: "No authorization header was found.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await verifyJwt(bearer);
|
||||||
|
} catch (err) {
|
||||||
|
return status(403, {
|
||||||
|
status: 403,
|
||||||
|
message: "Invalid jwt. Verification vailed",
|
||||||
|
details: err,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export const appWs = baseWs.ws("/ws", {
|
||||||
|
body: t.Union(
|
||||||
|
Object.entries(actionMap).map(([k, v]) =>
|
||||||
|
t.Intersect([t.Object({ action: t.Literal(k) }), v.body ?? t.Object({})]),
|
||||||
|
),
|
||||||
|
) as unknown as TObject<{ action: TString }>,
|
||||||
|
async open(ws) {
|
||||||
|
if (!ws.data.jwt.sub) {
|
||||||
|
ws.close(3000, "Unauthorized");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async message(ws, { action, ...body }) {
|
||||||
|
const handler = actionMap[action as keyof typeof actionMap];
|
||||||
|
for (const perm of handler.permissions ?? []) {
|
||||||
|
if (!ws.data.jwt.permissions.includes(perm)) {
|
||||||
|
return ws.close(3000, `Missing permission: '${perm}'.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await handler.message(ws as any, body as any);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type Ws = Parameters<NonNullable<Parameters<typeof baseWs.ws>[1]["open"]>>[0];
|
||||||
|
function handler<Schema extends TSchema = TObject<{}>>(ret: {
|
||||||
|
body?: Schema;
|
||||||
|
permissions?: string[];
|
||||||
|
message: (ws: Ws, body: Schema["static"]) => void | Promise<void>;
|
||||||
|
}) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
10
auth/go.mod
10
auth/go.mod
@@ -6,7 +6,7 @@ toolchain go1.25.5
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alexedwards/argon2id v1.0.0
|
github.com/alexedwards/argon2id v1.0.0
|
||||||
github.com/exaring/otelpgx v0.9.3
|
github.com/exaring/otelpgx v0.9.4
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
github.com/jackc/pgx/v5 v5.7.6
|
||||||
@@ -15,8 +15,8 @@ require (
|
|||||||
github.com/lestrrat-go/jwx/v3 v3.0.12
|
github.com/lestrrat-go/jwx/v3 v3.0.12
|
||||||
github.com/swaggo/echo-swagger v1.4.1
|
github.com/swaggo/echo-swagger v1.4.1
|
||||||
github.com/swaggo/swag v1.16.6
|
github.com/swaggo/swag v1.16.6
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0
|
||||||
go.opentelemetry.io/otel v1.39.0
|
go.opentelemetry.io/otel v1.39.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0
|
||||||
@@ -55,7 +55,7 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
@@ -63,7 +63,7 @@ require (
|
|||||||
github.com/go-openapi/swag v0.23.1 // indirect
|
github.com/go-openapi/swag v0.23.1 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.28.0
|
github.com/go-playground/validator/v10 v10.29.0
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
github.com/golang-migrate/migrate/v4 v4.19.1
|
||||||
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6
|
github.com/jackc/pgerrcode v0.0.0-20250907135507-afb5586c32a6
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
|
|||||||
24
auth/go.sum
24
auth/go.sum
@@ -29,12 +29,12 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
|
|||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/exaring/otelpgx v0.9.3 h1:4yO02tXC7ZJZ+hcqcUkfxblYNCIFGVhpUWI0iw1TzPU=
|
github.com/exaring/otelpgx v0.9.4 h1:V0XdEPXAaeBteeL8WbEPLWVCwKh3Be2aVX7/vCBpli4=
|
||||||
github.com/exaring/otelpgx v0.9.3/go.mod h1:R5/M5LWsPPBZc1SrRE5e0DiU48bI78C1/GPTWs6I66U=
|
github.com/exaring/otelpgx v0.9.4/go.mod h1:R5/M5LWsPPBZc1SrRE5e0DiU48bI78C1/GPTWs6I66U=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
@@ -56,8 +56,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
|
||||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
|
||||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
@@ -163,14 +163,14 @@ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
|
|||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0 h1:eypSOd+0txRKCXPNyqLPsbSfA0jULgJcGmSAdFAnrCM=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0/go.mod h1:CRGvIBL/aAxpQU34ZxyQVFlovVcp67s4cAmQu8Jh9mc=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0 h1:6YeICKmGrvgJ5th4+OMNpcuoB6q/Xs8gt0YCO7MUv1k=
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0 h1:9PCiXc7BmfD7+BI8POoc3bQSoRSEo01eNqPVu1/+pDY=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0/go.mod h1:ZEA7j2B35siNV0T00aapacNzjz4tvOlNoHp0ncCfwNQ=
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0/go.mod h1:NGBbj2Bgb5Oe/35f9WaU3qRnOey+7X+bxnnSS5zzvLA=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
|
go.opentelemetry.io/contrib/propagators/b3 v1.39.0 h1:PI7pt9pkSnimWcp5sQhUA9OzLbc3Ba4sL+VEUTNsxrk=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU=
|
go.opentelemetry.io/contrib/propagators/b3 v1.39.0/go.mod h1:5gV/EzPnfYIwjzj+6y8tbGW2PKWhcsz5e/7twptRVQY=
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
- name: postgres
|
- name: postgres
|
||||||
repository: oci://registry-1.docker.io/cloudpirates
|
repository: oci://registry-1.docker.io/cloudpirates
|
||||||
version: 0.12.4
|
version: 0.13.4
|
||||||
digest: sha256:e486b44703c7a97eee25f7715ab040d197d79c41ea1c422ae009b1f68985f544
|
digest: sha256:5bd757786798fcd85a9645fd2a387a6a57a73eaca63830ae3d7fad279f23a0b3
|
||||||
generated: "2025-12-01T20:17:25.152279487+01:00"
|
generated: "2025-12-17T20:04:52.09437115Z"
|
||||||
|
|||||||
@@ -12,4 +12,4 @@ dependencies:
|
|||||||
- condition: postgres.enabled
|
- condition: postgres.enabled
|
||||||
name: postgres
|
name: postgres
|
||||||
repository: oci://registry-1.docker.io/cloudpirates
|
repository: oci://registry-1.docker.io/cloudpirates
|
||||||
version: 0.12.4
|
version: 0.13.4
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ go 1.24.2
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asticode/go-astisub v0.38.0
|
github.com/asticode/go-astisub v0.38.0
|
||||||
github.com/aws/aws-sdk-go-v2 v1.40.1
|
github.com/aws/aws-sdk-go-v2 v1.41.0
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/exaring/otelpgx v0.9.3
|
github.com/exaring/otelpgx v0.9.4
|
||||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
github.com/golang-migrate/migrate/v4 v4.19.1
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
github.com/jackc/pgx/v5 v5.7.6
|
||||||
github.com/labstack/echo-jwt/v4 v4.4.0
|
github.com/labstack/echo-jwt/v4 v4.4.0
|
||||||
@@ -15,8 +15,8 @@ require (
|
|||||||
github.com/swaggo/echo-swagger v1.4.1
|
github.com/swaggo/echo-swagger v1.4.1
|
||||||
github.com/swaggo/swag v1.16.6
|
github.com/swaggo/swag v1.16.6
|
||||||
gitlab.com/opennota/screengen v1.0.2
|
gitlab.com/opennota/screengen v1.0.2
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0
|
||||||
go.opentelemetry.io/otel v1.39.0
|
go.opentelemetry.io/otel v1.39.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0
|
||||||
@@ -38,7 +38,7 @@ require (
|
|||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/asticode/go-astikit v0.57.1 // indirect
|
github.com/asticode/go-astikit v0.57.1 // indirect
|
||||||
github.com/asticode/go-astits v1.14.0 // indirect
|
github.com/asticode/go-astits v1.14.0 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
@@ -76,20 +76,20 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.3
|
github.com/aws/aws-sdk-go-v2/config v1.32.5
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
|
||||||
github.com/aws/smithy-go v1.24.0 // indirect
|
github.com/aws/smithy-go v1.24.0 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
|||||||
@@ -13,42 +13,42 @@ github.com/asticode/go-astisub v0.38.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2z
|
|||||||
github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
|
github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
|
||||||
github.com/asticode/go-astits v1.14.0 h1:zkgnZzipx2XX5mWycqsSBeEyDH58+i4HtyF4j2ROb00=
|
github.com/asticode/go-astits v1.14.0 h1:zkgnZzipx2XX5mWycqsSBeEyDH58+i4HtyF4j2ROb00=
|
||||||
github.com/asticode/go-astits v1.14.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
|
github.com/asticode/go-astits v1.14.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.40.1 h1:difXb4maDZkRH0x//Qkwcfpdg1XQVXEAEs2DdXldFFc=
|
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.40.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.3 h1:cpz7H2uMNTDa0h/5CYL5dLUEzPSLo2g0NkbxTRJtSSU=
|
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.3/go.mod h1:srtPKaJJe3McW6T/+GMBZyIPc+SeqJsNPJsd4mOYZ6s=
|
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3 h1:01Ym72hK43hjwDeJUfi1l2oYLXBAOR8gNSZNmXmvuas=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.3/go.mod h1:55nWF/Sr9Zvls0bGnWkRxUdhzKqj9uRNlPvgV1vgxKc=
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15 h1:utxLraaifrSBkeyII9mIbVwXXWrZdlPO7FIKmyLCEcY=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.15/go.mod h1:hW6zjYUDQwfz3icf4g2O41PHi77u10oAzJ84iSzR/lo=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15 h1:Y5YXgygXwDI5P4RkteB5yF7v35neH7LfJKBG+hzIons=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.15/go.mod h1:K+/1EpG42dFSY7CBj+Fruzm8PsCGWTXJ3jdeJ659oGQ=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15 h1:AvltKnW9ewxX2hFmQS0FyJH93aSvJVUEFvXfU+HWtSE=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.15/go.mod h1:3I4oCdZdmgrREhU74qS1dK9yZ62yumob+58AbFR4cQA=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15 h1:NLYTEyZmVZo0Qh183sC8nC+ydJXOOeIL/qI/sS3PdLY=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.15/go.mod h1:Z803iB3B0bc8oJV8zH2PERLRfQUJ2n2BXISpsA4+O1M=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6 h1:P1MU/SuhadGvg2jtviDXPEejU3jBNhoeeAlRadHzvHI=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.6/go.mod h1:5KYaMG6wmVKMFBSfWoyG/zH8pWwzQFnKgpoSRlXHKdQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15 h1:3/u/4yZOffg5jdNk1sDpOQ4Y+R6Xbh+GzpDrSZjuy3U=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.15/go.mod h1:4Zkjq0FKjE78NKjabuM4tRXKFzUJWXgP0ItEZK8l7JU=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15 h1:wsSQ4SVz5YE1crz0Ap7VBZrV4nNqZt4CIBBT8mnwoNc=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.15/go.mod h1:I7sditnFGtYMIqPRU1QoHZAUrXkGp4SczmlLwrNPlD0=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0 h1:IrbE3B8O9pm3lsg96AXIN5MXX4pECEuExh/A0Du3AuI=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2 h1:U3ygWUhCpiSPYSHOrRhb3gOl9T5Y3kB8k5Vjs//57bE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.0/go.mod h1:/sJLzHtiiZvs6C1RbxS/anSAFwZD6oC6M/kotQzOiLw=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.93.2/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3 h1:d/6xOGIllc/XW1lzG9a4AUBMmpLA9PXcQnVPTuHHcik=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.3/go.mod h1:fQ7E7Qj9GiW8y0ClD7cUJk3Bz5Iw8wZkWDHsTe8vDKs=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6 h1:8sTTiw+9yuNXcfWeqKF2x01GqCF49CpP4Z9nKrrk/ts=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.6/go.mod h1:8WYg+Y40Sn3X2hioaaWAAIngndR8n1XFdRPPX+7QBaM=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11 h1:E+KqWoVsSrj1tJ6I/fjDIu5xoS2Zacuu1zT+H7KtiIk=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.11/go.mod h1:qyWHz+4lvkXcr3+PoGlGHEI+3DLLiU6/GdrFfMaAhB0=
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3 h1:tzMkjh0yTChUqJDgGkcDdxvZDSrJ/WB6R6ymI5ehqJI=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.3/go.mod h1:T270C0R5sZNLbWUe8ueiAF42XSZxxPocTaGSgs5c/60=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
|
||||||
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
|
||||||
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
@@ -76,8 +76,8 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
|
|||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/exaring/otelpgx v0.9.3 h1:4yO02tXC7ZJZ+hcqcUkfxblYNCIFGVhpUWI0iw1TzPU=
|
github.com/exaring/otelpgx v0.9.4 h1:V0XdEPXAaeBteeL8WbEPLWVCwKh3Be2aVX7/vCBpli4=
|
||||||
github.com/exaring/otelpgx v0.9.3/go.mod h1:R5/M5LWsPPBZc1SrRE5e0DiU48bI78C1/GPTWs6I66U=
|
github.com/exaring/otelpgx v0.9.4/go.mod h1:R5/M5LWsPPBZc1SrRE5e0DiU48bI78C1/GPTWs6I66U=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
@@ -213,14 +213,14 @@ gitlab.com/opennota/screengen v1.0.2 h1:GxYTJdAPEzmg5v5CV4dgn45JVW+EcXXAvCxhE7w6
|
|||||||
gitlab.com/opennota/screengen v1.0.2/go.mod h1:4kED4yriw2zslwYmXFCa5qCvEKwleBA7l5OE+d94NTU=
|
gitlab.com/opennota/screengen v1.0.2/go.mod h1:4kED4yriw2zslwYmXFCa5qCvEKwleBA7l5OE+d94NTU=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0 h1:bwnLpizECbPr1RrQ27waeY2SPIPeccCx/xLuoYADZ9s=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0 h1:eypSOd+0txRKCXPNyqLPsbSfA0jULgJcGmSAdFAnrCM=
|
||||||
go.opentelemetry.io/contrib/bridges/otelslog v0.13.0/go.mod h1:3nWlOiiqA9UtUnrcNk82mYasNxD8ehOspL0gOfEo6Y4=
|
go.opentelemetry.io/contrib/bridges/otelslog v0.14.0/go.mod h1:CRGvIBL/aAxpQU34ZxyQVFlovVcp67s4cAmQu8Jh9mc=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0 h1:6YeICKmGrvgJ5th4+OMNpcuoB6q/Xs8gt0YCO7MUv1k=
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0 h1:9PCiXc7BmfD7+BI8POoc3bQSoRSEo01eNqPVu1/+pDY=
|
||||||
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.63.0/go.mod h1:ZEA7j2B35siNV0T00aapacNzjz4tvOlNoHp0ncCfwNQ=
|
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.64.0/go.mod h1:NGBbj2Bgb5Oe/35f9WaU3qRnOey+7X+bxnnSS5zzvLA=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
|
go.opentelemetry.io/contrib/propagators/b3 v1.39.0 h1:PI7pt9pkSnimWcp5sQhUA9OzLbc3Ba4sL+VEUTNsxrk=
|
||||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU=
|
go.opentelemetry.io/contrib/propagators/b3 v1.39.0/go.mod h1:5gV/EzPnfYIwjzj+6y8tbGW2PKWhcsz5e/7twptRVQY=
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM=
|
||||||
|
|||||||
Reference in New Issue
Block a user