174 lines
5.9 KiB
TypeScript
174 lines
5.9 KiB
TypeScript
import * as plugins from './cloudflare.plugins.js';
|
|
import * as interfaces from './interfaces/index.js';
|
|
import { WorkerManager } from './cloudflare.classes.workermanager.js';
|
|
import { logger } from './cloudflare.logger.js';
|
|
|
|
export interface IWorkerRoute extends interfaces.ICflareWorkerRoute {
|
|
zoneName: string;
|
|
}
|
|
|
|
export interface IWorkerRouteDefinition {
|
|
zoneName: string;
|
|
pattern: string;
|
|
}
|
|
|
|
export class CloudflareWorker {
|
|
// STATIC
|
|
public static async fromApiObject(
|
|
workerManager: WorkerManager,
|
|
apiObject
|
|
): Promise<CloudflareWorker> {
|
|
const newWorker = new CloudflareWorker(workerManager);
|
|
Object.assign(newWorker, apiObject);
|
|
await newWorker.getRoutes();
|
|
return newWorker;
|
|
}
|
|
|
|
// INSTANCE
|
|
private workerManager: WorkerManager;
|
|
|
|
public script: string;
|
|
public id: string;
|
|
public etag: string;
|
|
// tslint:disable-next-line: variable-name
|
|
public created_on: string;
|
|
// tslint:disable-next-line: variable-name
|
|
public modified_on: string;
|
|
|
|
public routes: IWorkerRoute[] = [];
|
|
constructor(workerManagerArg: WorkerManager) {
|
|
this.workerManager = workerManagerArg;
|
|
}
|
|
|
|
/**
|
|
* gets all routes for a worker
|
|
*/
|
|
public async getRoutes() {
|
|
const zones = await this.workerManager.cfAccount.convenience.listZones();
|
|
|
|
for (const zone of zones) {
|
|
try {
|
|
// The official client doesn't have a direct method to list worker routes
|
|
// We'll use the custom request method for this specific case
|
|
const response: {
|
|
result: interfaces.ICflareWorkerRoute[];
|
|
} = await this.workerManager.cfAccount.request('GET', `/zones/${zone.id}/workers/routes`);
|
|
|
|
for (const route of response.result) {
|
|
logger.log('debug', `Processing route: ${route.pattern}`);
|
|
logger.log('debug', `Comparing script: ${route.script} with worker ID: ${this.id}`);
|
|
|
|
if (route.script === this.id) {
|
|
this.routes.push({ ...route, zoneName: zone.name });
|
|
}
|
|
}
|
|
} catch (error) {
|
|
logger.log('error', `Failed to get worker routes for zone ${zone.name}: ${error.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets routes for this worker
|
|
* @param routeArray Array of route definitions
|
|
*/
|
|
public async setRoutes(routeArray: IWorkerRouteDefinition[]) {
|
|
for (const newRoute of routeArray) {
|
|
// Determine whether a route is new, needs an update, or is already up to date
|
|
let routeStatus: 'new' | 'needsUpdate' | 'alreadyUpToDate' = 'new';
|
|
let routeIdForUpdate: string;
|
|
|
|
for (const existingRoute of this.routes) {
|
|
if (existingRoute.pattern === newRoute.pattern) {
|
|
routeStatus = 'needsUpdate';
|
|
routeIdForUpdate = existingRoute.id;
|
|
|
|
if (existingRoute.script === this.id) {
|
|
routeStatus = 'alreadyUpToDate';
|
|
logger.log('info', `Route already exists, no update needed`);
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
const zoneId = await this.workerManager.cfAccount.convenience.getZoneId(newRoute.zoneName);
|
|
|
|
// Handle route creation or update
|
|
if (routeStatus === 'new') {
|
|
// The official client doesn't have a direct method to create worker routes
|
|
// We'll use the custom request method for this specific case
|
|
await this.workerManager.cfAccount.request('POST', `/zones/${zoneId}/workers/routes`, {
|
|
pattern: newRoute.pattern,
|
|
script: this.id,
|
|
});
|
|
|
|
logger.log('info', `Created new route ${newRoute.pattern} for worker ${this.id}`);
|
|
} else if (routeStatus === 'needsUpdate') {
|
|
// The official client doesn't have a direct method to update worker routes
|
|
// We'll use the custom request method for this specific case
|
|
await this.workerManager.cfAccount.request('PUT', `/zones/${zoneId}/workers/routes/${routeIdForUpdate}`, {
|
|
pattern: newRoute.pattern,
|
|
script: this.id,
|
|
});
|
|
|
|
logger.log('info', `Updated route ${newRoute.pattern} for worker ${this.id}`);
|
|
}
|
|
} catch (error) {
|
|
logger.log('error', `Failed to set route ${newRoute.pattern}: ${error.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Upload or update worker script content
|
|
* @param scriptContent The worker script content
|
|
* @returns Updated worker object
|
|
*/
|
|
public async updateScript(scriptContent: string): Promise<CloudflareWorker> {
|
|
if (!this.workerManager.cfAccount.preselectedAccountId) {
|
|
throw new Error('No account selected. Please select it first on the account.');
|
|
}
|
|
|
|
try {
|
|
logger.log('info', `Updating script for worker ${this.id}`);
|
|
|
|
// The official client requires the metadata property
|
|
const updatedWorker = await this.workerManager.cfAccount.apiAccount.workers.scripts.content.update(this.id, {
|
|
account_id: this.workerManager.cfAccount.preselectedAccountId,
|
|
"CF-WORKER-BODY-PART": scriptContent,
|
|
metadata: {} // Required empty object
|
|
});
|
|
|
|
// Update this instance with new data
|
|
Object.assign(this, updatedWorker);
|
|
|
|
return this;
|
|
} catch (error) {
|
|
logger.log('error', `Failed to update worker script: ${error.message}`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete this worker script
|
|
* @returns True if deletion was successful
|
|
*/
|
|
public async delete(): Promise<boolean> {
|
|
if (!this.workerManager.cfAccount.preselectedAccountId) {
|
|
throw new Error('No account selected. Please select it first on the account.');
|
|
}
|
|
|
|
try {
|
|
logger.log('info', `Deleting worker ${this.id}`);
|
|
|
|
await this.workerManager.cfAccount.apiAccount.workers.scripts.delete(this.id, {
|
|
account_id: this.workerManager.cfAccount.preselectedAccountId
|
|
});
|
|
|
|
return true;
|
|
} catch (error) {
|
|
logger.log('error', `Failed to delete worker: ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
} |