mirror of
https://github.com/pockethost/pockethost.git
synced 2025-11-24 06:25:48 +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(
|
//#region src/lib/handlers/instance/hooks.ts
|
||||||
"PUT",
|
routerAdd("PUT", "/api/instance/:id", (c) => {
|
||||||
"/api/instance/:id",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceUpdate(c);
|
return require(`${__hooks}/mothership`).HandleInstanceUpdate(c);
|
||||||
},
|
}, $apis.requireRecordAuth());
|
||||||
$apis.requireRecordAuth()
|
routerAdd("POST", "/api/instance", (c) => {
|
||||||
);
|
|
||||||
routerAdd(
|
|
||||||
"POST",
|
|
||||||
"/api/instance",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceCreate(c);
|
return require(`${__hooks}/mothership`).HandleInstanceCreate(c);
|
||||||
},
|
}, $apis.requireRecordAuth());
|
||||||
$apis.requireRecordAuth()
|
routerAdd("DELETE", "/api/instance/:id", (c) => {
|
||||||
);
|
|
||||||
routerAdd(
|
|
||||||
"DELETE",
|
|
||||||
"/api/instance/:id",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceDelete(c);
|
return require(`${__hooks}/mothership`).HandleInstanceDelete(c);
|
||||||
},
|
}, $apis.requireRecordAuth());
|
||||||
$apis.requireRecordAuth()
|
routerAdd("GET", "/api/instance/resolve", (c) => {
|
||||||
);
|
|
||||||
routerAdd(
|
|
||||||
"GET",
|
|
||||||
"/api/instance/resolve",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceResolve(c);
|
return require(`${__hooks}/mothership`).HandleInstanceResolve(c);
|
||||||
},
|
}, $apis.requireAdminAuth());
|
||||||
$apis.requireAdminAuth()
|
/** Validate instance version */
|
||||||
);
|
|
||||||
onModelBeforeCreate((e) => {
|
onModelBeforeCreate((e) => {
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceVersionValidation(e);
|
return require(`${__hooks}/mothership`).HandleInstanceVersionValidation(e);
|
||||||
}, "instances");
|
}, "instances");
|
||||||
onModelAfterCreate((e) => {
|
onModelAfterCreate((e) => {}, "instances");
|
||||||
}, "instances");
|
onAfterBootstrap((e) => {});
|
||||||
onAfterBootstrap((e) => {
|
onAfterBootstrap((e) => {});
|
||||||
});
|
/** Reset instance status to idle on start */
|
||||||
onAfterBootstrap((e) => {
|
|
||||||
});
|
|
||||||
onAfterBootstrap((e) => {
|
onAfterBootstrap((e) => {
|
||||||
return require(`${__hooks}/mothership`).HandleInstancesResetIdle(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) => {
|
onModelBeforeUpdate((e) => {
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e);
|
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e);
|
||||||
}, "instances");
|
}, "instances");
|
||||||
|
|
||||||
// src/lib/handlers/lemon/hooks.ts
|
//#endregion
|
||||||
|
//#region src/lib/handlers/lemon/hooks.ts
|
||||||
routerAdd("POST", "/api/ls", (c) => {
|
routerAdd("POST", "/api/ls", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleLemonSqueezySale(c);
|
return require(`${__hooks}/mothership`).HandleLemonSqueezySale(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
// src/lib/handlers/mail/hooks.ts
|
//#endregion
|
||||||
routerAdd(
|
//#region src/lib/handlers/mail/hooks.ts
|
||||||
"POST",
|
routerAdd("POST", "/api/mail", (c) => {
|
||||||
"/api/mail",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleMailSend(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) => {
|
onAfterBootstrap((e) => {
|
||||||
return require(`${__hooks}/mothership`).HandleMetaUpdateAtBoot(e);
|
return require(`${__hooks}/mothership`).HandleMetaUpdateAtBoot(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
// src/lib/handlers/mirror/hooks.ts
|
//#endregion
|
||||||
routerAdd(
|
//#region src/lib/handlers/mirror/hooks.ts
|
||||||
"GET",
|
routerAdd("GET", "/api/mirror", (c) => {
|
||||||
"/api/mirror",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleMirrorData(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) => {
|
routerAdd(`GET`, `api/process_single_notification`, (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleProcessSingleNotification(c);
|
return require(`${__hooks}/mothership`).HandleProcessSingleNotification(c);
|
||||||
});
|
});
|
||||||
@ -89,12 +68,14 @@ onModelBeforeUpdate((e) => {
|
|||||||
return require(`${__hooks}/mothership`).HandleUserWelcomeMessage(e);
|
return require(`${__hooks}/mothership`).HandleUserWelcomeMessage(e);
|
||||||
}, "users");
|
}, "users");
|
||||||
|
|
||||||
// src/lib/handlers/outpost/hooks.ts
|
//#endregion
|
||||||
|
//#region src/lib/handlers/outpost/hooks.ts
|
||||||
routerAdd("GET", "/api/unsubscribe", (c) => {
|
routerAdd("GET", "/api/unsubscribe", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleOutpostUnsubscribe(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) => {
|
routerAdd("GET", "/api/signup", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleSignupCheck(c);
|
return require(`${__hooks}/mothership`).HandleSignupCheck(c);
|
||||||
});
|
});
|
||||||
@ -102,27 +83,29 @@ routerAdd("POST", "/api/signup", (c) => {
|
|||||||
return require(`${__hooks}/mothership`).HandleSignupConfirm(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) => {
|
routerAdd("POST", "/api/sns", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleSesError(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) => {
|
routerAdd("GET", "/api/stats", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleStatsRequest(c);
|
return require(`${__hooks}/mothership`).HandleStatsRequest(c);
|
||||||
});
|
});
|
||||||
|
|
||||||
// src/lib/handlers/user/hooks.ts
|
//#endregion
|
||||||
routerAdd(
|
//#region src/lib/handlers/user/hooks.ts
|
||||||
"GET",
|
routerAdd("GET", "/api/userToken/:id", (c) => {
|
||||||
"/api/userToken/:id",
|
|
||||||
(c) => {
|
|
||||||
return require(`${__hooks}/mothership`).HandleUserTokenRequest(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) => {
|
routerAdd("GET", "/api/versions", (c) => {
|
||||||
return require(`${__hooks}/mothership`).HandleVersionsRequest(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)
|
return require(`${__hooks}/mothership`).HandleInstancesResetIdle(e)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** Migrate existing cnames to domains table */
|
||||||
|
onAfterBootstrap((e) => {
|
||||||
|
return require(`${__hooks}/mothership`).HandleMigrateCnamesToDomains(e)
|
||||||
|
})
|
||||||
|
|
||||||
/** Validate instance version */
|
/** Validate instance version */
|
||||||
onModelBeforeUpdate((e) => {
|
onModelBeforeUpdate((e) => {
|
||||||
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e)
|
return require(`${__hooks}/mothership`).HandleInstanceBeforeUpdate(e)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ export * from './api/HandleInstanceDelete'
|
|||||||
export * from './api/HandleInstanceResolve'
|
export * from './api/HandleInstanceResolve'
|
||||||
export * from './api/HandleInstanceUpdate'
|
export * from './api/HandleInstanceUpdate'
|
||||||
export * from './bootstrap/HandleInstancesResetIdle'
|
export * from './bootstrap/HandleInstancesResetIdle'
|
||||||
|
export * from './bootstrap/HandleMigrateCnamesToDomains'
|
||||||
export * from './bootstrap/HandleMigrateInstanceVersions'
|
export * from './bootstrap/HandleMigrateInstanceVersions'
|
||||||
export * from './bootstrap/HandleMigrateRegions'
|
export * from './bootstrap/HandleMigrateRegions'
|
||||||
export * from './model/HandleInstanceBeforeUpdate'
|
export * from './model/HandleInstanceBeforeUpdate'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user