Compare commits

..

3 Commits

Author SHA1 Message Date
Marek Maslowski 8a7b874ac0 Merge ff3a7ddbf0 into 002ea91be8 2026-04-24 17:03:08 +00:00
Marek Maslowski ff3a7ddbf0 adding permission check for creation and delete of links 2026-04-24 18:52:07 +02:00
Marek Maslowski 3a3267d998 v1 2026-04-24 18:52:07 +02:00
255 changed files with 1172 additions and 191437 deletions
-121
View File
@@ -1,121 +0,0 @@
# Trademark Policy
## Introduction
This is the TREK project's policy for the use of our trademarks. While TREK is
available under the GNU Affero General Public License v3.0 (AGPL-3.0), that
license does not include a license to use our trademarks.
This policy describes how you may use our trademarks. Our goal is to strike a
balance between: 1) our need to ensure that our trademarks remain reliable
indicators of the software we release; and 2) our community members' desire to
be full participants in the TREK project.
## Our trademarks
This policy covers the name "TREK" as well as any associated logos, trade dress,
goodwill, or designs (our "Marks").
## In general
Whenever you use our Marks, you must always do so in a way that does not mislead
anyone about exactly who is the source of the software. For example, you cannot
say you are distributing TREK when you're distributing a modified version of it,
because people would think they would be getting the same software that they
can get directly from us when they aren't. You also cannot use our Marks on
your website in a way that suggests that your website is an official TREK
website or that we endorse your website. But, if true, you can say you like
TREK, that you participate in the TREK community, that you are providing an
unmodified version of TREK, or that you wrote a guide describing how to use
TREK.
This fundamental requirement, that it is always clear to people what they are
getting and from whom, is reflected throughout this policy. It should also
serve as your guide if you are not sure about how you are using the Marks.
In addition:
* You may not use or register, in whole or in part, the Marks as part of your
own trademark, service mark, domain name, company name, trade name, product
name or service name.
* Trademark law does not allow your use of names or trademarks that are too
similar to ours. You therefore may not use an obvious variation of any of our
Marks or any phonetic equivalent, foreign language equivalent, takeoff, or
abbreviation for a similar or compatible product or service.
* You agree that you will not acquire any rights in the Marks and that any
goodwill generated by your use of the Marks and participation in our
community inures solely to our benefit.
## Distribution of unmodified source code or unmodified executable code we have compiled
When you redistribute an unmodified copy of TREK, you are not changing the
quality or nature of it. Therefore, you may retain the Marks we have placed on
the software to identify your redistribution. This kind of use only applies if
you are redistributing an official TREK distribution that has not been changed
in any way.
## Distribution of executable code that you have compiled, or modified code
You may use the word mark "TREK", but not any TREK logos, to truthfully
describe the origin of the software that you are providing, that is, that the
code you are distributing is a modification of TREK. You may say, for example,
that "this software is derived from the source code for TREK."
Of course, you can place your own trademarks or logos on versions of the
software to which you have made substantive modifications, because by modifying
the software, you have become the origin of that exact version. In that case,
you should not use our Marks.
However, you may use our Marks for the distribution of code (source or
executable) on the condition that any executable is built from an official TREK
source code release and that any modifications are limited to switching on or
off features already included in the software, translations into other
languages, and incorporating minor bug-fix patches. Use of our Marks on any
further modification is not permitted.
## Mobile wrappers, hosted instances, and forks
The following clarifications apply specifically to common ways TREK is
redistributed:
* **Self-hosted instances of unmodified TREK.** You may refer to your instance
as "a TREK instance" or "running TREK." You may not name the service itself
in a way that suggests it is the official TREK ("TREK Cloud," "TREK
Official," etc.).
* **Mobile wrappers (WebView shells, Capacitor apps, native apps) pointing at
TREK.** You may describe your app as "a mobile client for TREK" or "for use
with TREK." You may not publish it on app stores under the name "TREK" or a
confusingly similar name, and you may not use the TREK logo as the app icon
unless your wrapper distributes only an unmodified, official TREK instance
and you have obtained permission.
* **Forks of the TREK source code.** Forks that diverge from upstream must use
a different name. You may state that your fork is "based on TREK" or "a fork
of TREK," but the project name itself must be your own.
## Statements about your software's relation to TREK
You may use the word mark, but not TREK logos, to truthfully describe the
relationship between your software and ours. The word mark "TREK" should be
used after a verb or preposition that describes the relationship between your
software and ours. So you may say, for example, "Bob's app for TREK" but may
not say "Bob's TREK app." Some other examples that may work for you are:
* [Your software] uses TREK
* [Your software] is powered by TREK
* [Your software] runs on TREK
* [Your software] for use with TREK
* [Your software] for TREK
## Questions and permission requests
If you are not sure whether your intended use of the Marks is permitted under
this policy, or if you would like to request explicit permission for a use that
is not covered, please open an issue on the TREK GitHub repository or contact
the maintainers directly.
---
These guidelines are based on the
[Model Trademark Guidelines](http://www.modeltrademarkguidelines.org), used
under a
[Creative Commons Attribution 3.0 Unported license](https://creativecommons.org/licenses/by/3.0/deed.en_US).
+2 -2
View File
@@ -1,5 +1,5 @@
apiVersion: v2
name: trek
version: 3.0.9
version: 3.0.8
description: Minimal Helm chart for TREK app
appVersion: "3.0.9"
appVersion: "3.0.8"
+5 -5
View File
@@ -1,12 +1,12 @@
{
"name": "trek-client",
"version": "3.0.9",
"version": "3.0.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "trek-client",
"version": "3.0.9",
"version": "3.0.8",
"dependencies": {
"@react-pdf/renderer": "^4.3.2",
"axios": "^1.6.7",
@@ -8907,9 +8907,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.10",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
"version": "8.5.9",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
"integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==",
"dev": true,
"funding": [
{
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "trek-client",
"version": "3.0.9",
"version": "3.0.8",
"private": true,
"type": "module",
"scripts": {
+5 -12
View File
@@ -266,22 +266,17 @@ export default function DemoBanner(): React.ReactElement | null {
return (
<div style={{
position: 'fixed', inset: 0, zIndex: 99999,
position: 'fixed', inset: 0, zIndex: 9999,
background: 'rgba(0,0,0,0.6)', backdropFilter: 'blur(8px)',
display: 'flex', alignItems: 'center', justifyContent: 'center',
paddingTop: 'max(16px, env(safe-area-inset-top))',
paddingBottom: 'max(16px, calc(env(safe-area-inset-bottom) + 80px))',
paddingLeft: 16, paddingRight: 16,
overflow: 'auto',
padding: 16, overflow: 'auto',
fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif",
}} onClick={() => setDismissed(true)}>
<div style={{
background: 'white', borderRadius: 20, padding: '28px 24px 0',
background: 'white', borderRadius: 20, padding: '28px 24px 20px',
maxWidth: 480, width: '100%',
boxShadow: '0 20px 60px rgba(0,0,0,0.3)',
maxHeight: 'min(90vh, calc(100dvh - 96px))',
overflow: 'auto',
display: 'flex', flexDirection: 'column',
maxHeight: '90vh', overflow: 'auto',
}} onClick={(e: React.MouseEvent<HTMLDivElement>) => e.stopPropagation()}>
{/* Header */}
@@ -372,10 +367,8 @@ export default function DemoBanner(): React.ReactElement | null {
{/* Footer */}
<div style={{
padding: '14px 0 20px', borderTop: '1px solid #e5e7eb',
paddingTop: 14, borderTop: '1px solid #e5e7eb',
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
position: 'sticky', bottom: 0, background: 'white',
marginTop: 'auto',
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: '#9ca3af' }}>
<Github size={13} />
@@ -24,6 +24,10 @@ const mockDayNotesState = vi.hoisted(() => ({
moveNote: vi.fn(),
}))
const mockPermissionsState = vi.hoisted(() => ({
canDo: true,
}))
// ── Module mocks ────────────────────────────────────────────────────────────
vi.mock('../../api/client', async (importOriginal) => {
@@ -79,7 +83,7 @@ vi.mock('../../store/permissionsStore', async (importOriginal) => {
const actual = await importOriginal() as any
return {
...actual,
useCanDo: () => () => true,
useCanDo: () => () => mockPermissionsState.canDo,
}
})
@@ -125,6 +129,7 @@ beforeEach(() => {
// Reset mutable day-notes state
mockDayNotesState.noteUi = {}
mockDayNotesState.dayNotes = {}
mockPermissionsState.canDo = true
seedStore(useAuthStore, { user: buildUser(), isAuthenticated: true })
seedStore(useTripStore, { trip: buildTrip({ id: 1 }) })
seedStore(useSettingsStore, { settings: { time_format: '24h', temperature_unit: 'celsius' } } as any)
@@ -894,23 +899,138 @@ describe('DayPlanSidebar', () => {
// ── ICS export click ─────────────────────────────────────────────────
it('FE-PLANNER-DAYPLAN-058: clicking ICS button calls fetch for .ics export', async () => {
it('FE-PLANNER-DAYPLAN-058: clicking ICS button first asks link or download', async () => {
const user = userEvent.setup()
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
ok: true,
blob: () => Promise.resolve(new Blob(['BEGIN:VCALENDAR'], { type: 'text/calendar' })),
} as any)
// Mock URL.createObjectURL
if (!navigator.clipboard) {
Object.defineProperty(navigator, 'clipboard', {
value: { writeText: vi.fn().mockResolvedValue(undefined) },
configurable: true,
})
}
const clipboardSpy = vi.spyOn(navigator.clipboard, 'writeText').mockResolvedValue(undefined)
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input, init) => {
const url = String(input)
const method = (init?.method || 'GET').toUpperCase()
if (url === '/api/trips/1/subscribe.ics' && method === 'GET') {
return {
ok: true,
json: () => Promise.resolve({ token: null }),
} as any
}
if (url === '/api/trips/1/subscribe.ics' && method === 'POST') {
return {
ok: true,
json: () => Promise.resolve({
url: 'https://example.com/api/shared/token/calendar.ics',
webcal_url: 'webcal://example.com/api/shared/token/calendar.ics',
}),
} as any
}
if (url === '/api/trips/1/subscribe.ics' && method === 'DELETE') {
return { ok: true } as any
}
if (url === '/api/trips/1/export.ics' && method === 'GET') {
return {
ok: true,
blob: () => Promise.resolve(new Blob(['BEGIN:VCALENDAR'], { type: 'text/calendar' })),
} as any
}
throw new Error(`Unexpected fetch call: ${method} ${url}`)
})
const createObjURL = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock')
const revokeObjURL = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {})
render(<DayPlanSidebar {...makeDefaultProps()} />)
await user.click(screen.getByText('ICS').closest('button')!)
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.any(Object)))
expect(await screen.findByText('Calendar share')).toBeInTheDocument()
expect(screen.getByText('Create a subscription link for calendar apps, or download the ICS file.')).toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'Create link' }))
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.objectContaining({ method: 'POST' })))
expect(screen.getByDisplayValue('https://example.com/api/shared/token/calendar.ics')).toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'Copy' }))
await waitFor(() => expect(clipboardSpy).toHaveBeenCalledWith('https://example.com/api/shared/token/calendar.ics'))
await user.click(screen.getByRole('button', { name: 'Delete link' }))
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.objectContaining({ method: 'DELETE' })))
expect(screen.getByRole('button', { name: 'Create link' })).toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'Download ICS file' }))
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/export.ics', expect.any(Object)))
expect(createObjURL).toHaveBeenCalled()
expect(revokeObjURL).toHaveBeenCalledWith('blob:mock')
fetchSpy.mockRestore()
clipboardSpy.mockRestore()
createObjURL.mockRestore()
revokeObjURL.mockRestore()
})
it('FE-PLANNER-DAYPLAN-097: opening ICS dialog shows existing generated link when present', async () => {
const user = userEvent.setup()
const expectedUrl = `${window.location.origin}/api/shared/existing-token/calendar.ics`
const clipboardSpy = vi.spyOn(navigator.clipboard, 'writeText').mockResolvedValue(undefined)
const fetchSpy = vi.spyOn(globalThis, 'fetch')
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ token: 'existing-token' }),
} as any)
.mockResolvedValueOnce({
ok: true,
blob: () => Promise.resolve(new Blob(['BEGIN:VCALENDAR'], { type: 'text/calendar' })),
} as any)
const createObjURL = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock')
const revokeObjURL = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {})
render(<DayPlanSidebar {...makeDefaultProps()} />)
await user.click(screen.getByText('ICS').closest('button')!)
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.any(Object)))
expect(await screen.findByDisplayValue(expectedUrl)).toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Create link' })).not.toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'Copy' }))
await waitFor(() => expect(clipboardSpy).toHaveBeenCalledWith(expectedUrl))
await user.click(screen.getByRole('button', { name: 'Download ICS file' }))
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/export.ics', expect.any(Object)))
expect(createObjURL).toHaveBeenCalled()
expect(revokeObjURL).toHaveBeenCalledWith('blob:mock')
expect(fetchSpy).not.toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.objectContaining({ method: 'POST' }))
fetchSpy.mockRestore()
clipboardSpy.mockRestore()
createObjURL.mockRestore()
revokeObjURL.mockRestore()
})
it('FE-PLANNER-DAYPLAN-099: ICS dialog hides delete link button without share_manage permission', async () => {
const user = userEvent.setup()
mockPermissionsState.canDo = false
const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
ok: true,
json: () => Promise.resolve({ token: 'existing-token' }),
} as any)
render(<DayPlanSidebar {...makeDefaultProps()} />)
await user.click(screen.getByText('ICS').closest('button')!)
await waitFor(() => expect(fetchSpy).toHaveBeenCalledWith('/api/trips/1/subscribe.ics', expect.any(Object)))
expect(await screen.findByDisplayValue(`${window.location.origin}/api/shared/existing-token/calendar.ics`)).toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Delete link' })).not.toBeInTheDocument()
fetchSpy.mockRestore()
})
// ── openAddNote button click ──────────────────────────────────────────
it('FE-PLANNER-DAYPLAN-059: clicking Add Note button calls openAddNote', async () => {
+198 -16
View File
@@ -4,7 +4,7 @@ declare global { interface Window { __dragData: DragDataPayload | null } }
import React, { useState, useEffect, useRef, useMemo } from 'react'
import ReactDOM from 'react-dom'
import { ChevronDown, ChevronRight, ChevronUp, ChevronsDownUp, ChevronsUpDown, Navigation, RotateCcw, ExternalLink, Clock, Pencil, GripVertical, Ticket, Plus, FileText, Check, Trash2, Info, MapPin, Star, Heart, Camera, Lightbulb, Flag, Bookmark, Train, Bus, Plane, Car, Ship, Coffee, ShoppingBag, AlertTriangle, FileDown, Lock, Hotel, Utensils, Users, Undo2, X, Route as RouteIcon } from 'lucide-react'
import { ChevronDown, ChevronRight, ChevronUp, ChevronsDownUp, ChevronsUpDown, Navigation, RotateCcw, ExternalLink, Clock, Pencil, GripVertical, Ticket, Plus, FileText, Check, Trash2, Info, MapPin, Star, Heart, Camera, Lightbulb, Flag, Bookmark, Train, Bus, Plane, Car, Ship, Coffee, ShoppingBag, AlertTriangle, FileDown, Lock, Hotel, Utensils, Users, Undo2, X, Route as RouteIcon, Link2, Copy } from 'lucide-react'
const RES_ICONS = { flight: Plane, hotel: Hotel, restaurant: Utensils, train: Train, car: Car, cruise: Ship, event: Ticket, tour: Users, other: FileText }
import { assignmentsApi, reservationsApi } from '../../api/client'
@@ -225,6 +225,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar({
const tripActions = useRef(useTripStore.getState()).current
const can = useCanDo()
const canEditDays = can('day_edit', trip)
const canManageShare = can('share_manage', trip)
const { noteUi, setNoteUi, noteInputRef, dayNotes, openAddNote: _openAddNote, openEditNote: _openEditNote, cancelNote, saveNote, deleteNote: _deleteNote, moveNote: _moveNote } = useDayNotes(tripId)
@@ -252,6 +253,9 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar({
const setDropTargetKey = (key) => { dropTargetRef.current = key; _setDropTargetKey(key) }
const [dragOverDayId, setDragOverDayId] = useState(null)
const [transportDetail, setTransportDetail] = useState(null)
const [icsDialog, setIcsDialog] = useState<{ url: string; webcal_url: string; creating: boolean } | null>(null)
const [icsCopied, setIcsCopied] = useState(false)
const icsCopyTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const [transportPosVersion, setTransportPosVersion] = useState(0)
useEffect(() => {
@@ -284,6 +288,99 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar({
const currency = trip?.currency || 'EUR'
useEffect(() => {
return () => {
if (icsCopyTimerRef.current) clearTimeout(icsCopyTimerRef.current)
}
}, [])
const closeIcsDialog = () => setIcsDialog(null)
const handleIcsOpenDialog = async () => {
setIcsCopied(false)
setIcsDialog({ url: '', webcal_url: '', creating: true })
try {
const res = await fetch(`/api/trips/${tripId}/subscribe.ics`, { credentials: 'include' })
if (!res.ok) throw new Error()
const data = await res.json() as { token?: string | null }
if (data.token) {
const url = `${window.location.origin}/api/shared/${encodeURIComponent(data.token)}/calendar.ics`
const webcal_url = url.replace(/^https?:\/\//, 'webcal://')
setIcsDialog({ url, webcal_url, creating: false })
} else {
setIcsDialog({ url: '', webcal_url: '', creating: false })
}
} catch {
setIcsDialog({ url: '', webcal_url: '', creating: false })
toast.error(t('dayplan.calendarLinkFailed'))
}
}
const handleIcsCreateLink = async () => {
if (icsDialog?.creating) return
setIcsDialog(prev => prev ? { ...prev, creating: true } : { url: '', webcal_url: '', creating: true })
try {
const res = await fetch(`/api/trips/${tripId}/subscribe.ics`, { method: 'POST', credentials: 'include' })
if (!res.ok) throw new Error()
const data = await res.json() as { url?: string; webcal_url?: string }
const shareUrl = data.url
const openUrl = data.webcal_url || data.url
if (!shareUrl || !openUrl) throw new Error()
setIcsDialog({ url: shareUrl, webcal_url: openUrl, creating: false })
} catch {
setIcsDialog(prev => prev ? { ...prev, creating: false } : prev)
toast.error(t('dayplan.calendarLinkFailed'))
}
}
const handleIcsCopyLink = async () => {
if (!icsDialog?.url) return
try {
await navigator.clipboard.writeText(icsDialog.url)
setIcsCopied(true)
if (icsCopyTimerRef.current) clearTimeout(icsCopyTimerRef.current)
icsCopyTimerRef.current = setTimeout(() => setIcsCopied(false), 2000)
} catch {
toast.error(t('dayplan.calendarCopyFailed'))
}
}
const handleIcsDeleteLink = async () => {
if (!icsDialog || icsDialog.creating) return
setIcsDialog(prev => prev ? { ...prev, creating: true } : prev)
try {
const res = await fetch(`/api/trips/${tripId}/subscribe.ics`, {
method: 'DELETE',
credentials: 'include',
})
if (!res.ok) throw new Error()
setIcsCopied(false)
setIcsDialog(prev => prev ? { ...prev, url: '', webcal_url: '', creating: false } : prev)
toast.success(t('dayplan.calendarLinkDeleted'))
} catch {
setIcsDialog(prev => prev ? { ...prev, creating: false } : prev)
toast.error(t('dayplan.calendarDeleteFailed'))
}
}
const handleIcsDownload = async () => {
try {
const res = await fetch(`/api/trips/${tripId}/export.ics`, { credentials: 'include' })
if (!res.ok) throw new Error()
const blob = await res.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${trip?.title || 'trip'}.ics`
a.click()
URL.revokeObjectURL(url)
toast.success(t('dayplan.calendarDownloaded'))
closeIcsDialog()
} catch {
toast.error(t('dayplan.calendarExportFailed'))
}
}
// Drag-Daten aus dataTransfer, Ref oder window lesen (dataTransfer geht bei Re-Render verloren)
const getDragData = (e) => {
const dt = e?.dataTransfer
@@ -993,21 +1090,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar({
</div>
<div style={{ position: 'relative', flexShrink: 0 }}>
<button
onClick={async () => {
try {
const res = await fetch(`/api/trips/${tripId}/export.ics`, {
credentials: 'include',
})
if (!res.ok) throw new Error()
const blob = await res.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${trip?.title || 'trip'}.ics`
a.click()
URL.revokeObjectURL(url)
} catch { toast.error(t('planner.icsExportFailed')) }
}}
onClick={handleIcsOpenDialog}
onMouseEnter={() => setIcsHover(true)}
onMouseLeave={() => setIcsHover(false)}
style={{
@@ -2128,6 +2211,105 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar({
document.body
)}
{/* ICS subscription dialog */}
{icsDialog && ReactDOM.createPortal(
<div style={{
position: 'fixed', inset: 0, zIndex: 1000,
display: 'flex', alignItems: 'center', justifyContent: 'center',
background: 'rgba(0,0,0,0.3)', backdropFilter: 'blur(3px)',
}} onClick={closeIcsDialog}>
<div style={{
width: 420, maxWidth: '92vw', background: 'var(--bg-card)', borderRadius: 16,
boxShadow: '0 16px 48px rgba(0,0,0,0.22)', padding: '22px 22px 18px',
display: 'flex', flexDirection: 'column', gap: 12, position: 'relative',
}} onClick={e => e.stopPropagation()}>
<button
onClick={closeIcsDialog}
aria-label="Close"
style={{
position: 'absolute',
top: 10,
right: 10,
width: 30,
height: 30,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 8,
border: '1px solid var(--border-faint)',
background: 'transparent',
color: 'var(--text-muted)',
cursor: 'pointer',
}}
>
<X size={14} />
</button>
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
<Link2 size={14} style={{ color: 'var(--text-muted)' }} />
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-primary)' }}>
{t('dayplan.calendarShareTitle')}
</span>
</div>
<p style={{ fontSize: 11, color: 'var(--text-faint)', margin: 0, lineHeight: 1.5 }}>
{t('dayplan.calendarShareDescription')}
</p>
{icsDialog.url ? (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<div style={{
display: 'flex', alignItems: 'center', gap: 6, padding: '8px 10px',
background: 'var(--bg-tertiary)', borderRadius: 8, border: '1px solid var(--border-faint)',
}}>
<input type="text" value={icsDialog.url} readOnly style={{
flex: 1, border: 'none', background: 'none', fontSize: 11, color: 'var(--text-primary)',
outline: 'none', fontFamily: 'monospace',
}} />
<button onClick={handleIcsCopyLink} style={{
display: 'flex', alignItems: 'center', gap: 4, padding: '4px 8px', borderRadius: 6,
border: 'none', background: icsCopied ? '#16a34a' : 'var(--accent)', color: icsCopied ? 'white' : 'var(--accent-text)',
fontSize: 10, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit', transition: 'background 0.2s',
}}>
{icsCopied ? <><Check size={10} /> {t('common.copied')}</> : <><Copy size={10} /> {t('common.copy')}</>}
</button>
</div>
{canManageShare && (
<button onClick={handleIcsDeleteLink} style={{
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5,
padding: '6px 0', borderRadius: 8, border: '1px solid rgba(239,68,68,0.3)',
background: 'rgba(239,68,68,0.06)', color: '#ef4444', fontSize: 11, fontWeight: 500,
cursor: 'pointer', fontFamily: 'inherit',
}}>
<Trash2 size={11} /> {t('dayplan.calendarDeleteLink')}
</button>
)}
</div>
) : (
<button onClick={handleIcsCreateLink}
disabled={!canManageShare}
style={{
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
width: '100%', padding: '8px 0', borderRadius: 8, border: '1px dashed var(--border-primary)',
background: 'none', color: 'var(--text-muted)', fontSize: 12, fontWeight: 500,
cursor: 'pointer', fontFamily: 'inherit',
}}>
{canManageShare ? <><Link2 size={12} /> {t('dayplan.calendarCreateLink')}</> : <>{t('dayplan.calendarCreateLinkNoPermission')}</>}
</button>
)}
<button
onClick={handleIcsDownload}
style={{
display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
width: '100%', padding: '8px 0', borderRadius: 8, border: 'none',
background: 'var(--accent)', color: 'var(--accent-text)', fontSize: 12, fontWeight: 500,
cursor: 'pointer', fontFamily: 'inherit',
}}
>
{t('dayplan.calendarDownloadFile')}
</button>
</div>
</div>,
document.body
)}
{/* Transport-Detail-Modal */}
{transportDetail && ReactDOM.createPortal(
<div style={{
+12
View File
@@ -305,6 +305,18 @@ const en: Record<string, string | { name: string; category: string }[]> = {
'settings.notificationsActive': 'Active channel',
'settings.notificationsManagedByAdmin': 'Notification events are configured by your administrator.',
'dayplan.icsTooltip': 'Export calendar (ICS)',
'dayplan.calendarShareTitle': 'Calendar share',
'dayplan.calendarShareDescription': 'Create a subscription link for calendar apps, or download the ICS file.',
'dayplan.calendarCreateLink': 'Create link',
'dayplan.calendarCreateLinkNoPermission': 'You do not have permission to create calendar links for this trip.',
'dayplan.calendarDeleteLink': 'Delete link',
'dayplan.calendarDownloadFile': 'Download ICS file',
'dayplan.calendarLinkFailed': 'Calendar link failed',
'dayplan.calendarDeleteFailed': 'Delete link failed',
'dayplan.calendarCopyFailed': 'Copy failed',
'dayplan.calendarDownloaded': 'ICS downloaded',
'dayplan.calendarExportFailed': 'ICS export failed',
'dayplan.calendarLinkDeleted': 'Calendar link deleted',
'share.linkTitle': 'Public Link',
'share.linkHint': 'Create a link anyone can use to view this trip without logging in. Read-only — no editing possible.',
'share.createLink': 'Create link',
-56
View File
@@ -1,56 +0,0 @@
# compiled output
/dist
/node_modules
/build
# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# temp directory
.temp
.tmp
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-4
View File
@@ -1,4 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all"
}
-98
View File
@@ -1,98 +0,0 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Project setup
```bash
$ npm install
```
## Compile and run the project
```bash
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
```
## Run tests
```bash
# unit tests
$ npm run test
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
```
## Deployment
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
```bash
$ npm install -g @nestjs/mau
$ mau deploy
```
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
## Resources
Check out a few resources that may come in handy when working with NestJS:
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## Stay in touch
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
## License
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
-35
View File
@@ -1,35 +0,0 @@
// @ts-check
import eslint from '@eslint/js';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{
ignores: ['eslint.config.mjs'],
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
eslintPluginPrettierRecommended,
{
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
sourceType: 'commonjs',
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
"prettier/prettier": ["error", { endOfLine: "auto" }],
},
},
);
-8
View File
@@ -1,8 +0,0 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
-11956
View File
File diff suppressed because it is too large Load Diff
-87
View File
@@ -1,87 +0,0 @@
{
"name": "server-nest-2",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@better-auth/oauth-provider": "^1.6.9",
"@better-auth/passkey": "^1.6.9",
"@hedystia/better-auth-typeorm": "^0.8.2",
"@nestjs/common": "^11.1.19",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^11.1.19",
"@nestjs/platform-express": "^11.1.19",
"@nestjs/platform-socket.io": "^11.1.19",
"@nestjs/throttler": "^6.5.0",
"@nestjs/typeorm": "^11.0.1",
"@nestjs/websockets": "^11.1.19",
"@thallesp/nestjs-better-auth": "^2.6.0",
"better-auth": "^1.6.9",
"better-sqlite3": "^12.9.0",
"csrf-csrf": "^4.0.3",
"helmet": "^8.1.0",
"mysql2": "^3.22.2",
"pg": "^8.20.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.2",
"typeorm": "^0.3.28"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0",
"@nestjs/schematics": "^11.0.0",
"@nestjs/testing": "^11.0.1",
"@types/express": "^5.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^24.0.0",
"@types/supertest": "^7.0.0",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.2",
"globals": "^17.0.0",
"jest": "^30.0.0",
"prettier": "^3.4.2",
"source-map-support": "^0.5.21",
"supertest": "^7.0.0",
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.2",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3",
"typescript-eslint": "^8.20.0"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
-46
View File
@@ -1,46 +0,0 @@
import authConfig from './config/auth.config.js';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module.js';
type SupportedDbType = 'mysql' | 'mariadb' | 'postgres' | 'sqlite';
function resolveDriver(type: SupportedDbType) {
switch (type) {
case 'mysql':
case 'mariadb':
return require('mysql2');
case 'postgres':
return require('pg');
case 'sqlite':
return require('better-sqlite3');
}
}
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, load: [authConfig] }),
AuthModule,
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => {
const type = config.get<SupportedDbType>('DB_TYPE', 'sqlite');
return {
type,
driver: resolveDriver(type),
host: config.get<string>('DB_HOST', 'localhost'),
port: config.get<number>('DB_PORT', 5432),
username: config.get<string>('DB_USER', 'usr'),
password: config.get<string>('DB_PASS', 'pwd'),
database: config.get<string>('DB_NAME', 'data/travel.db'),
autoLoadEntities: true,
synchronize: config.get<string>('NODE_ENV') !== 'production',
};
},
inject: [ConfigService],
}),
],
})
export class AppModule {}
-20
View File
@@ -1,20 +0,0 @@
import { betterAuth } from 'better-auth';
import { typeormAdapter } from '@hedystia/better-auth-typeorm';
import { DataSource } from 'typeorm';
import { AuthConfig } from '../config/auth.config.js';
export function createAuth(dataSource: DataSource, cfg: AuthConfig) {
return betterAuth({
database: typeormAdapter(dataSource, { debugLogs: cfg.debugLogs }),
secret: cfg.secret,
baseURL: cfg.baseURL,
basePath: '/api/auth',
trustedOrigins: cfg.frontendUrl ? [cfg.frontendUrl] : [],
advanced: {
cookies: { session_token: { name: 'trek_session' } },
useSecureCookies: cfg.cookieSecure,
},
emailAndPassword: { enabled: true },
plugins: [],
});
}
-39
View File
@@ -1,39 +0,0 @@
import { betterAuth } from 'better-auth';
import { typeormAdapter } from '@hedystia/better-auth-typeorm';
import { magicLink } from 'better-auth/plugins/magic-link';
import { genericOAuth } from 'better-auth/plugins/generic-oauth';
import { jwt } from 'better-auth/plugins/jwt';
import { oauthProvider } from '@better-auth/oauth-provider';
import { passkey } from '@better-auth/passkey';
import { DataSource } from 'typeorm';
// Used only by `npx @better-auth/cli generate`.
// Not imported at runtime — auth.factory.ts uses the DI DataSource.
const dataSource = new DataSource({
type: 'better-sqlite3',
database: ':memory:',
});
export const auth = betterAuth({
baseURL: 'http://localhost:3000',
database: typeormAdapter(dataSource, {
entitiesDir: './src/models/entities/auth',
migrationsDir: './src/database/migrations',
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: true,
sendVerificationEmail: async () => {},
sendResetPassword: async () => {},
},
emailVerification: {
sendVerificationEmail: async () => {},
},
plugins: [
jwt(),
magicLink({ sendMagicLink: async () => {} }),
genericOAuth({ config: [] }),
oauthProvider({ loginPage: '/login' }),
passkey(),
],
});
-43
View File
@@ -1,43 +0,0 @@
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule as BetterAuthNestModule } from '@thallesp/nestjs-better-auth';
import { DataSource } from 'typeorm';
import { createAuth } from './auth.factory.js';
import { AuthConfig } from '../config/auth.config.js';
import { User } from '../models/entities/auth/User.js';
import { Account } from '../models/entities/auth/Account.js';
import { Session } from '../models/entities/auth/Session.js';
import { Verification } from '../models/entities/auth/Verification.js';
import { Passkey } from '../models/entities/auth/Passkey.js';
import { Jwks } from '../models/entities/auth/Jwks.js';
import { OauthClient } from '../models/entities/auth/OauthClient.js';
import { OauthAccessToken } from '../models/entities/auth/OauthAccessToken.js';
import { OauthRefreshToken } from '../models/entities/auth/OauthRefreshToken.js';
import { OauthConsent } from '../models/entities/auth/OauthConsent.js';
@Module({
imports: [
TypeOrmModule.forFeature([
User,
Account,
Session,
Verification,
Passkey,
Jwks,
OauthClient,
OauthAccessToken,
OauthRefreshToken,
OauthConsent,
]),
BetterAuthNestModule.forRootAsync({
imports: [ConfigModule],
inject: [DataSource, ConfigService],
useFactory: (ds: DataSource, config: ConfigService) => ({
auth: createAuth(ds, config.get<AuthConfig>('auth')!),
}),
}),
],
exports: [BetterAuthNestModule],
})
export class AuthModule {}
-26
View File
@@ -1,26 +0,0 @@
import { registerAs } from '@nestjs/config';
import { boolean } from 'better-auth';
export interface AuthConfig {
secret: string;
baseURL: string;
frontendUrl: string | undefined;
cookieSecure: boolean;
debugLogs: boolean;
}
export default registerAs(
'auth',
(): AuthConfig => ({
secret: process.env.BETTER_AUTH_SECRET ?? 'changeme',
baseURL: process.env.BETTER_AUTH_URL ?? 'http://localhost:3000',
frontendUrl: process.env.BASE_URL,
cookieSecure:
process.env.COOKIE_SECURE === 'true' &&
process.env.NODE_ENV === 'production' &&
process.env.BASE_URL?.startsWith('https') === true,
debugLogs:
process.env.BETTER_AUTH_DEBUG_LOGS === 'true' ||
process.env.NODE_ENV === 'development',
}),
);
@@ -1,103 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -1,79 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -1,58 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -1,59 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777216318138 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -1,103 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -1,112 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthAccessToken',
new TableIndex({
name: 'oauthAccessToken_clientId_idx',
columnNames: ['clientId'],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthApplication',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'oauthAccessToken',
new TableIndex({
name: 'oauthAccessToken_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -1,104 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthApplication1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthApplication',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'redirectUrls',
type: 'text',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthApplication',
new TableIndex({
name: 'oauthApplication_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthApplication',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthApplication');
}
}
@@ -1,95 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'consentGiven',
type: 'boolean',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'oauthConsent',
new TableIndex({
name: 'oauthConsent_clientId_idx',
columnNames: ['clientId'],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthApplication',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'oauthConsent',
new TableIndex({
name: 'oauthConsent_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -1,99 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -1,79 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -1,58 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -1,59 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217712285 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -1,103 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -1,113 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -1,184 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -1,77 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -1,106 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -1,99 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -1,79 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -1,58 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -1,59 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217820713 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -1,103 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -1,46 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateJwks1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'jwks',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'privateKey',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('jwks');
}
}
@@ -1,113 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -1,184 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -1,77 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -1,106 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -1,99 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -1,79 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -1,58 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -1,59 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217882945 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
@@ -1,103 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateAccount1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'account',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'accountId',
type: 'text',
},
{
name: 'providerId',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'accessToken',
type: 'text',
isNullable: true,
},
{
name: 'refreshToken',
type: 'text',
isNullable: true,
},
{
name: 'idToken',
type: 'text',
isNullable: true,
},
{
name: 'accessTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'refreshTokenExpiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scope',
type: 'text',
isNullable: true,
},
{
name: 'password',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
],
}),
);
await queryRunner.createIndex(
'account',
new TableIndex({
name: 'account_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'account',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('account');
}
}
@@ -1,46 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateJwks1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'jwks',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'privateKey',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('jwks');
}
}
@@ -1,113 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthAccessToken1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthAccessToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isNullable: true,
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'refreshId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthAccessToken',
new TableForeignKey({
columnNames: ['refreshId'],
referencedTableName: 'oauthRefreshToken',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthAccessToken');
}
}
@@ -1,184 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthClient1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthClient',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
isUnique: true,
},
{
name: 'clientSecret',
type: 'text',
isNullable: true,
},
{
name: 'disabled',
type: 'boolean',
isNullable: true,
default: false,
},
{
name: 'skipConsent',
type: 'boolean',
isNullable: true,
},
{
name: 'enableEndSession',
type: 'boolean',
isNullable: true,
},
{
name: 'subjectType',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'uri',
type: 'text',
isNullable: true,
},
{
name: 'icon',
type: 'text',
isNullable: true,
},
{
name: 'contacts',
type: 'text',
isNullable: true,
},
{
name: 'tos',
type: 'text',
isNullable: true,
},
{
name: 'policy',
type: 'text',
isNullable: true,
},
{
name: 'softwareId',
type: 'text',
isNullable: true,
},
{
name: 'softwareVersion',
type: 'text',
isNullable: true,
},
{
name: 'softwareStatement',
type: 'text',
isNullable: true,
},
{
name: 'redirectUris',
type: 'text',
},
{
name: 'postLogoutRedirectUris',
type: 'text',
isNullable: true,
},
{
name: 'tokenEndpointAuthMethod',
type: 'text',
isNullable: true,
},
{
name: 'grantTypes',
type: 'text',
isNullable: true,
},
{
name: 'responseTypes',
type: 'text',
isNullable: true,
},
{
name: 'public',
type: 'boolean',
isNullable: true,
},
{
name: 'type',
type: 'text',
isNullable: true,
},
{
name: 'requirePKCE',
type: 'boolean',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'metadata',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthClient',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthClient');
}
}
@@ -1,77 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthConsent1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthConsent',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'userId',
type: 'text',
isNullable: true,
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'updatedAt',
type: 'datetime',
isNullable: true,
},
],
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthConsent',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthConsent');
}
}
@@ -1,106 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateOauthRefreshToken1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'oauthRefreshToken',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'clientId',
type: 'text',
},
{
name: 'sessionId',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
{
name: 'referenceId',
type: 'text',
isNullable: true,
},
{
name: 'expiresAt',
type: 'datetime',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'revoked',
type: 'datetime',
isNullable: true,
},
{
name: 'authTime',
type: 'datetime',
isNullable: true,
},
{
name: 'scopes',
type: 'text',
},
],
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['clientId'],
referencedTableName: 'oauthClient',
referencedColumnNames: ['clientId'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['sessionId'],
referencedTableName: 'session',
referencedColumnNames: ['id'],
onDelete: 'SET NULL',
}),
);
await queryRunner.createForeignKey(
'oauthRefreshToken',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('oauthRefreshToken');
}
}
@@ -1,99 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreatePasskey1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'passkey',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
isNullable: true,
},
{
name: 'publicKey',
type: 'text',
},
{
name: 'userId',
type: 'text',
},
{
name: 'credentialID',
type: 'text',
},
{
name: 'counter',
type: 'integer',
},
{
name: 'deviceType',
type: 'text',
},
{
name: 'backedUp',
type: 'boolean',
},
{
name: 'transports',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
isNullable: true,
},
{
name: 'aaguid',
type: 'text',
isNullable: true,
},
],
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'passkey',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
await queryRunner.createIndex(
'passkey',
new TableIndex({
name: 'passkey_credentialID_idx',
columnNames: ['credentialID'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('passkey');
}
}
@@ -1,79 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateSession1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'session',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'token',
type: 'text',
isUnique: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
},
{
name: 'ipAddress',
type: 'text',
isNullable: true,
},
{
name: 'userAgent',
type: 'text',
isNullable: true,
},
{
name: 'userId',
type: 'text',
},
],
}),
);
await queryRunner.createIndex(
'session',
new TableIndex({
name: 'session_userId_idx',
columnNames: ['userId'],
}),
);
await queryRunner.createForeignKey(
'session',
new TableForeignKey({
columnNames: ['userId'],
referencedTableName: 'user',
referencedColumnNames: ['id'],
onDelete: 'CASCADE',
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('session');
}
}
@@ -1,58 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateUser1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'user',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'name',
type: 'text',
},
{
name: 'email',
type: 'text',
isUnique: true,
},
{
name: 'emailVerified',
type: 'boolean',
default: false,
},
{
name: 'image',
type: 'text',
isNullable: true,
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('user');
}
}
@@ -1,59 +0,0 @@
import {
type MigrationInterface,
type QueryRunner,
Table,
TableColumn,
TableForeignKey,
TableIndex,
} from 'typeorm';
export class CreateVerification1777217895075 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: 'verification',
columns: [
{
name: 'id',
type: 'text',
isPrimary: true,
},
{
name: 'identifier',
type: 'text',
},
{
name: 'value',
type: 'text',
},
{
name: 'expiresAt',
type: 'datetime',
},
{
name: 'createdAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
{
name: 'updatedAt',
type: 'datetime',
default: 'CURRENT_TIMESTAMP',
},
],
}),
);
await queryRunner.createIndex(
'verification',
new TableIndex({
name: 'verification_identifier_idx',
columnNames: ['identifier'],
}),
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable('verification');
}
}
-8
View File
@@ -1,8 +0,0 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule, { bodyParser: false });
await app.listen(process.env.PORT ?? 3001);
}
bootstrap();
@@ -1,34 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('bucket_list')
export class BucketList extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'lat', nullable: true })
lat: number | null;
@Column({ name: 'lng', nullable: true })
lng: number | null;
@Column({ name: 'country_code', nullable: true })
countryCode: string | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column({
name: 'target_date',
nullable: true,
default: null,
})
targetDate: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.bucketLists, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,15 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('visited_countries')
export class VisitedCountries extends IntBaseEntity {
@Column('text', { name: 'country_code' })
countryCode: string;
@ManyToOne(() => SqliteUsers, (users) => users.visitedCountries, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,22 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_visited_regions_country', ['countryCode'], {})
@Entity('visited_regions')
export class VisitedRegions extends IntBaseEntity {
@Column({ name: 'region_code' })
regionCode: string;
@Column({ name: 'region_name' })
regionName: string;
@Column({ name: 'country_code' })
countryCode: string;
@ManyToOne(() => SqliteUsers, (users) => users.visitedRegions, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,59 +0,0 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('account')
export class Account {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'accountId' })
accountId: string;
@Column('text', { name: 'providerId' })
providerId: string;
@Index('account_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Column('text', { name: 'accessToken', nullable: true })
accessToken: string | null;
@Column('text', { name: 'refreshToken', nullable: true })
refreshToken: string | null;
@Column('text', { name: 'idToken', nullable: true })
idToken: string | null;
@Column({ type: 'timestamp', name: 'accessTokenExpiresAt', nullable: true })
accessTokenExpiresAt: Date | null;
@Column({ type: 'timestamp', name: 'refreshTokenExpiresAt', nullable: true })
refreshTokenExpiresAt: Date | null;
@Column('text', { name: 'scope', nullable: true })
scope: string | null;
@Column('text', { name: 'password', nullable: true })
password: string | null;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -1,22 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('jwks')
export class Jwks {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'publicKey' })
publicKey: string;
@Column('text', { name: 'privateKey' })
privateKey: string;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
}
@@ -1,57 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { OauthRefreshToken } from './OauthRefreshToken';
import { Session } from './Session';
import { User } from './User';
@Entity('oauthAccessToken')
export class OauthAccessToken {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'token', nullable: true, unique: true })
token: string | null;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'sessionId', nullable: true })
sessionId: string | null;
@ManyToOne(() => Session, { onDelete: 'SET NULL', nullable: true })
@JoinColumn({ name: 'sessionId', referencedColumnName: 'id' })
session?: Session;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'refreshId', nullable: true })
refreshId: string | null;
@ManyToOne(() => OauthRefreshToken, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'refreshId', referencedColumnName: 'id' })
refresh?: OauthRefreshToken;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column('text', { name: 'scopes' })
scopes: string;
}
@@ -1,56 +0,0 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('oauthApplication')
export class OauthApplication {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'icon', nullable: true })
icon: string | null;
@Column('text', { name: 'metadata', nullable: true })
metadata: string | null;
@Column('text', { name: 'clientId', nullable: true, unique: true })
clientId: string | null;
@Column('text', { name: 'clientSecret', nullable: true })
clientSecret: string | null;
@Column('text', { name: 'redirectUrls', nullable: true })
redirectUrls: string | null;
@Column('text', { name: 'type', nullable: true })
type: string | null;
@Column('boolean', { name: 'disabled', nullable: true, default: false })
disabled: boolean | null;
@Index('oauthApplication_userId_idx')
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
}
@@ -1,102 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { User } from './User';
@Entity('oauthClient')
export class OauthClient {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'clientId', unique: true })
clientId: string;
@Column('text', { name: 'clientSecret', nullable: true })
clientSecret: string | null;
@Column('boolean', { name: 'disabled', nullable: true, default: false })
disabled: boolean | null;
@Column('boolean', { name: 'skipConsent', nullable: true })
skipConsent: boolean | null;
@Column('boolean', { name: 'enableEndSession', nullable: true })
enableEndSession: boolean | null;
@Column('text', { name: 'subjectType', nullable: true })
subjectType: string | null;
@Column('text', { name: 'scopes', nullable: true })
scopes: string | null;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'uri', nullable: true })
uri: string | null;
@Column('text', { name: 'icon', nullable: true })
icon: string | null;
@Column('text', { name: 'contacts', nullable: true })
contacts: string | null;
@Column('text', { name: 'tos', nullable: true })
tos: string | null;
@Column('text', { name: 'policy', nullable: true })
policy: string | null;
@Column('text', { name: 'softwareId', nullable: true })
softwareId: string | null;
@Column('text', { name: 'softwareVersion', nullable: true })
softwareVersion: string | null;
@Column('text', { name: 'softwareStatement', nullable: true })
softwareStatement: string | null;
@Column('text', { name: 'redirectUris' })
redirectUris: string;
@Column('text', { name: 'postLogoutRedirectUris', nullable: true })
postLogoutRedirectUris: string | null;
@Column('text', { name: 'tokenEndpointAuthMethod', nullable: true })
tokenEndpointAuthMethod: string | null;
@Column('text', { name: 'grantTypes', nullable: true })
grantTypes: string | null;
@Column('text', { name: 'responseTypes', nullable: true })
responseTypes: string | null;
@Column('boolean', { name: 'public', nullable: true })
public: boolean | null;
@Column('text', { name: 'type', nullable: true })
type: string | null;
@Column('boolean', { name: 'requirePKCE', nullable: true })
requirePKCE: boolean | null;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'metadata', nullable: true })
metadata: string | null;
}
@@ -1,38 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { User } from './User';
@Entity('oauthConsent')
export class OauthConsent {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'userId', nullable: true })
userId: string | null;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: true })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user?: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column('text', { name: 'scopes' })
scopes: string;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'updatedAt', nullable: true })
updatedAt: Date | null;
}
@@ -1,55 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { OauthClient } from './OauthClient';
import { Session } from './Session';
import { User } from './User';
@Entity('oauthRefreshToken')
export class OauthRefreshToken {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'token', unique: true })
token: string;
@Column('text', { name: 'clientId' })
clientId: string;
@ManyToOne(() => OauthClient, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'clientId', referencedColumnName: 'clientId' })
client: OauthClient;
@Column('text', { name: 'sessionId', nullable: true })
sessionId: string | null;
@ManyToOne(() => Session, { onDelete: 'SET NULL', nullable: true })
@JoinColumn({ name: 'sessionId', referencedColumnName: 'id' })
session?: Session;
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Column('text', { name: 'referenceId', nullable: true })
referenceId: string | null;
@Column({ type: 'timestamp', name: 'expiresAt', nullable: true })
expiresAt: Date | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column({ type: 'timestamp', name: 'revoked', nullable: true })
revoked: Date | null;
@Column({ type: 'timestamp', name: 'authTime', nullable: true })
authTime: Date | null;
@Column('text', { name: 'scopes' })
scopes: string;
}
@@ -1,54 +0,0 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('passkey')
export class Passkey {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name', nullable: true })
name: string | null;
@Column('text', { name: 'publicKey' })
publicKey: string;
@Index('passkey_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
@Index('passkey_credentialID_idx')
@Column('text', { name: 'credentialID' })
credentialID: string;
@Column('integer', { name: 'counter' })
counter: number;
@Column('text', { name: 'deviceType' })
deviceType: string;
@Column('boolean', { name: 'backedUp' })
backedUp: boolean;
@Column('text', { name: 'transports', nullable: true })
transports: string | null;
@Column({ type: 'timestamp', name: 'createdAt', nullable: true })
createdAt: Date | null;
@Column('text', { name: 'aaguid', nullable: true })
aaguid: string | null;
}
@@ -1,44 +0,0 @@
/**
* AUTOGENERATED
*/
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { User } from './User';
@Entity('session')
export class Session {
@PrimaryColumn('text')
id: string;
@Column({ type: 'timestamp', name: 'expiresAt' })
expiresAt: Date;
@Column('text', { name: 'token', unique: true })
token: string;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
@Column('text', { name: 'ipAddress', nullable: true })
ipAddress: string | null;
@Column('text', { name: 'userAgent', nullable: true })
userAgent: string | null;
@Index('session_userId_idx')
@Column('text', { name: 'userId' })
userId: string;
@ManyToOne(() => User, { onDelete: 'CASCADE', nullable: false })
@JoinColumn({ name: 'userId', referencedColumnName: 'id' })
user: User;
}
@@ -1,28 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('user')
export class User {
@PrimaryColumn('text')
id: string;
@Column('text', { name: 'name' })
name: string;
@Column('text', { name: 'email', unique: true })
email: string;
@Column('boolean', { name: 'emailVerified', default: false })
emailVerified: boolean;
@Column('text', { name: 'image', nullable: true })
image: string | null;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -1,26 +0,0 @@
/**
* AUTOGENERATED
*/
import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
@Entity('verification')
export class Verification {
@PrimaryColumn('text')
id: string;
@Index('verification_identifier_idx')
@Column('text', { name: 'identifier' })
identifier: string;
@Column('text', { name: 'value' })
value: string;
@Column({ type: 'timestamp', name: 'expiresAt' })
expiresAt: Date;
@Column({ type: 'timestamp', name: 'createdAt' })
createdAt: Date;
@Column({ type: 'timestamp', name: 'updatedAt' })
updatedAt: Date;
}
@@ -1,62 +0,0 @@
import {
Column,
CreateDateColumn,
DeleteDateColumn,
PrimaryColumn,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
// Layer 1 — timestamps only, always present
export abstract class TimestampedEntity {
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@UpdateDateColumn({ name: 'updated_at' })
updatedAt: Date;
}
export abstract class TimestampedSortableEntity extends TimestampedEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 2 — adds soft delete
export abstract class SoftDeletableEntity extends TimestampedEntity {
@DeleteDateColumn({ name: 'deleted_at', nullable: true })
deletedAt: Date | null;
}
// Layer 3a — adds integer PK to timestamped entity
export abstract class IntBaseEntity extends TimestampedEntity {
@PrimaryGeneratedColumn()
id: number;
}
export abstract class IntSortableBaseEntity extends IntBaseEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 3b — adds integer PK + soft delete
export abstract class SoftDeletableIntBaseEntity extends SoftDeletableEntity {
@PrimaryGeneratedColumn()
id: number;
}
// Layer 3c — natural/business string PK (e.g. country code, slug)
export abstract class StringBaseEntity extends TimestampedEntity {
@PrimaryColumn({ name: 'id' })
id: string;
}
export abstract class StringSortableBaseEntity extends StringBaseEntity {
@Column('int', { name: 'sort_order', default: 0 })
sortOrder: number;
}
// Layer 3d — natural string PK + soft delete
export abstract class SoftDeletableStringBaseEntity extends SoftDeletableEntity {
@PrimaryColumn({ name: 'id' })
id: string;
}
@@ -1,25 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_mcp_tokens_hash', ['tokenHash'], { unique: true })
@Entity('mcp_tokens')
export class McpTokens extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'token_hash', unique: true })
tokenHash: string;
@Column({ name: 'token_prefix' })
tokenPrefix: string;
@Column({ name: 'last_used_at', nullable: true })
lastUsedAt: Date | null;
@ManyToOne(() => SqliteUsers, (users) => users.mcpTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,35 +0,0 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_ncp_user', ['userId'], {})
@Entity('notification_channel_preferences')
export class NotificationChannelPreferences {
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'event_type' })
eventType: string;
@PrimaryColumn({ name: 'channel' })
channel: string;
@Column({ name: 'enabled', default: true })
enabled: boolean;
@ManyToOne(
() => SqliteUsers,
(users) => users.notificationChannelPreferences,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,81 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_notifications_target_scope', ['target', 'scope'], {})
@Index('idx_notifications_recipient_created', ['recipientId', 'createdAt'], {})
@Index(
'idx_notifications_recipient',
['recipientId', 'isRead', 'createdAt'],
{},
)
@Entity('notifications')
export class Notifications extends IntBaseEntity {
@Column({ name: 'type' })
type: string;
@Column({ name: 'scope' })
scope: string;
@Column('int', { name: 'target' })
target: number;
@Column('int', { name: 'recipient_id' })
recipientId: number;
@Column({ name: 'title_key' })
titleKey: string;
@Column('simple-json', {
name: 'title_params',
nullable: true,
default: {},
})
titleParams: Record<string, unknown> | null;
@Column({ name: 'text_key' })
textKey: string;
@Column('simple-json', {
name: 'text_params',
nullable: true,
default: {},
})
textParams: Record<string, unknown> | null;
@Column({ name: 'positive_text_key', nullable: true })
positiveTextKey: string | null;
@Column({ name: 'negative_text_key', nullable: true })
negativeTextKey: string | null;
@Column({ name: 'positive_callback', nullable: true })
positiveCallback: string | null;
@Column({ name: 'negative_callback', nullable: true })
negativeCallback: string | null;
@Column({ name: 'response', nullable: true })
response: string | null;
@Column({ name: 'navigate_text_key', nullable: true })
navigateTextKey: string | null;
@Column({ name: 'navigate_target', nullable: true })
navigateTarget: string | null;
@Column({ name: 'is_read', nullable: true, default: false })
isRead: boolean | null;
@ManyToOne(() => SqliteUsers, (users) => users.notifications, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'recipient_id', referencedColumnName: 'id' }])
recipient: SqliteUsers;
@ManyToOne(() => SqliteUsers, (users) => users.notifications2, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'sender_id', referencedColumnName: 'id' }])
sender: SqliteUsers;
}
@@ -1,53 +0,0 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { OldOauthConsents } from './OldOauthConsents';
import { OldOauthTokens } from './OldOauthTokens';
import { SqliteUsers } from './SqliteUsers';
import { StringBaseEntity } from '../base/BaseEntity';
@Index('idx_oauth_clients_client_id', ['clientId'], { unique: true })
@Index('idx_oauth_clients_user', ['userId'], {})
@Entity('oauth_clients')
export class OldOauthClients extends StringBaseEntity {
@Column('int', { name: 'user_id', nullable: true })
userId: number | null;
@Column({ name: 'name' })
name: string;
@Column({ name: 'client_id', unique: true })
clientId: string;
@Column({ name: 'client_secret_hash' })
clientSecretHash: string;
@Column('simple-array', { name: 'redirect_uris', default: [] })
redirectUris: string[];
@Column('simple-array', { name: 'allowed_scopes', default: [] })
allowedScopes: string[];
@Column({ name: 'is_public', default: false })
isPublic: boolean;
@Column({ name: 'created_via', default: 'settings_ui' })
createdVia: string;
@OneToMany(() => OldOauthConsents, (oauthConsents) => oauthConsents.client)
oauthConsents: OldOauthConsents[];
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.client)
oauthTokens: OldOauthTokens[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthClients, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,26 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { OldOauthClients } from './OldOauthClients';
import { IntBaseEntity } from '../base/BaseEntity';
@Entity('oauth_consents')
export class OldOauthConsents extends IntBaseEntity {
@Column('simple-array', { name: 'scopes', default: [] })
scopes: string[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthConsents, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => OldOauthClients,
(oauthClients) => oauthClients.oauthConsents,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'client_id', referencedColumnName: 'clientId' }])
client: OldOauthClients;
}
@@ -1,68 +0,0 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { OldOauthClients } from './OldOauthClients';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_oauth_tokens_parent', ['parentTokenId'], {})
@Index('idx_oauth_tokens_refresh', ['refreshTokenHash'], { unique: true })
@Index('idx_oauth_tokens_access', ['accessTokenHash'], { unique: true })
@Index('idx_oauth_tokens_user', ['userId'], {})
@Entity('oauth_tokens')
export class OldOauthTokens extends IntBaseEntity {
@Column('int', { name: 'user_id' })
userId: number;
@Column({ name: 'access_token_hash', unique: true })
accessTokenHash: string;
@Column({ name: 'refresh_token_hash', unique: true })
refreshTokenHash: string;
@Column('simple-array', { name: 'scopes', default: [] })
scopes: string[];
@Column('datetime', { name: 'access_token_expires_at' })
accessTokenExpiresAt: Date;
@Column('datetime', { name: 'refresh_token_expires_at' })
refreshTokenExpiresAt: Date;
@Column('datetime', { name: 'revoked_at', nullable: true })
revokedAt: Date | null;
@Column('int', { name: 'parent_token_id', nullable: true })
parentTokenId: number | null;
@Column({ name: 'audience', nullable: true })
audience: string | null;
@ManyToOne(() => OldOauthTokens, (oauthTokens) => oauthTokens.oauthTokens)
@JoinColumn([{ name: 'parent_token_id', referencedColumnName: 'id' }])
parentToken: OldOauthTokens;
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.parentToken)
oauthTokens: OldOauthTokens[];
@ManyToOne(() => SqliteUsers, (users) => users.oauthTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => OldOauthClients,
(oauthClients) => oauthClients.oauthTokens,
{
onDelete: 'CASCADE',
},
)
@JoinColumn([{ name: 'client_id', referencedColumnName: 'clientId' }])
client: OldOauthClients;
}
@@ -1,29 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { SqliteUsers } from './SqliteUsers';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_prt_hash', ['tokenHash'], {})
@Index('idx_prt_user', ['userId'], {})
@Entity('password_reset_tokens')
export class OldPasswordResetTokens extends IntBaseEntity {
@Column('int', { name: 'user_id' })
userId: number;
@Column({ name: 'token_hash', unique: true })
tokenHash: string;
@Column({ name: 'expires_at' })
expiresAt: Date;
@Column({ name: 'consumed_at', nullable: true })
consumedAt: Date | null;
@Column({ name: 'created_ip', nullable: true })
createdIp: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.passwordResetTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,341 +0,0 @@
import {
Column,
Entity,
Index,
JoinTable,
ManyToMany,
OneToMany,
OneToOne,
} from 'typeorm';
import { OldPasswordResetTokens } from './OldPasswordResetTokens';
import { IntBaseEntity } from '../base/BaseEntity';
import { Settings } from '../system/Settings';
import { Trips } from '../trip/Trips';
import { Categories } from '../trip/Categories';
import { Tags } from '../trip/Tags';
import { TripFiles } from '../trip/files/TripFiles';
import { BudgetItems } from '../trip/budget/BudgetItems';
import { VacayPlans } from '../vacay/VacayPlans';
import { TripMembers } from '../trip/TripMembers';
import { VacayPlanMembers } from '../vacay/VacayPlanMembers';
import { VacayUserColors } from '../vacay/VacayUserColors';
import { VacayUserYears } from '../vacay/VacayUserYears';
import { VacayEntries } from '../vacay/VacayEntries';
import { CollabNotes } from '../trip/collab/CollabNotes';
import { CollabPolls } from '../trip/collab/CollabPolls';
import { CollabPollVotes } from '../trip/collab/CollabPollVotes';
import { CollabMessages } from '../trip/collab/CollabMessages';
import { AssignmentParticipants } from '../trip/AssignmentParticipants';
import { AuditLog } from '../system/AuditLog';
import { Notifications } from '../notification/Notifications';
import { NotificationChannelPreferences } from '../notification/NotificationChannelPreferences';
import { BudgetItemMembers } from '../trip/budget/BudgetItemMembers';
import { CollabMessageReactions } from '../trip/collab/CollabMessageReactions';
import { InviteTokens } from '../system/InviteTokens';
import { PackingCategoryAssignees } from '../trip/lists/PackingCategoryAssignees';
import { PackingTemplates } from '../trip/lists/PackingTemplates';
import { PackingBags } from '../trip/lists/PackingBags';
import { VisitedCountries } from '../atlas/VisitedCountries';
import { BucketList } from '../atlas/BucketList';
import { ShareTokens } from '../trip/ShareTokens';
import { McpTokens } from '../mcp/McpTokens';
import { TripAlbumLinks } from '../trip/journey/TripAlbumLinks';
import { TodoItems } from '../trip/lists/TodoItems';
import { TodoCategoryAssignees } from '../trip/lists/TodoCategoryAssignees';
import { VisitedRegions } from '../atlas/VisitedRegions';
import { OldOauthConsents } from './OldOauthConsents';
import { OldOauthTokens } from './OldOauthTokens';
import { Journeys } from '../trip/journey/Journeys';
import { JourneyEntries } from '../trip/journey/JourneyEntries';
import { JourneyContributors } from '../trip/journey/JourneyContributors';
import { JourneyShareTokens } from '../trip/journey/JourneyShareTokens';
import { TrekPhotos } from '../trip/journey/TrekPhotos';
import { TripPhotos } from '../trip/TripPhotos';
import { UserNoticeDismissals } from '../system/UserNoticeDismissals';
import { IdempotencyKeys } from '../system/IdempotencyKeys';
import { OldOauthClients } from './OldOauthClients';
@Index('idx_users_email', ['email'], {})
@Entity('users')
export class SqliteUsers extends IntBaseEntity {
@Column({ name: 'username', unique: true })
username: string;
@Column({ name: 'email', unique: true })
email: string;
@Column({ name: 'password_hash' })
passwordHash: string;
@Column({ name: 'role', default: 'user' })
role: string;
@Column({ name: 'maps_api_key', nullable: true })
mapsApiKey: string | null;
@Column({ name: 'unsplash_api_key', nullable: true })
unsplashApiKey: string | null;
@Column({ name: 'openweather_api_key', nullable: true })
openweatherApiKey: string | null;
@Column({ name: 'avatar', nullable: true })
avatar: string | null;
@Column({ name: 'oidc_sub', nullable: true })
oidcSub: string | null;
@Column({ name: 'oidc_issuer', nullable: true })
oidcIssuer: string | null;
@Column({ name: 'last_login', nullable: true })
lastLogin: Date | null;
@Column({
name: 'mfa_enabled',
default: false,
})
mfaEnabled: boolean;
@Column({ name: 'mfa_secret', nullable: true })
mfaSecret: string | null;
@Column({ name: 'mfa_backup_codes', nullable: true })
mfaBackupCodes: string | null;
@Column({ name: 'immich_url', nullable: true })
immichUrl: string | null;
@Column({ name: 'immich_access_token', nullable: true })
immichAccessToken: string | null;
@Column({ name: 'synology_url', nullable: true })
synologyUrl: string | null;
@Column({ name: 'synology_username', nullable: true })
synologyUsername: string | null;
@Column({ name: 'synology_password', nullable: true })
synologyPassword: string | null;
@Column({ name: 'synology_sid', nullable: true })
synologySid: string | null;
@Column({
name: 'must_change_password',
default: false,
})
mustChangePassword: boolean;
@Column('int', { name: 'password_version', default: 0 })
passwordVersion: number;
@Column({ name: 'immich_api_key', nullable: true })
immichApiKey: string | null;
@Column({ name: 'synology_skip_ssl', default: false })
synologySkipSsl: boolean;
@Column({ name: 'synology_did', nullable: true })
synologyDid: string | null;
@Column('text', { name: 'first_seen_version', default: '0.0.0' })
firstSeenVersion: string;
@Column('int', { name: 'login_count', default: 0 })
loginCount: number;
@Column({ name: 'immich_auto_upload', default: false })
immichAutoUpload: boolean;
@OneToMany(
() => OldPasswordResetTokens,
(passwordResetTokens) => passwordResetTokens.user,
)
passwordResetTokens: OldPasswordResetTokens[];
@OneToMany(() => Settings, (settings) => settings.user)
settings: Settings[];
@OneToMany(() => Trips, (trips) => trips.user)
trips: Trips[];
@OneToMany(() => Categories, (categories) => categories.user)
categories: Categories[];
@OneToMany(() => Tags, (tags) => tags.user)
tags: Tags[];
@OneToMany(() => TripFiles, (tripFiles) => tripFiles.uploadedBy)
tripFiles: TripFiles[];
@OneToMany(() => TripMembers, (tripMembers) => tripMembers.invitedBy)
tripMembers: TripMembers[];
@OneToMany(() => TripMembers, (tripMembers) => tripMembers.user)
tripMembers2: TripMembers[];
@OneToMany(() => BudgetItems, (budgetItems) => budgetItems.paidByUser)
budgetItems: BudgetItems[];
@OneToOne(() => VacayPlans, (vacayPlans) => vacayPlans.owner)
vacayPlans: VacayPlans;
@OneToMany(
() => VacayPlanMembers,
(vacayPlanMembers) => vacayPlanMembers.user,
)
vacayPlanMembers: VacayPlanMembers[];
@OneToMany(() => VacayUserColors, (vacayUserColors) => vacayUserColors.user)
vacayUserColors: VacayUserColors[];
@OneToMany(() => VacayUserYears, (vacayUserYears) => vacayUserYears.user)
vacayUserYears: VacayUserYears[];
@OneToMany(() => VacayEntries, (vacayEntries) => vacayEntries.user)
vacayEntries: VacayEntries[];
@OneToMany(() => CollabNotes, (collabNotes) => collabNotes.user)
collabNotes: CollabNotes[];
@OneToMany(() => CollabPolls, (collabPolls) => collabPolls.user)
collabPolls: CollabPolls[];
@OneToMany(() => CollabPollVotes, (collabPollVotes) => collabPollVotes.user)
collabPollVotes: CollabPollVotes[];
@OneToMany(() => CollabMessages, (collabMessages) => collabMessages.user)
collabMessages: CollabMessages[];
@OneToMany(
() => AssignmentParticipants,
(assignmentParticipants) => assignmentParticipants.user,
)
assignmentParticipants: AssignmentParticipants[];
@OneToMany(() => AuditLog, (auditLog) => auditLog.user)
auditLogs: AuditLog[];
@OneToMany(() => Notifications, (notifications) => notifications.recipient)
notifications: Notifications[];
@OneToMany(() => Notifications, (notifications) => notifications.sender)
notifications2: Notifications[];
@OneToMany(
() => NotificationChannelPreferences,
(notificationChannelPreferences) => notificationChannelPreferences.user,
)
notificationChannelPreferences: NotificationChannelPreferences[];
@OneToMany(
() => BudgetItemMembers,
(budgetItemMembers) => budgetItemMembers.user,
)
budgetItemMembers: BudgetItemMembers[];
@OneToMany(
() => CollabMessageReactions,
(collabMessageReactions) => collabMessageReactions.user,
)
collabMessageReactions: CollabMessageReactions[];
@OneToMany(() => InviteTokens, (inviteTokens) => inviteTokens.createdBy)
inviteTokens: InviteTokens[];
@OneToMany(
() => PackingCategoryAssignees,
(packingCategoryAssignees) => packingCategoryAssignees.user,
)
packingCategoryAssignees: PackingCategoryAssignees[];
@OneToMany(
() => PackingTemplates,
(packingTemplates) => packingTemplates.createdBy,
)
packingTemplates: PackingTemplates[];
@OneToMany(() => PackingBags, (packingBags) => packingBags.user)
packingBags: PackingBags[];
@OneToMany(
() => VisitedCountries,
(visitedCountries) => visitedCountries.user,
)
visitedCountries: VisitedCountries[];
@OneToMany(() => BucketList, (bucketList) => bucketList.user)
bucketLists: BucketList[];
@OneToMany(() => ShareTokens, (shareTokens) => shareTokens.createdBy)
shareTokens: ShareTokens[];
@OneToMany(() => McpTokens, (mcpTokens) => mcpTokens.user)
mcpTokens: McpTokens[];
@OneToMany(() => TripAlbumLinks, (tripAlbumLinks) => tripAlbumLinks.user)
tripAlbumLinks: TripAlbumLinks[];
@OneToMany(() => TodoItems, (todoItems) => todoItems.assignedUser)
todoItems: TodoItems[];
@OneToMany(
() => TodoCategoryAssignees,
(todoCategoryAssignees) => todoCategoryAssignees.user,
)
todoCategoryAssignees: TodoCategoryAssignees[];
@OneToMany(() => VisitedRegions, (visitedRegions) => visitedRegions.user)
visitedRegions: VisitedRegions[];
@ManyToMany(() => PackingBags, (packingBags) => packingBags.users)
@JoinTable({
name: 'packing_bag_members',
joinColumns: [{ name: 'user_id', referencedColumnName: 'id' }],
inverseJoinColumns: [{ name: 'bag_id', referencedColumnName: 'id' }],
})
packingBags2: PackingBags[];
@OneToMany(() => OldOauthConsents, (oauthConsents) => oauthConsents.user)
oauthConsents: OldOauthConsents[];
@OneToMany(() => OldOauthTokens, (oauthTokens) => oauthTokens.user)
oauthTokens: OldOauthTokens[];
@OneToMany(() => Journeys, (journeys) => journeys.user)
journeys: Journeys[];
@OneToMany(() => JourneyEntries, (journeyEntries) => journeyEntries.author)
journeyEntries: JourneyEntries[];
@OneToMany(
() => JourneyContributors,
(journeyContributors) => journeyContributors.user,
)
journeyContributors: JourneyContributors[];
@OneToMany(
() => JourneyShareTokens,
(journeyShareTokens) => journeyShareTokens.createdBy,
)
journeyShareTokens: JourneyShareTokens[];
@OneToMany(() => TrekPhotos, (trekPhotos) => trekPhotos.owner)
trekPhotos: TrekPhotos[];
@OneToMany(() => TripPhotos, (tripPhotos) => tripPhotos.user)
tripPhotos: TripPhotos[];
@OneToMany(
() => UserNoticeDismissals,
(userNoticeDismissals) => userNoticeDismissals.user,
)
userNoticeDismissals: UserNoticeDismissals[];
@OneToMany(() => IdempotencyKeys, (idempotencyKeys) => idempotencyKeys.user)
idempotencyKeys: IdempotencyKeys[];
@OneToMany(() => OldOauthClients, (oauthClients) => oauthClients.user)
oauthClients: OldOauthClients[];
}
@@ -1,23 +0,0 @@
import { Column, Entity } from 'typeorm';
import { StringSortableBaseEntity } from '../base/BaseEntity';
@Entity('addons')
export class Addons extends StringSortableBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'description', nullable: true })
description: string | null;
@Column({ name: 'type', default: 'global' })
type: string;
@Column({ name: 'icon', default: 'Puzzle' })
icon: string | null;
@Column('int', { name: 'enabled', default: 0 })
enabled: number;
@Column('simple-json', { name: 'config', nullable: true, default: null })
config: Record<string, unknown> | null;
}
@@ -1,10 +0,0 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('app_settings')
export class AppSettings {
@PrimaryColumn({ name: 'key' })
declare id: string;
@Column({ name: 'value', nullable: true })
value: string | null;
}
@@ -1,25 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_audit_log_created', ['createdAt'], {})
@Entity('audit_log')
export class AuditLog extends IntBaseEntity {
@Column({ name: 'action' })
action: string;
@Column({ name: 'resource', nullable: true })
resource: string | null;
@Column('simple-json', { name: 'details', nullable: true })
details: Record<string, unknown> | null;
@Column({ name: 'ip', nullable: true })
ip: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.auditLogs, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,35 +0,0 @@
import { Entity, JoinColumn, ManyToOne } from 'typeorm';
import { Places } from '../trip/Places';
import { Reservations } from '../trip/reservation/Reservations';
import { TripFiles } from '../trip/files/TripFiles';
import { IntBaseEntity } from '../base/BaseEntity';
import { DayAssignments } from '../trip/DayAssignments';
@Entity('file_links')
export class FileLinks extends IntBaseEntity {
@ManyToOne(() => Places, (places) => places.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(
() => DayAssignments,
(dayAssignments) => dayAssignments.fileLinks,
{ onDelete: 'CASCADE' },
)
@JoinColumn([{ name: 'assignment_id', referencedColumnName: 'id' }])
assignment: DayAssignments;
@ManyToOne(() => Reservations, (reservations) => reservations.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'reservation_id', referencedColumnName: 'id' }])
reservation: Reservations;
@ManyToOne(() => TripFiles, (tripFiles) => tripFiles.fileLinks, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'file_id', referencedColumnName: 'id' }])
file: TripFiles;
}
@@ -1,38 +0,0 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
PrimaryColumn,
} from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_idempotency_keys_created', ['createdAt'], {})
@Entity('idempotency_keys')
export class IdempotencyKeys extends TimestampedEntity {
@PrimaryColumn({ name: 'key' })
key: string;
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'method' })
method: string;
@PrimaryColumn('text', { name: 'path' })
path: string;
@Column('int', { name: 'status_code' })
statusCode: number;
@Column('text', { name: 'response_body' })
responseBody: string;
@ManyToOne(() => SqliteUsers, (users) => users.idempotencyKeys, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,24 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('invite_tokens')
export class InviteTokens extends IntBaseEntity {
@Column({ name: 'token', unique: true })
token: string;
@Column('int', { name: 'max_uses', default: 1 })
maxUses: number;
@Column('int', { name: 'used_count', default: 0 })
usedCount: number;
@Column({ name: 'expires_at', nullable: true })
expiresAt: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.inviteTokens, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'created_by', referencedColumnName: 'id' }])
createdBy: SqliteUsers;
}
@@ -1,10 +0,0 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('schema_version')
export class SchemaVersion {
@PrimaryColumn('int', { name: 'id' })
id: number | null;
@Column('int', { name: 'version' })
version: number;
}
@@ -1,18 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('settings')
export class Settings extends IntBaseEntity {
@Column({ name: 'key' })
key: string;
@Column({ name: 'value', nullable: true })
value: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.settings, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,21 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
import { TimestampedEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('user_notice_dismissals')
export class UserNoticeDismissals extends TimestampedEntity {
@PrimaryColumn('int', { name: 'user_id' })
userId: number;
@PrimaryColumn({ name: 'notice_id' })
noticeId: string;
@Column('int', { name: 'dismissed_at' })
dismissedAt: number;
@ManyToOne(() => SqliteUsers, (users) => users.userNoticeDismissals, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
}
@@ -1,25 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { DayAssignments } from './DayAssignments';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Index('idx_assignment_participants_assignment', ['assignmentId'], {})
@Entity('assignment_participants')
export class AssignmentParticipants extends IntBaseEntity {
@Column('int', { name: 'assignment_id' })
assignmentId: number;
@ManyToOne(() => SqliteUsers, (users) => users.assignmentParticipants, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@ManyToOne(
() => DayAssignments,
(dayAssignments) => dayAssignments.assignmentParticipants,
{ onDelete: 'CASCADE' },
)
@JoinColumn([{ name: 'assignment_id', referencedColumnName: 'id' }])
assignment: DayAssignments;
}
@@ -1,25 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { Places } from './Places';
import { IntBaseEntity } from '../base/BaseEntity';
import { SqliteUsers } from '../old-entities/SqliteUsers';
@Entity('categories')
export class Categories extends IntBaseEntity {
@Column({ name: 'name' })
name: string;
@Column({ name: 'color', nullable: true, default: '#6366f1' })
color: string | null;
@Column({ name: 'icon', nullable: true, default: '📍' })
icon: string | null;
@ManyToOne(() => SqliteUsers, (users) => users.categories, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'user_id', referencedColumnName: 'id' }])
user: SqliteUsers;
@OneToMany(() => Places, (places) => places.category)
places: Places[];
}
@@ -1,59 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Days } from './Days';
import { Places } from './Places';
import { Trips } from './Trips';
import { IntBaseEntity } from '../base/BaseEntity';
@Index('idx_day_accommodations_end_day_id', ['endDayId'], {})
@Index('idx_day_accommodations_start_day_id', ['startDayId'], {})
@Index('idx_day_accommodations_trip_id', ['tripId'], {})
@Entity('day_accommodations')
export class DayAccommodations extends IntBaseEntity {
@Column('int', { name: 'trip_id' })
tripId: number;
@Column('int', { name: 'start_day_id' })
startDayId: number;
@Column('int', { name: 'end_day_id' })
endDayId: number;
@Column({ name: 'check_in', nullable: true })
checkIn: string | null;
@Column({ name: 'check_in_end', nullable: true })
checkInEnd: string | null;
@Column({ name: 'check_out', nullable: true })
checkOut: string | null;
@Column({ name: 'confirmation', nullable: true })
confirmation: string | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@ManyToOne(() => Days, (days) => days.dayAccommodations, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'end_day_id', referencedColumnName: 'id' }])
endDay: Days;
@ManyToOne(() => Days, (days) => days.dayAccommodations2, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'start_day_id', referencedColumnName: 'id' }])
startDay: Days;
@ManyToOne(() => Places, (places) => places.dayAccommodations, {
onDelete: 'SET NULL',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(() => Trips, (trips) => trips.dayAccommodations, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
}
@@ -1,76 +0,0 @@
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
} from 'typeorm';
import { Places } from './Places';
import { Days } from './Days';
import { AssignmentParticipants } from './AssignmentParticipants';
import { IntBaseEntity } from '../base/BaseEntity';
import { Reservations } from './reservation/Reservations';
import { FileLinks } from '../system/FileLinks';
@Index('idx_day_assignments_place_id', ['placeId'], {})
@Index('idx_day_assignments_day_id', ['dayId'], {})
@Entity('day_assignments')
export class DayAssignments extends IntBaseEntity {
@Column('int', { name: 'day_id' })
dayId: number;
@Column('int', { name: 'place_id' })
placeId: number;
@Column('int', {
name: 'order_index',
nullable: true,
default: 0,
})
orderIndex: number | null;
@Column('text', { name: 'notes', nullable: true })
notes: string | null;
@Column({
name: 'reservation_status',
nullable: true,
default: 'none',
})
reservationStatus: string | null;
@Column('text', { name: 'reservation_notes', nullable: true })
reservationNotes: string | null;
@Column({ name: 'reservation_datetime', nullable: true })
reservationDatetime: string | null;
@Column({ name: 'assignment_time', nullable: true })
assignmentTime: string | null;
@Column({ name: 'assignment_end_time', nullable: true })
assignmentEndTime: string | null;
@ManyToOne(() => Places, (places) => places.dayAssignments, {
onDelete: 'CASCADE',
})
@JoinColumn([{ name: 'place_id', referencedColumnName: 'id' }])
place: Places;
@ManyToOne(() => Days, (days) => days.dayAssignments, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'day_id', referencedColumnName: 'id' }])
day: Days;
@OneToMany(() => Reservations, (reservations) => reservations.assignment)
reservations: Reservations[];
@OneToMany(
() => AssignmentParticipants,
(assignmentParticipants) => assignmentParticipants.assignment,
)
assignmentParticipants: AssignmentParticipants[];
@OneToMany(() => FileLinks, (fileLinks) => fileLinks.assignment)
fileLinks: FileLinks[];
}
@@ -1,28 +0,0 @@
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Trips } from './Trips';
import { Days } from './Days';
import { IntSortableBaseEntity } from '../base/BaseEntity';
@Index('idx_day_notes_day_id', ['dayId'], {})
@Entity('day_notes')
export class DayNotes extends IntSortableBaseEntity {
@Column('int', { name: 'day_id' })
dayId: number;
@Column('text', { name: 'text' })
text: string;
@Column({ name: 'time', nullable: true })
time: string | null;
@Column({ name: 'icon', nullable: true, default: '📝' })
icon: string | null;
@ManyToOne(() => Trips, (trips) => trips.dayNotes, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'trip_id', referencedColumnName: 'id' }])
trip: Trips;
@ManyToOne(() => Days, (days) => days.dayNotes, { onDelete: 'CASCADE' })
@JoinColumn([{ name: 'day_id', referencedColumnName: 'id' }])
day: Days;
}

Some files were not shown because too many files have changed in this diff Show More