mirror of
https://github.com/pockethost/pockethost.git
synced 2025-11-23 22:15:49 +00:00
feat: add db migration support for multiple custom domains per instance
This commit is contained in:
parent
81fd2818cc
commit
60307e6ca7
5
.changeset/breezy-pans-move.md
Normal file
5
.changeset/breezy-pans-move.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'pockethost': patch
|
||||
---
|
||||
|
||||
Add db migration support for multiple custom domains per instance
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,84 +1,63 @@
|
||||
// src/lib/handlers/instance/hooks.ts
|
||||
routerAdd(
|
||||
"PUT",
|
||||
"/api/instance/:id",
|
||||
(c) => {
|
||||
|
||||
//#region src/lib/handlers/instance/hooks.ts
|
||||
routerAdd("PUT", "/api/instance/:id", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceUpdate(c);
|
||||
},
|
||||
$apis.requireRecordAuth()
|
||||
);
|
||||
routerAdd(
|
||||
"POST",
|
||||
"/api/instance",
|
||||
(c) => {
|
||||
}, $apis.requireRecordAuth());
|
||||
routerAdd("POST", "/api/instance", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceCreate(c);
|
||||
},
|
||||
$apis.requireRecordAuth()
|
||||
);
|
||||
routerAdd(
|
||||
"DELETE",
|
||||
"/api/instance/:id",
|
||||
(c) => {
|
||||
}, $apis.requireRecordAuth());
|
||||
routerAdd("DELETE", "/api/instance/:id", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceDelete(c);
|
||||
},
|
||||
$apis.requireRecordAuth()
|
||||
);
|
||||
routerAdd(
|
||||
"GET",
|
||||
"/api/instance/resolve",
|
||||
(c) => {
|
||||
}, $apis.requireRecordAuth());
|
||||
routerAdd("GET", "/api/instance/resolve", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceResolve(c);
|
||||
},
|
||||
$apis.requireAdminAuth()
|
||||
);
|
||||
}, $apis.requireAdminAuth());
|
||||
/** Validate instance version */
|
||||
onModelBeforeCreate((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceVersionValidation(e);
|
||||
}, "instances");
|
||||
onModelAfterCreate((e) => {
|
||||
}, "instances");
|
||||
onAfterBootstrap((e) => {
|
||||
});
|
||||
onAfterBootstrap((e) => {
|
||||
});
|
||||
onModelAfterCreate((e) => {}, "instances");
|
||||
onAfterBootstrap((e) => {});
|
||||
onAfterBootstrap((e) => {});
|
||||
/** Reset instance status to idle on start */
|
||||
onAfterBootstrap((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstancesResetIdle(e);
|
||||
});
|
||||
/** Migrate existing cnames to domains table */
|
||||
onAfterBootstrap((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleMigrateCnamesToDomains(e);
|
||||
});
|
||||
/** Validate instance version */
|
||||
onModelBeforeUpdate((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e);
|
||||
}, "instances");
|
||||
|
||||
// src/lib/handlers/lemon/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/lemon/hooks.ts
|
||||
routerAdd("POST", "/api/ls", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleLemonSqueezySale(c);
|
||||
});
|
||||
|
||||
// src/lib/handlers/mail/hooks.ts
|
||||
routerAdd(
|
||||
"POST",
|
||||
"/api/mail",
|
||||
(c) => {
|
||||
//#endregion
|
||||
//#region src/lib/handlers/mail/hooks.ts
|
||||
routerAdd("POST", "/api/mail", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleMailSend(c);
|
||||
},
|
||||
$apis.requireAdminAuth()
|
||||
);
|
||||
}, $apis.requireAdminAuth());
|
||||
|
||||
// src/lib/handlers/meta/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/meta/hooks.ts
|
||||
onAfterBootstrap((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleMetaUpdateAtBoot(e);
|
||||
});
|
||||
|
||||
// src/lib/handlers/mirror/hooks.ts
|
||||
routerAdd(
|
||||
"GET",
|
||||
"/api/mirror",
|
||||
(c) => {
|
||||
//#endregion
|
||||
//#region src/lib/handlers/mirror/hooks.ts
|
||||
routerAdd("GET", "/api/mirror", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleMirrorData(c);
|
||||
},
|
||||
$apis.gzip(),
|
||||
$apis.requireAdminAuth()
|
||||
);
|
||||
}, $apis.gzip(), $apis.requireAdminAuth());
|
||||
|
||||
// src/lib/handlers/notify/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/notify/hooks.ts
|
||||
routerAdd(`GET`, `api/process_single_notification`, (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleProcessSingleNotification(c);
|
||||
});
|
||||
@ -89,12 +68,14 @@ onModelBeforeUpdate((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleUserWelcomeMessage(e);
|
||||
}, "users");
|
||||
|
||||
// src/lib/handlers/outpost/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/outpost/hooks.ts
|
||||
routerAdd("GET", "/api/unsubscribe", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleOutpostUnsubscribe(c);
|
||||
});
|
||||
|
||||
// src/lib/handlers/signup/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/signup/hooks.ts
|
||||
routerAdd("GET", "/api/signup", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleSignupCheck(c);
|
||||
});
|
||||
@ -102,27 +83,29 @@ routerAdd("POST", "/api/signup", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleSignupConfirm(c);
|
||||
});
|
||||
|
||||
// src/lib/handlers/sns/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/sns/hooks.ts
|
||||
routerAdd("POST", "/api/sns", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleSesError(c);
|
||||
});
|
||||
|
||||
// src/lib/handlers/stats/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/stats/hooks.ts
|
||||
routerAdd("GET", "/api/stats", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleStatsRequest(c);
|
||||
});
|
||||
|
||||
// src/lib/handlers/user/hooks.ts
|
||||
routerAdd(
|
||||
"GET",
|
||||
"/api/userToken/:id",
|
||||
(c) => {
|
||||
//#endregion
|
||||
//#region src/lib/handlers/user/hooks.ts
|
||||
routerAdd("GET", "/api/userToken/:id", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleUserTokenRequest(c);
|
||||
},
|
||||
$apis.requireAdminAuth()
|
||||
);
|
||||
}, $apis.requireAdminAuth());
|
||||
|
||||
// src/lib/handlers/versions/hooks.ts
|
||||
//#endregion
|
||||
//#region src/lib/handlers/versions/hooks.ts
|
||||
/** Return a list of available PocketBase versions */
|
||||
routerAdd("GET", "/api/versions", (c) => {
|
||||
return require(`${__hooks}/mothership`).HandleVersionsRequest(c);
|
||||
});
|
||||
|
||||
//#endregion
|
||||
@ -0,0 +1,76 @@
|
||||
/// <reference path="../src/types/types.d.ts" />
|
||||
migrate(
|
||||
(db) => {
|
||||
const collection = new Collection({
|
||||
id: 'jw1wz9nmkvnhcm6',
|
||||
created: '2025-07-18 05:18:37.698Z',
|
||||
updated: '2025-07-18 05:18:37.698Z',
|
||||
name: 'domains',
|
||||
type: 'base',
|
||||
system: false,
|
||||
schema: [
|
||||
{
|
||||
system: false,
|
||||
id: 'fhie5snn',
|
||||
name: 'instance',
|
||||
type: 'relation',
|
||||
required: false,
|
||||
presentable: false,
|
||||
unique: false,
|
||||
options: {
|
||||
collectionId: 'etae8tuiaxl6xfv',
|
||||
cascadeDelete: false,
|
||||
minSelect: null,
|
||||
maxSelect: 1,
|
||||
displayFields: null,
|
||||
},
|
||||
},
|
||||
{
|
||||
system: false,
|
||||
id: 'wn3oncif',
|
||||
name: 'domain',
|
||||
type: 'text',
|
||||
required: false,
|
||||
presentable: false,
|
||||
unique: false,
|
||||
options: {
|
||||
min: null,
|
||||
max: null,
|
||||
pattern: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
system: false,
|
||||
id: 'vzkcvhhg',
|
||||
name: 'active',
|
||||
type: 'bool',
|
||||
required: false,
|
||||
presentable: false,
|
||||
unique: false,
|
||||
options: {},
|
||||
},
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX `idx_gtGcwf2` ON `domains` (`domain`)',
|
||||
'CREATE INDEX `idx_OtPOwXe` ON `domains` (`instance`)',
|
||||
'CREATE INDEX `idx_0omsTdi` ON `domains` (`created`)',
|
||||
'CREATE INDEX `idx_uMaIOVQ` ON `domains` (`updated`)',
|
||||
'CREATE UNIQUE INDEX `idx_VLBOSap` ON `domains` (\n `instance`,\n `domain`\n)',
|
||||
],
|
||||
listRule: null,
|
||||
viewRule: null,
|
||||
createRule: null,
|
||||
updateRule: null,
|
||||
deleteRule: null,
|
||||
options: {},
|
||||
})
|
||||
|
||||
return Dao(db).saveCollection(collection)
|
||||
},
|
||||
(db) => {
|
||||
const dao = new Dao(db)
|
||||
const collection = dao.findCollectionByNameOrId('jw1wz9nmkvnhcm6')
|
||||
|
||||
return dao.deleteCollection(collection)
|
||||
},
|
||||
)
|
||||
@ -0,0 +1,76 @@
|
||||
import { mkLog } from '$util/Logger'
|
||||
|
||||
export const HandleMigrateCnamesToDomains = (e: core.BootstrapEvent) => {
|
||||
const dao = $app.dao()
|
||||
const log = mkLog(`bootstrap:migrate-cnames`)
|
||||
|
||||
log(`Starting cname to domains migration`)
|
||||
|
||||
try {
|
||||
// Check if domains table exists
|
||||
const domainsCollection = dao.findCollectionByNameOrId('domains')
|
||||
if (!domainsCollection) {
|
||||
log(`Domains collection not found, skipping migration`)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if there are any instances with cnames that haven't been migrated
|
||||
log(`Checking for instances with cnames`)
|
||||
const instancesWithCnames = dao.findRecordsByFilter(
|
||||
'instances',
|
||||
"cname != NULL && cname != ''",
|
||||
)
|
||||
|
||||
if (instancesWithCnames.length === 0) {
|
||||
log(`No cnames to migrate`)
|
||||
return
|
||||
}
|
||||
|
||||
log(`Found ${instancesWithCnames.length} instances with cnames`)
|
||||
|
||||
// Check which ones are already migrated
|
||||
const unmigrated = instancesWithCnames.filter((instance) => {
|
||||
if (!instance) return false
|
||||
try {
|
||||
const existingDomain = dao.findFirstRecordByFilter(
|
||||
'domains',
|
||||
`instance = "${instance.getId()}"`,
|
||||
)
|
||||
return !existingDomain
|
||||
} catch (e) {
|
||||
// Not found means not migrated
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
if (unmigrated.length === 0) {
|
||||
log(`All cnames already migrated`)
|
||||
return
|
||||
}
|
||||
|
||||
log(`Found ${unmigrated.length} cnames to migrate`)
|
||||
|
||||
// Migrate cnames to domains table
|
||||
let migrated = 0
|
||||
unmigrated.forEach((instance) => {
|
||||
if (!instance) return
|
||||
try {
|
||||
const domainsCollection = dao.findCollectionByNameOrId('domains')
|
||||
const domainRecord = new Record(domainsCollection)
|
||||
|
||||
domainRecord.set('instance', instance.getId())
|
||||
domainRecord.set('domain', instance.getString('cname'))
|
||||
domainRecord.set('active', instance.getBool('cname_active'))
|
||||
|
||||
dao.saveRecord(domainRecord)
|
||||
migrated++
|
||||
} catch (error) {
|
||||
log(`Failed to migrate cname for instance ${instance.getId()}:`, error)
|
||||
}
|
||||
})
|
||||
|
||||
log(`Successfully migrated ${migrated} cnames to domains table`)
|
||||
} catch (error) {
|
||||
log(`Error migrating cnames: ${error}`)
|
||||
}
|
||||
}
|
||||
@ -52,6 +52,11 @@ onAfterBootstrap((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstancesResetIdle(e)
|
||||
})
|
||||
|
||||
/** Migrate existing cnames to domains table */
|
||||
onAfterBootstrap((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleMigrateCnamesToDomains(e)
|
||||
})
|
||||
|
||||
/** Validate instance version */
|
||||
onModelBeforeUpdate((e) => {
|
||||
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e)
|
||||
|
||||
@ -3,6 +3,7 @@ export * from './api/HandleInstanceDelete'
|
||||
export * from './api/HandleInstanceResolve'
|
||||
export * from './api/HandleInstanceUpdate'
|
||||
export * from './bootstrap/HandleInstancesResetIdle'
|
||||
export * from './bootstrap/HandleMigrateCnamesToDomains'
|
||||
export * from './bootstrap/HandleMigrateInstanceVersions'
|
||||
export * from './bootstrap/HandleMigrateRegions'
|
||||
export * from './model/HandleInstanceBeforeUpdate'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user