Compare commits
79 Commits
Author | SHA1 | Date | |
---|---|---|---|
d1788dc626 | |||
ba49c42dd8 | |||
4600749442 | |||
b0f8d1e4d0 | |||
902ca30529 | |||
5731150157 | |||
f39f8cd33c | |||
1d2e0974b2 | |||
801f86fede | |||
42feb09b4f | |||
d72bb28cf9 | |||
b9f0b798c9 | |||
9b5f42ef9b | |||
4e3355dc43 | |||
fc0a27f5b6 | |||
0248d52548 | |||
c3984819cc | |||
045b87a4a2 | |||
48ca9fdbb9 | |||
e466944c55 | |||
6d8deca9d4 | |||
a4518f3068 | |||
9e338354c6 | |||
9d8c14d187 | |||
5a0b12f6aa | |||
387f00078f | |||
fe2f45e3a9 | |||
90c9bfc906 | |||
4f9e81f612 | |||
a4e280f9f0 | |||
52bd80aebd | |||
15e3cdae83 | |||
c72147b469 | |||
d98c2f89c5 | |||
2b722816f6 | |||
91d58277dd | |||
2458da6754 | |||
d4379d19d3 | |||
b0fdd520f3 | |||
a746577945 | |||
bc4cae3333 | |||
e0614b5956 | |||
f568949085 | |||
bee256416f | |||
afa2679501 | |||
7838642fd5 | |||
7a992badf4 | |||
c65790e2f9 | |||
7ec0fe78fc | |||
12f4456ebd | |||
3e8cf73877 | |||
0032292714 | |||
ead87ceb63 | |||
04d70a4d12 | |||
8da43a79d3 | |||
3153021190 | |||
82701c19e7 | |||
d3a68b4fef | |||
c4c1367306 | |||
1f5352d9f5 | |||
f652cc72fe | |||
f510408fce | |||
e250e9b1a2 | |||
5a9b7bbeee | |||
1158b4ff99 | |||
8eb777dd45 | |||
acf5c242d3 | |||
9e9dd8d935 | |||
b7cc500f4d | |||
8a4126a49c | |||
b86391ca00 | |||
92682c1276 | |||
05677231f7 | |||
9c036925fd | |||
d3d5f72193 | |||
3d7c0e6b64 | |||
4faefb0bd7 | |||
162fff134e | |||
426237b2a7 |
20
.gitignore
vendored
20
.gitignore
vendored
@ -1,6 +1,20 @@
|
||||
.nogit/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
docs/
|
||||
public/
|
||||
pages/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
.nogit/
|
||||
nogit/
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# custom
|
@ -1,71 +0,0 @@
|
||||
# gitzone standard
|
||||
image: hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .yarn/
|
||||
key: "$CI_BUILD_STAGE"
|
||||
|
||||
stages:
|
||||
- test
|
||||
- release
|
||||
- trigger
|
||||
- pages
|
||||
|
||||
testLEGACY:
|
||||
stage: test
|
||||
script:
|
||||
- npmci test legacy
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
testLTS:
|
||||
stage: test
|
||||
script:
|
||||
- npmci test lts
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testSTABLE:
|
||||
stage: test
|
||||
script:
|
||||
- npmci test stable
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
|
||||
trigger:
|
||||
stage: trigger
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- docker
|
||||
|
||||
pages:
|
||||
image: hosttoday/ht-docker-node:npmci
|
||||
stage: pages
|
||||
script:
|
||||
- npmci command yarn global add npmpage
|
||||
- npmci command npmpage
|
||||
tags:
|
||||
- docker
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
12
.travis.yml
12
.travis.yml
@ -1,12 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '4'
|
||||
- stable
|
||||
deploy:
|
||||
provider: npm
|
||||
email: npm@lossless.digital
|
||||
api_key:
|
||||
secure: uWqO634z8xMWI8tcIpSvUeVeG4ypX5fppXWxrSKbO5zOHCHGqJK90XiGFfKUekMf0cYQPb5dLT5+J/3nd4mf4KtU3+v1OK6ZikEqn/PcSeqOmK7EnI9wDFZwDTgJWIn0lRwX2mfB9meblSZ7XthTXumX78fmRTyeyImLm9P0ak+CrNzs8rzKauBoqeVryOez4/LaH3f0kxSz7o7zYLxFqx5xjQ7TFqd1kkVTf4pSQanLHY3z+7+mKrkbcNVxx2gF76hyx6E4pntSJHrOEE/VU/KMk2B6yzrVWYUHUiSRGYOV9U17YaaWlC9DZmnS1cvYcqq3YNujTwPWtci3It9S98hLrSTnCCqin6xhj8IuV6U4WADiXOUvNKuTRcd0/leQ4w3xpPJ1FR2gRtEhwQ0NsnY0vL9tuRAW71lf31122TTJI8lJQNrnaeIGbX7eE0Pq0jeTpmM2W/Tl8pl6s6zBjlEC/mCynQq1pBiz7UmxMYCPE162I8V5USeZOBLzDPZV2y7hmPWjMrWTT+i/IpFmXHjQtVrwlyU6fCOeYHgK/5GdyhnrRYYlx+ce6pCn4tmkVxduimC3m1G8cTkPl00fIpy7KSVcaeQrc1N+KQUqK4FpIjeqB904SVPsI5v3P7sdobaT1aqFqszhR+JK5tXaoesew8R2RncjFK69J7DHJWk=
|
||||
on:
|
||||
tags: true
|
||||
repo: pushrocks/cflare
|
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "npm test",
|
||||
"name": "Run npm test",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
26
.vscode/settings.json
vendored
Normal file
26
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["/npmextra.json"],
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"npmci": {
|
||||
"type": "object",
|
||||
"description": "settings for npmci"
|
||||
},
|
||||
"gitzone": {
|
||||
"type": "object",
|
||||
"description": "settings for gitzone",
|
||||
"properties": {
|
||||
"projectType": {
|
||||
"type": "string",
|
||||
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
51
README.md
51
README.md
@ -1,51 +0,0 @@
|
||||
# cflare
|
||||
easy cloudflare management
|
||||
|
||||
## Availabililty
|
||||
[](https://www.npmjs.com/package/cflare)
|
||||
[](https://GitLab.com/mojoio/cflare)
|
||||
[](https://github.com/mojoio/cflare)
|
||||
[](https://mojoio.gitlab.io/cflare/)
|
||||
|
||||
## Status for master
|
||||
[](https://GitLab.com/mojoio/cflare/commits/master)
|
||||
[](https://GitLab.com/mojoio/cflare/commits/master)
|
||||
[](https://www.npmjs.com/package/cflare)
|
||||
[](https://david-dm.org/mojoio/cflare)
|
||||
[](https://www.bithound.io/github/mojoio/cflare/master/dependencies/npm)
|
||||
[](https://www.bithound.io/github/mojoio/cflare)
|
||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
||||
[](http://standardjs.com/)
|
||||
|
||||
## Usage
|
||||
Use TypeScript for best in class instellisense.
|
||||
|
||||
```javascript
|
||||
import * as cflare from 'cflare'
|
||||
|
||||
let myCflareAccount = new cflare.CflareAccount()
|
||||
testCflareAccount.auth({
|
||||
email: 'someuser@example.com',
|
||||
key: 'someLongApiKey'
|
||||
})
|
||||
|
||||
let myAsyncCflareManagement = async () => {
|
||||
// get things
|
||||
let myZones = await myCflareAccount.listZones() // zones are fully typed
|
||||
let myIdForADomain = await myCflareAccount.getZoneId('example.com') // type number
|
||||
let myRecordsForADomain = await myCflareAccount.listRecords('example.com') // records are fully typed
|
||||
|
||||
// set things
|
||||
myCflareAccount.updateRecord(...)
|
||||
myCflareAccount.createRecord(...)
|
||||
myCflareAccount.deleteRecord(...)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
For further information read the linked docs at the top of this README.
|
||||
|
||||
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
|
||||
|
||||
[](https://mojo.io)
|
219
changelog.md
Normal file
219
changelog.md
Normal file
@ -0,0 +1,219 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-03-19 - 6.0.6 - fix(core)
|
||||
Improve logging consistency, record update functionality, and API error handling in Cloudflare modules
|
||||
|
||||
- Replaced raw console.log calls with logger.log for unified logging across modules
|
||||
- Implemented and documented the updateRecord method with proper parameters in CloudflareAccount
|
||||
- Enhanced API request error handling and added detailed documentation in request methods
|
||||
- Refactored CloudflareWorker and WorkerManager methods to improve clarity and maintainability
|
||||
- Updated ZoneManager and CloudflareZone to improve error reporting and zone manipulation
|
||||
|
||||
## 2024-06-16 - 6.0.5 – no significant changes
|
||||
_No significant changes in this release._
|
||||
|
||||
## 2024-06-16 - 6.0.4 – miscellaneous
|
||||
Several improvements and fixes:
|
||||
- fix(start supporting workers again): update
|
||||
- update license info
|
||||
- update readme
|
||||
- switch to official cloudflare api client while keeping class based approach
|
||||
|
||||
## 2024-06-15 - 6.0.3 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2023-06-13 - 6.0.2 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2023-06-13 - 6.0.1 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2022-09-27 - 6.0.0 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2022-09-27 - 5.0.10 – core
|
||||
- BREAKING CHANGE(core): switch to esm
|
||||
|
||||
## 2022-09-27 - 5.0.9 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2021-01-22 - 5.0.8 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2021-01-22 - 5.0.7 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2021-01-22 - 5.0.6 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-06-10 - 5.0.5 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-06-10 - 5.0.4 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-28 - 5.0.3 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-28 - 5.0.2 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-28 - 5.0.1 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-28 - 5.0.0 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-19 - 4.0.5 – account
|
||||
- BREAKING CHANGE(account): authorization now uses the new Account API
|
||||
|
||||
## 2020-02-19 - 4.0.4 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-19 - 4.0.3 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-10 - 4.0.2 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-10 - 4.0.1 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-10 - 4.0.0 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-09 - 3.0.7 – API
|
||||
- BREAKING CHANGE(API): move to .convenience property
|
||||
|
||||
## 2020-02-09 - 3.0.6 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2020-02-09 - 3.0.5 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-19 - 3.0.4 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 3.0.3 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 3.0.2 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 3.0.1 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 3.0.0 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 2.0.1 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 2.0.0 – core
|
||||
- fix(core): update
|
||||
|
||||
## 2019-07-18 - 2.0.2 – no significant changes
|
||||
_No significant changes in this release._
|
||||
|
||||
## 2018-08-13 - 1.0.5 – scope
|
||||
- BREAKING CHANGE(scope): change scope, tools and package name
|
||||
|
||||
## 2017-06-11 - 1.0.4 – misc
|
||||
- now using tsclass
|
||||
|
||||
## 2017-06-09 - 1.0.3 – misc
|
||||
- update dependencies
|
||||
|
||||
## 2017-06-05 - 1.0.2 – misc
|
||||
- now supports purging of assets
|
||||
- improve test
|
||||
|
||||
## 2017-06-04 - 1.0.1 – misc
|
||||
- add npmextra.json
|
||||
|
||||
## 2017-06-04 - 1.0.0 – misc
|
||||
- add type TRecord, update ci
|
||||
|
||||
## 2017-06-04 - 0.0.20 – no significant changes
|
||||
_No significant changes in this release._
|
||||
|
||||
## 2017-06-04 - 0.0.19 – misc
|
||||
- go async/await
|
||||
- update brand link
|
||||
|
||||
## 2017-02-12 - 0.0.18 – misc
|
||||
- update README
|
||||
|
||||
## 2017-01-29 - 0.0.17 – misc
|
||||
- update README
|
||||
|
||||
## 2017-01-29 - 0.0.16 – misc
|
||||
- fix tests to run in parallel
|
||||
|
||||
## 2017-01-29 - 0.0.15 – misc
|
||||
- fixed bad request retry
|
||||
|
||||
## 2017-01-29 - 0.0.14 – misc
|
||||
- fix testing timeouts
|
||||
|
||||
## 2017-01-29 - 0.0.13 – misc
|
||||
- added random retry times
|
||||
|
||||
## 2017-01-29 - 0.0.12 – misc
|
||||
- update to new ci
|
||||
|
||||
## 2017-01-29 - 0.0.11 – misc
|
||||
- now using smartrequest
|
||||
|
||||
## 2017-01-22 - 0.0.10 – misc
|
||||
- now reacting to rate limiting
|
||||
|
||||
## 2016-07-31 - 0.0.9 – misc
|
||||
- update dependencies
|
||||
|
||||
## 2016-06-22 - 0.0.8 to 0.0.7 – no significant changes
|
||||
_No significant changes in these releases._
|
||||
|
||||
## 2016-06-22 - 0.0.6 – misc
|
||||
- updated dependencies
|
||||
|
||||
## 2016-06-21 - 0.0.5 – misc
|
||||
- fix stages
|
||||
|
||||
## 2016-06-21 - 0.0.4 – misc
|
||||
- fix stages
|
||||
|
||||
## 2016-06-21 - 0.0.3 – misc
|
||||
Multiple improvements:
|
||||
- now works for most things
|
||||
- update to latest dependencies
|
||||
- update .gitlab.yml
|
||||
- update
|
||||
- add .gitlab-ci.yml
|
||||
|
||||
## 2016-05-25 - 0.0.2 – misc
|
||||
Several changes:
|
||||
- improve domain string handling
|
||||
- update .getRecord
|
||||
- improve .createRecord
|
||||
- implemented .createRecord
|
||||
- compile
|
||||
- add functionality
|
||||
- start with tests
|
||||
- improved request method of cflare class
|
||||
|
||||
## 2016-04-27 - 0.0.1 – misc
|
||||
- now returning promises
|
||||
- add lossless badge
|
||||
|
||||
## 2016-04-27 - 0.0.0 – misc
|
||||
- added travis and improved README
|
||||
|
||||
## 2016-04-10 - 0.0.0 – misc
|
||||
- add package.json and README
|
||||
|
||||
## 2016-04-10 - unknown – misc
|
||||
- Initial commit
|
||||
|
||||
---
|
||||
_Note: Versions that only contained version bump commits or minor housekeeping (6.0.5; 2.0.2; 0.0.20; 0.0.8 to 0.0.7) have been omitted from detailed entries and are summarized above._
|
28
dist/cflare.classes.cflareaccount.d.ts
vendored
28
dist/cflare.classes.cflareaccount.d.ts
vendored
@ -1,28 +0,0 @@
|
||||
import 'typings-global';
|
||||
import * as interfaces from './cflare.interfaces';
|
||||
export declare class CflareAccount {
|
||||
private authEmail;
|
||||
private authKey;
|
||||
constructor();
|
||||
auth(optionsArg: {
|
||||
email: string;
|
||||
key: string;
|
||||
}): void;
|
||||
getZoneId(domainName: string): Promise<string>;
|
||||
getRecord(domainNameArg: string, typeArg: interfaces.TRecord): Promise<interfaces.ICflareRecord>;
|
||||
createRecord(domainNameArg: string, typeArg: interfaces.TRecord, contentArg: string): Promise<{}>;
|
||||
removeRecord(domainNameArg: string, typeArg: interfaces.TRecord): Promise<{}>;
|
||||
updateRecord(domainNameArg: string, typeArg: string, valueArg: any): Promise<{}>;
|
||||
/**
|
||||
* list all records of a specified domain name
|
||||
* @param domainNameArg - the domain name that you want to get the records from
|
||||
*/
|
||||
listRecords(domainNameArg: string): Promise<interfaces.ICflareRecord[]>;
|
||||
/**
|
||||
* list all zones in the associated authenticated account
|
||||
* @param domainName
|
||||
*/
|
||||
listZones(domainName?: string): Promise<interfaces.ICflareZone[]>;
|
||||
request(methodArg: string, routeArg: string, dataArg?: {}): Promise<{}>;
|
||||
private authCheck();
|
||||
}
|
164
dist/cflare.classes.cflareaccount.js
vendored
164
dist/cflare.classes.cflareaccount.js
vendored
File diff suppressed because one or more lines are too long
57
dist/cflare.interfaces.d.ts
vendored
57
dist/cflare.interfaces.d.ts
vendored
@ -1,57 +0,0 @@
|
||||
export declare type TRecord = 'A' | 'AAAA' | 'CNAME' | 'TXT' | 'SRV' | 'LOC' | 'MX' | 'NS' | 'SPF';
|
||||
export interface ICflareZone {
|
||||
'id': string;
|
||||
'name': string;
|
||||
'development_mode': number;
|
||||
'original_name_servers': string[];
|
||||
'original_registrar': string;
|
||||
'original_dnshost': string;
|
||||
'created_on': string;
|
||||
'modified_on': string;
|
||||
'name_servers': string[];
|
||||
'owner': {
|
||||
'id': string;
|
||||
'email': string;
|
||||
'owner_type': string;
|
||||
};
|
||||
'permissions': string[];
|
||||
'plan': {
|
||||
'id': string;
|
||||
'name': string;
|
||||
'price': number;
|
||||
'currency': string;
|
||||
'frequency': string;
|
||||
'legacy_id': string;
|
||||
'is_subscribed': boolean;
|
||||
'can_subscribe': boolean;
|
||||
};
|
||||
'plan_pending': {
|
||||
'id': string;
|
||||
'name': string;
|
||||
'price': number;
|
||||
'currency': string;
|
||||
'frequency': string;
|
||||
'legacy_id': string;
|
||||
'is_subscribed': string;
|
||||
'can_subscribe': string;
|
||||
};
|
||||
'status': string;
|
||||
'paused': boolean;
|
||||
'type': string;
|
||||
'checked_on': string;
|
||||
}
|
||||
export interface ICflareRecord {
|
||||
'id': string;
|
||||
'type': string;
|
||||
'name': string;
|
||||
'content': string;
|
||||
'proxiable': boolean;
|
||||
'proxied': boolean;
|
||||
'ttl': number;
|
||||
'locked': boolean;
|
||||
'zone_id': string;
|
||||
'zone_name': string;
|
||||
'created_on': string;
|
||||
'modified_on': string;
|
||||
'data': any;
|
||||
}
|
3
dist/cflare.interfaces.js
vendored
3
dist/cflare.interfaces.js
vendored
@ -1,3 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZsYXJlLmludGVyZmFjZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jZmxhcmUuaW50ZXJmYWNlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
|
6
dist/cflare.plugins.d.ts
vendored
6
dist/cflare.plugins.d.ts
vendored
@ -1,6 +0,0 @@
|
||||
import 'typings-global';
|
||||
export declare let beautylog: any;
|
||||
export import q = require('smartq');
|
||||
export import smartrequest = require('smartrequest');
|
||||
export import smartstring = require('smartstring');
|
||||
export import smartdelay = require('smartdelay');
|
9
dist/cflare.plugins.js
vendored
9
dist/cflare.plugins.js
vendored
@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
require("typings-global");
|
||||
exports.beautylog = require('beautylog');
|
||||
exports.q = require("smartq");
|
||||
exports.smartrequest = require("smartrequest");
|
||||
exports.smartstring = require("smartstring");
|
||||
exports.smartdelay = require("smartdelay");
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZsYXJlLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jZmxhcmUucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDBCQUF1QjtBQUNaLFFBQUEsU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQTtBQUMzQyw4QkFBbUM7QUFDbkMsK0NBQW9EO0FBQ3BELDZDQUFrRDtBQUNsRCwyQ0FBZ0QifQ==
|
2
dist/index.d.ts
vendored
2
dist/index.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
import "typings-global";
|
||||
export { CflareAccount } from "./cflare.classes.cflareaccount";
|
6
dist/index.js
vendored
6
dist/index.js
vendored
@ -1,6 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
require("typings-global");
|
||||
var cflare_classes_cflareaccount_1 = require("./cflare.classes.cflareaccount");
|
||||
exports.CflareAccount = cflare_classes_cflareaccount_1.CflareAccount;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDBCQUF3QjtBQUN4QiwrRUFBNkQ7QUFBckQsdURBQUEsYUFBYSxDQUFBIn0=
|
@ -1,6 +1,4 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Lossless GmbH
|
||||
Copyright (c) 2014 Task Venture Capital GmbH (hello@task.vc)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -18,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
@ -1,7 +1,29 @@
|
||||
{
|
||||
"npmci": {
|
||||
"globalNpmTools": [
|
||||
"npmts"
|
||||
]
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"gitzone": {
|
||||
"projectType": "npm",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"gitscope": "mojoio",
|
||||
"gitrepo": "cloudflare",
|
||||
"description": "A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.",
|
||||
"npmPackagename": "@apiclient.xyz/cloudflare",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"Cloudflare",
|
||||
"DNS management",
|
||||
"zone management",
|
||||
"worker management",
|
||||
"TypeScript",
|
||||
"API client",
|
||||
"cloud infrastructure",
|
||||
"automated DNS",
|
||||
"CDN management",
|
||||
"open source"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
68
package.json
68
package.json
@ -1,19 +1,32 @@
|
||||
{
|
||||
"name": "cflare",
|
||||
"version": "1.0.2",
|
||||
"description": "easy cloudflare management",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"name": "@apiclient.xyz/cloudflare",
|
||||
"version": "6.0.6",
|
||||
"private": false,
|
||||
"description": "A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.",
|
||||
"main": "dist_ts/index.js",
|
||||
"typings": "dist_ts/index.d.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "(npmts)"
|
||||
"test": "(tstest test/)",
|
||||
"build": "(tsbuild --web --allowimplicitany)",
|
||||
"buildDocs": "tsdoc",
|
||||
"updateOpenapi": "openapi-typescript https://raw.githubusercontent.com/cloudflare/api-schemas/main/openapi.yaml --output ts/openapi.spec.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://gitlab.com/pushrocks/cflare.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Push.Rocks",
|
||||
"cloudflare"
|
||||
"Cloudflare",
|
||||
"DNS management",
|
||||
"zone management",
|
||||
"worker management",
|
||||
"TypeScript",
|
||||
"API client",
|
||||
"cloud infrastructure",
|
||||
"automated DNS",
|
||||
"CDN management",
|
||||
"open source"
|
||||
],
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
@ -22,15 +35,36 @@
|
||||
},
|
||||
"homepage": "https://gitlab.com/pushrocks/cflare#readme",
|
||||
"dependencies": {
|
||||
"beautylog": "^6.1.1",
|
||||
"smartdelay": "^1.0.1",
|
||||
"smartq": "^1.1.0",
|
||||
"smartrequest": "^1.0.4",
|
||||
"smartstring": "^2.0.22",
|
||||
"typings-global": "^1.0.14"
|
||||
"@push.rocks/smartdelay": "^3.0.1",
|
||||
"@push.rocks/smartlog": "^3.0.2",
|
||||
"@push.rocks/smartpromise": "^4.0.2",
|
||||
"@push.rocks/smartrequest": "^2.0.15",
|
||||
"@push.rocks/smartstring": "^4.0.5",
|
||||
"@tsclass/tsclass": "^4.0.58",
|
||||
"cloudflare": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"qenv": "^1.1.3",
|
||||
"tapbundle": "^1.0.13"
|
||||
}
|
||||
"@git.zone/tsbuild": "^2.1.66",
|
||||
"@git.zone/tsrun": "^1.2.42",
|
||||
"@git.zone/tstest": "^1.0.74",
|
||||
"@push.rocks/qenv": "^6.0.5",
|
||||
"@push.rocks/tapbundle": "^5.0.4",
|
||||
"@types/node": "^20.3.1",
|
||||
"openapi-typescript": "^6.7.6"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"cli.js",
|
||||
"npmextra.json",
|
||||
"readme.md"
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
}
|
||||
|
6877
pnpm-lock.yaml
generated
Normal file
6877
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
1
readme.hints.md
Normal file
1
readme.hints.md
Normal file
@ -0,0 +1 @@
|
||||
- unofficial TypeScript cloudflare api client coming with a lot of convenience.
|
250
readme.md
Normal file
250
readme.md
Normal file
@ -0,0 +1,250 @@
|
||||
# @apiclient.xyz/cloudflare
|
||||
easy cloudflare management
|
||||
|
||||
## Install
|
||||
To install the `@apiclient.xyz/cloudflare` package, you can use npm. Simply run the following command:
|
||||
|
||||
```bash
|
||||
npm install @apiclient.xyz/cloudflare
|
||||
```
|
||||
|
||||
Make sure to include it in your `dependencies` in `package.json`.
|
||||
|
||||
## Usage
|
||||
|
||||
### Initial Setup
|
||||
|
||||
First, let's start by importing the required modules and setting up an instance of `CloudflareAccount` with your API token. This instance will be used to interact with the Cloudflare API.
|
||||
|
||||
```typescript
|
||||
import * as cflare from '@apiclient.xyz/cloudflare';
|
||||
|
||||
// Initialize Cloudflare Account
|
||||
const myCflareAccount = new cflare.CloudflareAccount('mySuperAwesomeAccountToken');
|
||||
```
|
||||
|
||||
### Managing Zones
|
||||
|
||||
#### List All Zones
|
||||
|
||||
To list all zones in your Cloudflare account, you can use the `listZones` method:
|
||||
|
||||
```typescript
|
||||
const listAllZones = async () => {
|
||||
const myZones = await myCflareAccount.convenience.listZones();
|
||||
console.log(myZones);
|
||||
};
|
||||
```
|
||||
|
||||
#### Get Zone ID
|
||||
|
||||
To get the ID of a specific zone (domain), use the `getZoneId` method:
|
||||
|
||||
```typescript
|
||||
const getZoneId = async (domainName: string) => {
|
||||
try {
|
||||
const zoneId = await myCflareAccount.convenience.getZoneId(domainName);
|
||||
console.log(`Zone ID for ${domainName}:`, zoneId);
|
||||
} catch (error) {
|
||||
console.error('Error getting zone ID:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Purge Cache for a Zone
|
||||
|
||||
To purge all cache for a specific zone:
|
||||
|
||||
```typescript
|
||||
const purgeZoneCache = async (domainName: string) => {
|
||||
await myCflareAccount.convenience.purgeZone(domainName);
|
||||
console.log(`Purged cache for ${domainName}`);
|
||||
};
|
||||
```
|
||||
|
||||
### Managing DNS Records
|
||||
|
||||
#### List DNS Records
|
||||
|
||||
To list all DNS records for a specific zone:
|
||||
|
||||
```typescript
|
||||
const listDnsRecords = async (domainName: string) => {
|
||||
try {
|
||||
const records = await myCflareAccount.convenience.listRecords(domainName);
|
||||
console.log(`DNS Records for ${domainName}:`, records);
|
||||
} catch (error) {
|
||||
console.error('Error listing DNS records:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Get a Specific Record
|
||||
|
||||
To get a specific DNS record by type (e.g., A, AAAA, CNAME, etc.):
|
||||
|
||||
```typescript
|
||||
const getDnsRecord = async (domainName: string, recordType: string) => {
|
||||
try {
|
||||
const record = await myCflareAccount.convenience.getRecord(domainName, recordType);
|
||||
console.log(`DNS Record (${recordType}) for ${domainName}:`, record);
|
||||
} catch (error) {
|
||||
console.error('Error getting DNS record:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Create a DNS Record
|
||||
|
||||
To create a new DNS record:
|
||||
|
||||
```typescript
|
||||
const createDnsRecord = async (domainName: string, recordType: string, content: string) => {
|
||||
try {
|
||||
const response = await myCflareAccount.convenience.createRecord(domainName, recordType, content, 120);
|
||||
console.log(`Created DNS record (${recordType}) for ${domainName}:`, response);
|
||||
} catch (error) {
|
||||
console.error('Error creating DNS record:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Remove a DNS Record
|
||||
|
||||
To remove a DNS record:
|
||||
|
||||
```typescript
|
||||
const removeDnsRecord = async (domainName: string, recordType: string) => {
|
||||
try {
|
||||
await myCflareAccount.convenience.removeRecord(domainName, recordType);
|
||||
console.log(`Removed DNS record (${recordType}) for ${domainName}`);
|
||||
} catch (error) {
|
||||
console.error('Error removing DNS record:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Clean a DNS Record
|
||||
|
||||
To clean (remove) all records of a specific type for a domain:
|
||||
|
||||
```typescript
|
||||
const cleanDnsRecord = async (domainName: string, recordType: string) => {
|
||||
try {
|
||||
await myCflareAccount.convenience.cleanRecord(domainName, recordType);
|
||||
console.log(`Cleaned DNS records (${recordType}) for ${domainName}`);
|
||||
} catch (error) {
|
||||
console.error('Error cleaning DNS record:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Managing Workers
|
||||
|
||||
#### Create a Worker
|
||||
|
||||
To create a new Cloudflare Worker:
|
||||
|
||||
```typescript
|
||||
const createWorker = async (workerName: string, workerScript: string) => {
|
||||
try {
|
||||
const worker = await myCflareAccount.workerManager.createWorker(workerName, workerScript);
|
||||
console.log(`Created Worker (${workerName}):`, worker);
|
||||
} catch (error) {
|
||||
console.error('Error creating Worker:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### List Workers
|
||||
|
||||
To list all workers in your Cloudflare account:
|
||||
|
||||
```typescript
|
||||
const listWorkers = async () => {
|
||||
try {
|
||||
const workers = await myCflareAccount.workerManager.listWorkers();
|
||||
console.log('Workers:', workers);
|
||||
} catch (error) {
|
||||
console.error('Error listing workers:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Set Worker Routes
|
||||
|
||||
To set routes for a Cloudflare Worker:
|
||||
|
||||
```typescript
|
||||
import { CloudflareWorker } from '@apiclient.xyz/cloudflare';
|
||||
|
||||
const setWorkerRoutes = async (worker: CloudflareWorker, routes: Array<{ zoneName: string, pattern: string }>) => {
|
||||
try {
|
||||
await worker.setRoutes(routes);
|
||||
console.log('Routes set successfully for Worker:', worker.id);
|
||||
} catch (error) {
|
||||
console.error('Error setting routes for Worker:', error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Sample Complete Workflow
|
||||
|
||||
Below is a sample workflow that includes all the above features:
|
||||
|
||||
```typescript
|
||||
import * as cflare from '@apiclient.xyz/cloudflare';
|
||||
|
||||
const myCflareAccount = new cflare.CloudflareAccount('mySuperAwesomeAccountToken');
|
||||
|
||||
const manageCloudflare = async () => {
|
||||
try {
|
||||
// List all zones
|
||||
const myZones = await myCflareAccount.convenience.listZones();
|
||||
console.log('Zones:', myZones);
|
||||
|
||||
// Get Zone ID for a specific domain
|
||||
const myZoneId = await myCflareAccount.convenience.getZoneId('example.com');
|
||||
console.log('Zone ID:', myZoneId);
|
||||
|
||||
// Purge cache for a zone
|
||||
await myCflareAccount.convenience.purgeZone('example.com');
|
||||
console.log('Cache purged for example.com');
|
||||
|
||||
// List DNS records for a domain
|
||||
const myRecords = await myCflareAccount.convenience.listRecords('example.com');
|
||||
console.log('DNS Records:', myRecords);
|
||||
|
||||
// Get a specific DNS record
|
||||
const myRecord = await myCflareAccount.convenience.getRecord('sub.example.com', 'A');
|
||||
console.log('Specific DNS Record:', myRecord);
|
||||
|
||||
// Create a DNS record
|
||||
const createResponse = await myCflareAccount.convenience.createRecord('sub.example.com', 'A', '127.0.0.1');
|
||||
console.log('Created DNS Record:', createResponse);
|
||||
|
||||
// Clean DNS records
|
||||
await myCflareAccount.convenience.cleanRecord('sub.example.com', 'A');
|
||||
console.log('Cleaned DNS Records for sub.example.com');
|
||||
|
||||
// Create a Cloudflare Worker
|
||||
const myWorker = await myCflareAccount.workerManager.createWorker('myWorker', `addEventListener('fetch', event => { event.respondWith(fetch(event.request)) })`);
|
||||
console.log('Created Worker:', myWorker);
|
||||
|
||||
// Set routes for the Worker
|
||||
await myWorker.setRoutes([{ zoneName: 'example.com', pattern: 'https://*example.com/*' }]);
|
||||
console.log('Routes set for Worker');
|
||||
|
||||
// List all Workers
|
||||
const workers = await myCflareAccount.workerManager.listWorkers();
|
||||
console.log('Workers:', workers);
|
||||
} catch (error) {
|
||||
console.error('Error managing Cloudflare:', error);
|
||||
}
|
||||
};
|
||||
|
||||
manageCloudflare();
|
||||
```
|
||||
|
||||
This complete guide covers initialization, managing Cloudflare zones, DNS records, and Cloudflare Workers comprehensively using TypeScript for enhanced type safety and intellisense. Always ensure to keep your API keys secure and avoid hardcoding them directly in your scripts.
|
||||
undefined
|
132
test/test.ts
132
test/test.ts
@ -1,54 +1,104 @@
|
||||
import { expect, tap } from 'tapbundle'
|
||||
import cflare = require('../dist/index')
|
||||
import { Qenv } from 'qenv'
|
||||
let testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit')
|
||||
console.log(testQenv.missingEnvVars)
|
||||
let testCflareAccount = new cflare.CflareAccount()
|
||||
testCflareAccount.auth({
|
||||
email: process.env.CF_EMAIL,
|
||||
key: process.env.CF_KEY
|
||||
})
|
||||
// tslint:disable-next-line: no-implicit-dependencies
|
||||
import { expect, tap } from '@push.rocks/tapbundle';
|
||||
// tslint:disable-next-line: no-implicit-dependencies
|
||||
import { Qenv } from '@push.rocks/qenv';
|
||||
|
||||
let randomPrefix = Math.floor(Math.random() * 2000)
|
||||
import * as cloudflare from '../ts/index.js';
|
||||
|
||||
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit');
|
||||
|
||||
const randomPrefix = Math.floor(Math.random() * 2000);
|
||||
let testCloudflareAccount: cloudflare.CloudflareAccount;
|
||||
|
||||
tap.test('should create a valid instance of CloudflareAccount', async () => {
|
||||
testCloudflareAccount = new cloudflare.CloudflareAccount(await testQenv.getEnvVarOnDemand('CF_KEY'));
|
||||
});
|
||||
|
||||
tap.test('should preselect an account', async () => {
|
||||
await testCloudflareAccount.preselectAccountByName('Sandbox Account');
|
||||
})
|
||||
|
||||
tap.test('.listZones() -> should display an entire account', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
let result = await testCflareAccount.listZones()
|
||||
console.log(result)
|
||||
})
|
||||
tools.timeout(600000);
|
||||
const result = await testCloudflareAccount.convenience.listZones();
|
||||
console.log(result);
|
||||
// await tools.delayFor(10000);
|
||||
});
|
||||
|
||||
tap.test('.getZoneId(domainName) -> should get an Cloudflare Id for a domain string', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
await testCflareAccount.getZoneId('bleu.de')
|
||||
})
|
||||
tap.test(
|
||||
'.getZoneId(domainName) -> should get an Cloudflare Id for a domain string',
|
||||
async (tools) => {
|
||||
tools.timeout(600000);
|
||||
const id = await testCloudflareAccount.convenience.getZoneId('bleu.de');
|
||||
console.log(`The account id for bleu.de is: ${id}`);
|
||||
}
|
||||
);
|
||||
|
||||
tap.test('.listRecords(domainName) -> should list all records for a specific Domain Name', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
await testCflareAccount.listRecords('bleu.de')
|
||||
.then(async (responseArg) => {
|
||||
console.log(responseArg)
|
||||
})
|
||||
})
|
||||
tap.test(
|
||||
'.listRecords(domainName) -> should list all records for a specific Domain Name',
|
||||
async (tools) => {
|
||||
tools.timeout(600000);
|
||||
await testCloudflareAccount.convenience.listRecords('bleu.de').then(async (responseArg) => {
|
||||
console.log(responseArg);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
tap.test('should create a valid record for a subdomain', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
await testCflareAccount.createRecord(`${randomPrefix}subdomain.bleu.de`, 'A', '127.0.0.1')
|
||||
})
|
||||
tools.timeout(600000);
|
||||
await testCloudflareAccount.convenience.createRecord(
|
||||
`${randomPrefix}subdomain.bleu.de`,
|
||||
'A',
|
||||
'127.0.0.1',
|
||||
120
|
||||
);
|
||||
});
|
||||
|
||||
tap.test('should get a record from Cloudflare', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
await testCflareAccount.getRecord('bleu.de', 'A')
|
||||
.then(function (responseArg) {
|
||||
console.log(responseArg)
|
||||
})
|
||||
})
|
||||
tools.timeout(600000);
|
||||
await testCloudflareAccount.convenience
|
||||
.getRecord(`${randomPrefix}subdomain.bleu.de`, 'A')
|
||||
.then((responseArg) => {
|
||||
console.log(responseArg);
|
||||
});
|
||||
});
|
||||
|
||||
tap.test('should remove a subdomain record from Cloudflare', async (tools) => {
|
||||
// tools.timeout(600000)
|
||||
await testCflareAccount.removeRecord(`${randomPrefix}subdomain.bleu.de`, 'A')
|
||||
tools.timeout(600000);
|
||||
await testCloudflareAccount.convenience
|
||||
.removeRecord(`${randomPrefix}subdomain.bleu.de`, 'A')
|
||||
.then(async (responseArg) => {
|
||||
console.log(responseArg)
|
||||
})
|
||||
})
|
||||
console.log(responseArg);
|
||||
});
|
||||
});
|
||||
|
||||
tap.start()
|
||||
tap.test('.purge(some.domain) -> should purge everything', async () => {
|
||||
await testCloudflareAccount.convenience.purgeZone('bleu.de');
|
||||
});
|
||||
|
||||
tap.test('should list workers', async () => {
|
||||
const workerArray = await testCloudflareAccount.workerManager.listWorkerScripts();
|
||||
console.log(workerArray);
|
||||
});
|
||||
|
||||
// WORKERS
|
||||
tap.test('should create a worker', async () => {
|
||||
const worker = await testCloudflareAccount.workerManager.createWorker(
|
||||
'myawesomescript',
|
||||
`addEventListener('fetch', event => { event.respondWith(fetch(event.request)) })`
|
||||
);
|
||||
await worker.setRoutes([
|
||||
{
|
||||
zoneName: 'bleu.de',
|
||||
pattern: 'https://*bleu.de/hello',
|
||||
},
|
||||
]);
|
||||
console.log(worker);
|
||||
});
|
||||
|
||||
tap.test('should get workers again', async () => {
|
||||
const workerArray = await testCloudflareAccount.workerManager.listWorkerScripts();
|
||||
console.log(workerArray);
|
||||
});
|
||||
|
||||
tap.start();
|
||||
|
8
ts/00_commitinfo_data.ts
Normal file
8
ts/00_commitinfo_data.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@apiclient.xyz/cloudflare',
|
||||
version: '6.0.6',
|
||||
description: 'A TypeScript client for managing Cloudflare accounts, zones, DNS records, and workers with ease.'
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
import 'typings-global'
|
||||
import plugins = require('./cflare.plugins')
|
||||
import * as interfaces from './cflare.interfaces'
|
||||
|
||||
export class CflareAccount {
|
||||
private authEmail: string
|
||||
private authKey: string
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
auth (optionsArg: { email: string, key: string }) {
|
||||
this.authEmail = optionsArg.email
|
||||
this.authKey = optionsArg.key
|
||||
}
|
||||
|
||||
async getZoneId (domainName: string) {
|
||||
let zoneArray = await this.listZones(domainName)
|
||||
let filteredResponse = zoneArray.filter((zoneArg) => {
|
||||
return zoneArg.name === domainName
|
||||
})
|
||||
if (filteredResponse.length >= 1) {
|
||||
return filteredResponse[ 0 ].id
|
||||
} else {
|
||||
plugins.beautylog.error(`the domain ${domainName} does not appear to be in this account!`)
|
||||
throw new Error(`the domain ${domainName} does not appear to be in this account!`)
|
||||
}
|
||||
|
||||
}
|
||||
getRecord (domainNameArg: string, typeArg: interfaces.TRecord): Promise<interfaces.ICflareRecord> {
|
||||
let done = plugins.q.defer()
|
||||
let result: interfaces.ICflareRecord
|
||||
|
||||
let domain = new plugins.smartstring.Domain(domainNameArg)
|
||||
this.listRecords(domain.zoneName)
|
||||
.then((recordArrayArg) => {
|
||||
let filteredResponse = recordArrayArg.filter((recordArg) => {
|
||||
return (recordArg.type === typeArg && recordArg.name === domainNameArg)
|
||||
})
|
||||
done.resolve(filteredResponse[ 0 ])
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
async createRecord (domainNameArg: string, typeArg: interfaces.TRecord, contentArg: string) {
|
||||
let done = plugins.q.defer()
|
||||
let domain = new plugins.smartstring.Domain(domainNameArg)
|
||||
let domainIdArg = await this.getZoneId(domain.zoneName)
|
||||
let dataObject = {
|
||||
name: domain.fullName,
|
||||
type: typeArg,
|
||||
content: contentArg
|
||||
}
|
||||
this.request('POST', '/zones/' + domainIdArg + '/dns_records', dataObject)
|
||||
.then(function (responseArg) {
|
||||
done.resolve(responseArg)
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
removeRecord (domainNameArg: string, typeArg: interfaces.TRecord) {
|
||||
let done = plugins.q.defer()
|
||||
let domain = new plugins.smartstring.Domain(domainNameArg)
|
||||
this.getRecord(domain.fullName, typeArg)
|
||||
.then((responseArg) => {
|
||||
if (responseArg) {
|
||||
let requestRoute: string = '/zones/' + responseArg.zone_id + '/dns_records/' + responseArg.id
|
||||
this.request('DELETE', requestRoute)
|
||||
.then((responseArg) => {
|
||||
done.resolve(responseArg)
|
||||
})
|
||||
} else {
|
||||
done.reject()
|
||||
}
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
updateRecord (domainNameArg: string, typeArg: string, valueArg) {
|
||||
let done = plugins.q.defer()
|
||||
let domain = new plugins.smartstring.Domain(domainNameArg)
|
||||
return done.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* list all records of a specified domain name
|
||||
* @param domainNameArg - the domain name that you want to get the records from
|
||||
*/
|
||||
async listRecords (domainNameArg: string): Promise<interfaces.ICflareRecord[]> {
|
||||
let domain = new plugins.smartstring.Domain(domainNameArg)
|
||||
let domainId = await this.getZoneId(domain.zoneName)
|
||||
let responseArg: any = await this.request('GET', '/zones/' + domainId + '/dns_records?per_page=100')
|
||||
let result: interfaces.ICflareRecord[] = responseArg.result
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* list all zones in the associated authenticated account
|
||||
* @param domainName
|
||||
*/
|
||||
async listZones (domainName?: string): Promise<interfaces.ICflareZone[]> { // TODO: handle pagination
|
||||
let requestRoute = '/zones?per_page=50'
|
||||
|
||||
// may be optionally filtered by domain name
|
||||
if (domainName) {
|
||||
requestRoute = requestRoute + '&name=' + domainName
|
||||
}
|
||||
|
||||
let response: any = await this.request('GET', requestRoute)
|
||||
let result = response.result
|
||||
return result
|
||||
}
|
||||
|
||||
request (methodArg: string, routeArg: string, dataArg = {}) {
|
||||
let done = plugins.q.defer()
|
||||
let jsonArg: string = JSON.stringify(dataArg)
|
||||
let options: plugins.smartrequest.ISmartRequestOptions = {
|
||||
method: methodArg,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Auth-Email': this.authEmail,
|
||||
'X-Auth-Key': this.authKey
|
||||
},
|
||||
requestBody: jsonArg
|
||||
}
|
||||
// console.log(options);
|
||||
let retryCount = 0
|
||||
|
||||
let makeRequest = async () => {
|
||||
let response: any = await plugins.smartrequest.request(
|
||||
`https://api.cloudflare.com/client/v4${routeArg}`,
|
||||
options
|
||||
)
|
||||
if (response.statusCode === 200) {
|
||||
done.resolve(response.body)
|
||||
} else if (response.statusCode === 429) {
|
||||
console.log('rate limited! Waiting for retry!')
|
||||
retryRequest()
|
||||
} else if (response.statusCode === 400) {
|
||||
console.log('bad request! Going to retry!')
|
||||
} else {
|
||||
console.log(response.statusCode)
|
||||
done.reject(new Error('request failed'))
|
||||
}
|
||||
}
|
||||
let retryRequest = async (delayTimeArg = Math.floor(Math.random() * (60000 - 8000) + 8000)) => {
|
||||
console.log(`retry started and waiting for ${delayTimeArg} ms`)
|
||||
await plugins.smartdelay.delayFor(delayTimeArg)
|
||||
if (retryCount < 10) {
|
||||
retryCount++
|
||||
return await makeRequest()
|
||||
}
|
||||
}
|
||||
makeRequest()
|
||||
return done.promise
|
||||
}
|
||||
|
||||
private authCheck () {
|
||||
return (this.authEmail && this.authKey) // check if auth is available
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
import * as plugins from './cflare.plugins'
|
||||
|
||||
export type TRecord = 'A' | 'AAAA' | 'CNAME' | 'TXT' | 'SRV' | 'LOC' | 'MX' | 'NS' | 'SPF'
|
||||
|
||||
export interface ICflareZone {
|
||||
'id': string
|
||||
'name': string
|
||||
'development_mode': number
|
||||
'original_name_servers': string[]
|
||||
'original_registrar': string
|
||||
'original_dnshost': string
|
||||
'created_on': string
|
||||
'modified_on': string
|
||||
'name_servers': string[]
|
||||
'owner': {
|
||||
'id': string
|
||||
'email': string
|
||||
'owner_type': string
|
||||
},
|
||||
'permissions': string[]
|
||||
'plan': {
|
||||
'id': string
|
||||
'name': string
|
||||
'price': number
|
||||
'currency': string
|
||||
'frequency': string
|
||||
'legacy_id': string
|
||||
'is_subscribed': boolean
|
||||
'can_subscribe': boolean
|
||||
},
|
||||
'plan_pending': {
|
||||
'id': string
|
||||
'name': string
|
||||
'price': number
|
||||
'currency': string
|
||||
'frequency': string
|
||||
'legacy_id': string
|
||||
'is_subscribed': string
|
||||
'can_subscribe': string
|
||||
},
|
||||
'status': string
|
||||
'paused': boolean
|
||||
'type': string
|
||||
'checked_on': string
|
||||
}
|
||||
|
||||
export interface ICflareRecord {
|
||||
'id': string
|
||||
'type': string
|
||||
'name': string
|
||||
'content': string
|
||||
'proxiable': boolean
|
||||
'proxied': boolean
|
||||
'ttl': number
|
||||
'locked': boolean
|
||||
'zone_id': string
|
||||
'zone_name': string
|
||||
'created_on': string
|
||||
'modified_on': string
|
||||
'data': any
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import 'typings-global'
|
||||
export let beautylog = require('beautylog')
|
||||
export import q = require('smartq')
|
||||
export import smartrequest = require('smartrequest')
|
||||
export import smartstring = require('smartstring')
|
||||
export import smartdelay = require('smartdelay')
|
267
ts/cloudflare.classes.account.ts
Normal file
267
ts/cloudflare.classes.account.ts
Normal file
@ -0,0 +1,267 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
|
||||
// interfaces
|
||||
import { WorkerManager } from './cloudflare.classes.workermanager.js';
|
||||
import { ZoneManager } from './cloudflare.classes.zonemanager.js';
|
||||
|
||||
export class CloudflareAccount {
|
||||
private authToken: string;
|
||||
public preselectedAccountId: string;
|
||||
|
||||
public workerManager = new WorkerManager(this);
|
||||
public zoneManager = new ZoneManager(this);
|
||||
|
||||
public apiAccount: plugins.cloudflare.Cloudflare;
|
||||
|
||||
/**
|
||||
* constructor sets auth information on the CloudflareAccountInstance
|
||||
* @param optionsArg
|
||||
*/
|
||||
constructor(authTokenArg: string) {
|
||||
this.authToken = authTokenArg;
|
||||
this.apiAccount = new plugins.cloudflare.Cloudflare({
|
||||
apiToken: this.authToken,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request to the Cloudflare API
|
||||
* @param method HTTP method (GET, POST, PUT, DELETE)
|
||||
* @param endpoint API endpoint path
|
||||
* @param data Optional request body data
|
||||
* @returns API response
|
||||
*/
|
||||
public async request<T = any>(
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
endpoint: string,
|
||||
data?: any
|
||||
): Promise<T> {
|
||||
try {
|
||||
const options: plugins.smartrequest.ISmartRequestOptions = {
|
||||
method,
|
||||
url: `https://api.cloudflare.com/client/v4${endpoint}`,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.authToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
if (data) {
|
||||
options.json = data;
|
||||
}
|
||||
|
||||
const response = await plugins.smartrequest.request(options);
|
||||
return JSON.parse(response.body);
|
||||
} catch (error) {
|
||||
logger.log('error', `Cloudflare API request failed: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async preselectAccountByName(nameArg: string) {
|
||||
const accounts = await this.convenience.listAccounts();
|
||||
const account = accounts.find((accountArg) => {
|
||||
return accountArg.name === nameArg;
|
||||
});
|
||||
if (account) {
|
||||
this.preselectedAccountId = account.id;
|
||||
} else {
|
||||
throw new Error(`account with name ${nameArg} not found`);
|
||||
}
|
||||
}
|
||||
|
||||
public convenience = {
|
||||
/**
|
||||
* listAccounts
|
||||
*/
|
||||
listAccounts: async () => {
|
||||
const accounts: plugins.ICloudflareTypes['Account'][] = [];
|
||||
for await (const account of this.apiAccount.accounts.list()) {
|
||||
accounts.push(account as interfaces.ICloudflareApiAccountObject);
|
||||
}
|
||||
return accounts;
|
||||
},
|
||||
/**
|
||||
* gets a zone id of a domain from cloudflare
|
||||
* @param domainName
|
||||
*/
|
||||
getZoneId: async (domainName: string) => {
|
||||
const domain = new plugins.smartstring.Domain(domainName);
|
||||
const zoneArray = await this.convenience.listZones(domain.zoneName);
|
||||
const filteredResponse = zoneArray.filter((zoneArg) => {
|
||||
return zoneArg.name === domainName;
|
||||
});
|
||||
if (filteredResponse.length >= 1) {
|
||||
return filteredResponse[0].id;
|
||||
} else {
|
||||
logger.log('error', `the domain ${domainName} does not appear to be in this account!`);
|
||||
throw new Error(`the domain ${domainName} does not appear to be in this account!`);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* gets a record
|
||||
* @param domainNameArg
|
||||
* @param typeArg
|
||||
*/
|
||||
getRecord: async (
|
||||
domainNameArg: string,
|
||||
typeArg: plugins.tsclass.network.TDnsRecordType
|
||||
): Promise<plugins.ICloudflareTypes['Record']> => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const recordArrayArg = await this.convenience.listRecords(domain.zoneName);
|
||||
const filteredResponse = recordArrayArg.filter((recordArg) => {
|
||||
return recordArg.type === typeArg && recordArg.name === domainNameArg;
|
||||
});
|
||||
return filteredResponse[0];
|
||||
},
|
||||
/**
|
||||
* creates a record
|
||||
*/
|
||||
createRecord: async (
|
||||
domainNameArg: string,
|
||||
typeArg: plugins.tsclass.network.TDnsRecordType,
|
||||
contentArg: string,
|
||||
ttlArg = 1
|
||||
): Promise<any> => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
const response = await this.apiAccount.dns.records.create({
|
||||
zone_id: zoneId,
|
||||
type: typeArg as any,
|
||||
name: domain.fullName,
|
||||
content: contentArg,
|
||||
ttl: ttlArg,
|
||||
})
|
||||
return response;
|
||||
},
|
||||
/**
|
||||
* removes a record from Cloudflare
|
||||
* @param domainNameArg
|
||||
* @param typeArg
|
||||
*/
|
||||
removeRecord: async (
|
||||
domainNameArg: string,
|
||||
typeArg: plugins.tsclass.network.TDnsRecordType
|
||||
): Promise<any> => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
const records = await this.convenience.listRecords(domain.zoneName);
|
||||
const recordToDelete = records.find((recordArg) => {
|
||||
return recordArg.name === domainNameArg && recordArg.type === typeArg;
|
||||
});
|
||||
if (recordToDelete) {
|
||||
await this.apiAccount.dns.records.delete(recordToDelete.id, {
|
||||
zone_id: zoneId,
|
||||
});
|
||||
} else {
|
||||
logger.log('warn', `record ${domainNameArg} of type ${typeArg} not found`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* cleanrecord allows the cleaning of any previous records to avoid unwanted sideeffects
|
||||
*/
|
||||
cleanRecord: async (domainNameArg: string, typeArg: plugins.tsclass.network.TDnsRecordType) => {
|
||||
logger.log('info', `Cleaning ${typeArg} records for ${domainNameArg}`);
|
||||
const records = await this.convenience.listRecords(domainNameArg);
|
||||
const recordsToDelete = records.filter((recordArg) => {
|
||||
return recordArg.type === typeArg;
|
||||
});
|
||||
for (const recordToDelete of recordsToDelete) {
|
||||
await this.apiAccount.dns.records.delete(recordToDelete.id, {
|
||||
zone_id: recordToDelete.zone_id,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* updates a record
|
||||
* @param domainNameArg Domain name for the record
|
||||
* @param typeArg Type of DNS record
|
||||
* @param contentArg New content for the record
|
||||
* @param ttlArg Time to live in seconds (optional)
|
||||
* @returns Updated record
|
||||
*/
|
||||
updateRecord: async (
|
||||
domainNameArg: string,
|
||||
typeArg: plugins.tsclass.network.TDnsRecordType,
|
||||
contentArg: string,
|
||||
ttlArg: number = 1
|
||||
): Promise<plugins.ICloudflareTypes['Record']> => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
|
||||
// Find existing record
|
||||
const record = await this.convenience.getRecord(domainNameArg, typeArg);
|
||||
|
||||
if (!record) {
|
||||
logger.log('warn', `Record ${domainNameArg} of type ${typeArg} not found for update, creating instead`);
|
||||
return this.convenience.createRecord(domainNameArg, typeArg, contentArg, ttlArg);
|
||||
}
|
||||
|
||||
// Update the record
|
||||
const updatedRecord = await this.apiAccount.dns.records.edit(record.id, {
|
||||
zone_id: zoneId,
|
||||
type: typeArg as any,
|
||||
name: domain.fullName,
|
||||
content: contentArg,
|
||||
ttl: ttlArg
|
||||
});
|
||||
|
||||
return updatedRecord;
|
||||
},
|
||||
/**
|
||||
* list all records of a specified domain name
|
||||
* @param domainNameArg - the domain name that you want to get the records from
|
||||
*/
|
||||
listRecords: async (domainNameArg: string) => {
|
||||
const domain = new plugins.smartstring.Domain(domainNameArg);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
const records: plugins.ICloudflareTypes['Record'][] = [];
|
||||
for await (const record of this.apiAccount.dns.records.list({
|
||||
zone_id: zoneId,
|
||||
})) {
|
||||
records.push(record);
|
||||
}
|
||||
return records;
|
||||
},
|
||||
/**
|
||||
* list all zones in the associated authenticated account
|
||||
* @param domainName
|
||||
*/
|
||||
listZones: async (domainName?: string) => {
|
||||
const zones: plugins.ICloudflareTypes['Zone'][] = [];
|
||||
for await (const zone of this.apiAccount.zones.list()) {
|
||||
zones.push(zone);
|
||||
}
|
||||
return zones;
|
||||
},
|
||||
/**
|
||||
* purges a zone
|
||||
*/
|
||||
purgeZone: async (domainName: string): Promise<void> => {
|
||||
const domain = new plugins.smartstring.Domain(domainName);
|
||||
const zoneId = await this.convenience.getZoneId(domain.zoneName);
|
||||
await this.apiAccount.cache.purge({
|
||||
zone_id: zoneId,
|
||||
purge_everything: true,
|
||||
});
|
||||
},
|
||||
|
||||
// acme convenience functions
|
||||
acmeSetDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => {
|
||||
await this.convenience.cleanRecord(dnsChallenge.hostName, 'TXT');
|
||||
await this.convenience.createRecord(
|
||||
dnsChallenge.hostName,
|
||||
'TXT',
|
||||
dnsChallenge.challenge,
|
||||
120
|
||||
);
|
||||
},
|
||||
acmeRemoveDnsChallenge: async (dnsChallenge: plugins.tsclass.network.IDnsChallenge) => {
|
||||
await this.convenience.removeRecord(dnsChallenge.hostName, 'TXT');
|
||||
},
|
||||
};
|
||||
}
|
96
ts/cloudflare.classes.record.ts
Normal file
96
ts/cloudflare.classes.record.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
|
||||
export interface ICloudflareRecordInfo {
|
||||
id: string;
|
||||
type: plugins.tsclass.network.TDnsRecordType;
|
||||
name: string;
|
||||
content: string;
|
||||
proxiable: boolean;
|
||||
proxied: boolean;
|
||||
ttl: number;
|
||||
locked: boolean;
|
||||
zone_id: string;
|
||||
zone_name: string;
|
||||
created_on: string;
|
||||
modified_on: string;
|
||||
}
|
||||
|
||||
export class CloudflareRecord {
|
||||
/**
|
||||
* Create a CloudflareRecord instance from an API object
|
||||
* @param apiObject Cloudflare DNS record API object
|
||||
* @returns CloudflareRecord instance
|
||||
*/
|
||||
public static createFromApiObject(apiObject: plugins.ICloudflareTypes['Record']): CloudflareRecord {
|
||||
const record = new CloudflareRecord();
|
||||
Object.assign(record, apiObject);
|
||||
return record;
|
||||
}
|
||||
|
||||
// Record properties
|
||||
public id: string;
|
||||
public type: plugins.tsclass.network.TDnsRecordType;
|
||||
public name: string;
|
||||
public content: string;
|
||||
public proxiable: boolean;
|
||||
public proxied: boolean;
|
||||
public ttl: number;
|
||||
public locked: boolean;
|
||||
public zone_id: string;
|
||||
public zone_name: string;
|
||||
public created_on: string;
|
||||
public modified_on: string;
|
||||
|
||||
/**
|
||||
* Update the record content
|
||||
* @param cloudflareAccount The Cloudflare account to use
|
||||
* @param newContent New content for the record
|
||||
* @param ttl Optional TTL value in seconds
|
||||
* @returns Updated record
|
||||
*/
|
||||
public async update(
|
||||
cloudflareAccount: any,
|
||||
newContent: string,
|
||||
ttl?: number
|
||||
): Promise<CloudflareRecord> {
|
||||
logger.log('info', `Updating record ${this.name} (${this.type}) with new content`);
|
||||
|
||||
const updatedRecord = await cloudflareAccount.apiAccount.dns.records.edit(this.id, {
|
||||
zone_id: this.zone_id,
|
||||
type: this.type as any,
|
||||
name: this.name,
|
||||
content: newContent,
|
||||
ttl: ttl || this.ttl,
|
||||
proxied: this.proxied
|
||||
});
|
||||
|
||||
// Update this instance
|
||||
this.content = newContent;
|
||||
if (ttl) {
|
||||
this.ttl = ttl;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this record
|
||||
* @param cloudflareAccount The Cloudflare account to use
|
||||
* @returns Boolean indicating success
|
||||
*/
|
||||
public async delete(cloudflareAccount: any): Promise<boolean> {
|
||||
try {
|
||||
logger.log('info', `Deleting record ${this.name} (${this.type})`);
|
||||
|
||||
await cloudflareAccount.apiAccount.dns.records.delete(this.id, {
|
||||
zone_id: this.zone_id
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to delete record: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
101
ts/cloudflare.classes.worker.ts
Normal file
101
ts/cloudflare.classes.worker.ts
Normal file
@ -0,0 +1,101 @@
|
||||
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) {
|
||||
const requestRoute = `/zones/${zone.id}/workers/routes`;
|
||||
const response: {
|
||||
result: interfaces.ICflareWorkerRoute[];
|
||||
} = await this.workerManager.cfAccount.request('GET', requestRoute);
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets routes for this worker
|
||||
* @param routeArray Array of route definitions
|
||||
*/
|
||||
public async setRoutes(routeArray: IWorkerRouteDefinition[]) {
|
||||
for (const newRoute of routeArray) {
|
||||
// lets determine wether a route is new, needs an update or 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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lets care about actually setting routes
|
||||
if (routeStatus === 'new') {
|
||||
const zoneId = await this.workerManager.cfAccount.convenience.getZoneId(newRoute.zoneName);
|
||||
const requestRoute = `/zones/${zoneId}/workers/routes`;
|
||||
await this.workerManager.cfAccount.request('POST', requestRoute, {
|
||||
pattern: newRoute.pattern,
|
||||
script: this.id,
|
||||
});
|
||||
} else if (routeStatus === 'needsUpdate') {
|
||||
const zoneId = await this.workerManager.cfAccount.convenience.getZoneId(newRoute.zoneName);
|
||||
const requestRoute = `/zones/${zoneId}/workers/routes/${routeIdForUpdate}`;
|
||||
await this.workerManager.cfAccount.request('PUT', requestRoute, {
|
||||
pattern: newRoute.pattern,
|
||||
script: this.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
ts/cloudflare.classes.workermanager.ts
Normal file
90
ts/cloudflare.classes.workermanager.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import { CloudflareAccount } from './cloudflare.classes.account.js';
|
||||
import { CloudflareWorker } from './cloudflare.classes.worker.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
|
||||
export class WorkerManager {
|
||||
public cfAccount: CloudflareAccount;
|
||||
|
||||
constructor(cfAccountArg: CloudflareAccount) {
|
||||
this.cfAccount = cfAccountArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new worker or updates an existing one
|
||||
* @param workerName Name of the worker
|
||||
* @param workerScript JavaScript content of the worker
|
||||
* @returns The created or updated worker
|
||||
*/
|
||||
public async createWorker(workerName: string, workerScript: string): Promise<plugins.ICloudflareTypes['Script']> {
|
||||
if (!this.cfAccount.preselectedAccountId) {
|
||||
throw new Error('No account selected. Please select it first on the account.');
|
||||
}
|
||||
const worker = await this.cfAccount.apiAccount.workers.scripts.content.update(workerName, {
|
||||
account_id: this.cfAccount.preselectedAccountId,
|
||||
"CF-WORKER-BODY-PART": workerScript,
|
||||
});
|
||||
return worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a worker by name
|
||||
* @param workerName Name of the worker to retrieve
|
||||
* @returns CloudflareWorker instance or undefined if not found
|
||||
*/
|
||||
public async getWorker(workerName: string): Promise<CloudflareWorker | undefined> {
|
||||
if (!this.cfAccount.preselectedAccountId) {
|
||||
throw new Error('No account selected. Please select it first on the account.');
|
||||
}
|
||||
|
||||
try {
|
||||
const script = await this.cfAccount.apiAccount.workers.scripts.get(workerName, {
|
||||
account_id: this.cfAccount.preselectedAccountId
|
||||
});
|
||||
|
||||
return CloudflareWorker.fromApiObject(this, script);
|
||||
} catch (error) {
|
||||
logger.log('warn', `Worker '${workerName}' not found: ${error.message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all worker scripts
|
||||
* @returns Array of worker scripts
|
||||
*/
|
||||
public async listWorkerScripts() {
|
||||
if (!this.cfAccount.preselectedAccountId) {
|
||||
throw new Error('No account selected. Please select it first on the account.');
|
||||
}
|
||||
const workerScripts: plugins.ICloudflareTypes['Script'][] = [];
|
||||
for await (const scriptArg of this.cfAccount.apiAccount.workers.scripts.list({
|
||||
account_id: this.cfAccount.preselectedAccountId,
|
||||
})) {
|
||||
workerScripts.push(scriptArg);
|
||||
}
|
||||
return workerScripts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a worker script
|
||||
* @param workerName Name of the worker to delete
|
||||
* @returns True if deletion was successful
|
||||
*/
|
||||
public async deleteWorker(workerName: string): Promise<boolean> {
|
||||
if (!this.cfAccount.preselectedAccountId) {
|
||||
throw new Error('No account selected. Please select it first on the account.');
|
||||
}
|
||||
|
||||
try {
|
||||
await this.cfAccount.apiAccount.workers.scripts.delete(workerName, {
|
||||
account_id: this.cfAccount.preselectedAccountId
|
||||
});
|
||||
logger.log('info', `Worker '${workerName}' deleted successfully`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to delete worker '${workerName}': ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
177
ts/cloudflare.classes.zone.ts
Normal file
177
ts/cloudflare.classes.zone.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
|
||||
export class CloudflareZone {
|
||||
// Zone properties
|
||||
public id: string;
|
||||
public name: string;
|
||||
public status: interfaces.ICflareZone['status'];
|
||||
public paused: boolean;
|
||||
public type: interfaces.ICflareZone['type'];
|
||||
public development_mode: number;
|
||||
public name_servers: string[];
|
||||
public original_name_servers: string[];
|
||||
public original_registrar: string | null;
|
||||
public original_dnshost: string | null;
|
||||
public modified_on: string;
|
||||
public created_on: string;
|
||||
public activated_on: string;
|
||||
public meta: interfaces.ICflareZone['meta'];
|
||||
public owner: interfaces.ICflareZone['owner'];
|
||||
public account: interfaces.ICflareZone['account'];
|
||||
public permissions: string[];
|
||||
public plan: interfaces.ICflareZone['plan'];
|
||||
|
||||
private cfAccount: any; // Will be set when created through a manager
|
||||
|
||||
/**
|
||||
* Create a CloudflareZone instance from an API object
|
||||
* @param apiObject Cloudflare Zone API object
|
||||
* @param cfAccount Optional Cloudflare account instance
|
||||
* @returns CloudflareZone instance
|
||||
*/
|
||||
public static createFromApiObject(
|
||||
apiObject: plugins.ICloudflareTypes['Zone'],
|
||||
cfAccount?: any
|
||||
): CloudflareZone {
|
||||
const cloudflareZone = new CloudflareZone();
|
||||
Object.assign(cloudflareZone, apiObject);
|
||||
|
||||
if (cfAccount) {
|
||||
cloudflareZone.cfAccount = cfAccount;
|
||||
}
|
||||
|
||||
return cloudflareZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if development mode is currently active
|
||||
* @returns True if development mode is active
|
||||
*/
|
||||
public isDevelopmentModeActive(): boolean {
|
||||
return this.development_mode > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable development mode for the zone
|
||||
* @param cfAccount Cloudflare account to use if not already set
|
||||
* @param duration Duration in seconds (default: 3 hours)
|
||||
* @returns Updated zone
|
||||
*/
|
||||
public async enableDevelopmentMode(
|
||||
cfAccount?: any,
|
||||
duration: number = 10800
|
||||
): Promise<CloudflareZone> {
|
||||
const account = cfAccount || this.cfAccount;
|
||||
if (!account) {
|
||||
throw new Error('CloudflareAccount is required to enable development mode');
|
||||
}
|
||||
|
||||
logger.log('info', `Enabling development mode for zone ${this.name}`);
|
||||
|
||||
const response = await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
|
||||
value: 'on',
|
||||
time: duration
|
||||
});
|
||||
|
||||
this.development_mode = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable development mode for the zone
|
||||
* @param cfAccount Cloudflare account to use if not already set
|
||||
* @returns Updated zone
|
||||
*/
|
||||
public async disableDevelopmentMode(cfAccount?: any): Promise<CloudflareZone> {
|
||||
const account = cfAccount || this.cfAccount;
|
||||
if (!account) {
|
||||
throw new Error('CloudflareAccount is required to disable development mode');
|
||||
}
|
||||
|
||||
logger.log('info', `Disabling development mode for zone ${this.name}`);
|
||||
|
||||
const response = await account.request('PATCH', `/zones/${this.id}/settings/development_mode`, {
|
||||
value: 'off'
|
||||
});
|
||||
|
||||
this.development_mode = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge all cached content for this zone
|
||||
* @param cfAccount Cloudflare account to use if not already set
|
||||
* @returns True if successful
|
||||
*/
|
||||
public async purgeCache(cfAccount?: any): Promise<boolean> {
|
||||
const account = cfAccount || this.cfAccount;
|
||||
if (!account) {
|
||||
throw new Error('CloudflareAccount is required to purge cache');
|
||||
}
|
||||
|
||||
logger.log('info', `Purging all cache for zone ${this.name}`);
|
||||
|
||||
try {
|
||||
await account.request('POST', `/zones/${this.id}/purge_cache`, {
|
||||
purge_everything: true
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to purge cache: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge specific URLs from the cache
|
||||
* @param urls Array of URLs to purge
|
||||
* @param cfAccount Cloudflare account to use if not already set
|
||||
* @returns True if successful
|
||||
*/
|
||||
public async purgeUrls(urls: string[], cfAccount?: any): Promise<boolean> {
|
||||
const account = cfAccount || this.cfAccount;
|
||||
if (!account) {
|
||||
throw new Error('CloudflareAccount is required to purge URLs');
|
||||
}
|
||||
|
||||
if (!urls.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.log('info', `Purging ${urls.length} URLs from cache for zone ${this.name}`);
|
||||
|
||||
try {
|
||||
await account.request('POST', `/zones/${this.id}/purge_cache`, {
|
||||
files: urls
|
||||
});
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to purge URLs: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the zone is active
|
||||
* @returns True if the zone is active
|
||||
*/
|
||||
public isActive(): boolean {
|
||||
return this.status === 'active' && !this.paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the zone is using Cloudflare nameservers
|
||||
* @returns True if using Cloudflare nameservers
|
||||
*/
|
||||
public isUsingCloudflareNameservers(): boolean {
|
||||
// Check if original nameservers match current nameservers
|
||||
if (!this.original_name_servers || !this.name_servers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If they're different, and current nameservers are Cloudflare's
|
||||
return this.name_servers.some(ns => ns.includes('cloudflare'));
|
||||
}
|
||||
}
|
153
ts/cloudflare.classes.zonemanager.ts
Normal file
153
ts/cloudflare.classes.zonemanager.ts
Normal file
@ -0,0 +1,153 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import { CloudflareAccount } from './cloudflare.classes.account.js';
|
||||
import { CloudflareZone } from './cloudflare.classes.zone.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
|
||||
export class ZoneManager {
|
||||
public cfAccount: CloudflareAccount;
|
||||
|
||||
constructor(cfAccountArg: CloudflareAccount) {
|
||||
this.cfAccount = cfAccountArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all zones, optionally filtered by name
|
||||
* @param zoneName Optional zone name to filter by
|
||||
* @returns Array of CloudflareZone instances
|
||||
*/
|
||||
public async getZones(zoneName?: string): Promise<CloudflareZone[]> {
|
||||
let requestRoute = `/zones?per_page=50`;
|
||||
|
||||
// May be optionally filtered by domain name
|
||||
if (zoneName) {
|
||||
requestRoute = `${requestRoute}&name=${encodeURIComponent(zoneName)}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const response: { result: interfaces.ICflareZone[] } = await this.cfAccount.request('GET', requestRoute);
|
||||
|
||||
return response.result.map(apiObject =>
|
||||
CloudflareZone.createFromApiObject(apiObject as any, this.cfAccount)
|
||||
);
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to fetch zones: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single zone by name
|
||||
* @param zoneName Zone name to find
|
||||
* @returns CloudflareZone instance or undefined if not found
|
||||
*/
|
||||
public async getZoneByName(zoneName: string): Promise<CloudflareZone | undefined> {
|
||||
const zones = await this.getZones(zoneName);
|
||||
return zones.find(zone => zone.name === zoneName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a zone by its ID
|
||||
* @param zoneId Zone ID to find
|
||||
* @returns CloudflareZone instance or undefined if not found
|
||||
*/
|
||||
public async getZoneById(zoneId: string): Promise<CloudflareZone | undefined> {
|
||||
try {
|
||||
const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
|
||||
'GET',
|
||||
`/zones/${zoneId}`
|
||||
);
|
||||
|
||||
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to fetch zone with ID ${zoneId}: ${error.message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new zone
|
||||
* @param zoneName Name of the zone to create
|
||||
* @param jumpStart Whether to automatically attempt to fetch existing DNS records
|
||||
* @param accountId Account ID to use (defaults to preselected account)
|
||||
* @returns The created zone
|
||||
*/
|
||||
public async createZone(
|
||||
zoneName: string,
|
||||
jumpStart: boolean = false,
|
||||
accountId?: string
|
||||
): Promise<CloudflareZone | undefined> {
|
||||
const useAccountId = accountId || this.cfAccount.preselectedAccountId;
|
||||
|
||||
if (!useAccountId) {
|
||||
throw new Error('No account selected. Please select it first on the account.');
|
||||
}
|
||||
|
||||
try {
|
||||
logger.log('info', `Creating zone ${zoneName}`);
|
||||
|
||||
const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
|
||||
'POST',
|
||||
'/zones',
|
||||
{
|
||||
name: zoneName,
|
||||
jump_start: jumpStart,
|
||||
account: { id: useAccountId }
|
||||
}
|
||||
);
|
||||
|
||||
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to create zone ${zoneName}: ${error.message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a zone
|
||||
* @param zoneId ID of the zone to delete
|
||||
* @returns True if successful
|
||||
*/
|
||||
public async deleteZone(zoneId: string): Promise<boolean> {
|
||||
try {
|
||||
logger.log('info', `Deleting zone with ID ${zoneId}`);
|
||||
|
||||
await this.cfAccount.request('DELETE', `/zones/${zoneId}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to delete zone with ID ${zoneId}: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a zone exists
|
||||
* @param zoneName Name of the zone to check
|
||||
* @returns True if the zone exists
|
||||
*/
|
||||
public async zoneExists(zoneName: string): Promise<boolean> {
|
||||
const zones = await this.getZones(zoneName);
|
||||
return zones.some(zone => zone.name === zoneName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a zone (if it's in pending status)
|
||||
* @param zoneId ID of the zone to activate
|
||||
* @returns Updated zone or undefined if activation failed
|
||||
*/
|
||||
public async activateZone(zoneId: string): Promise<CloudflareZone | undefined> {
|
||||
try {
|
||||
logger.log('info', `Activating zone with ID ${zoneId}`);
|
||||
|
||||
const response: { result: interfaces.ICflareZone } = await this.cfAccount.request(
|
||||
'PUT',
|
||||
`/zones/${zoneId}/activation_check`
|
||||
);
|
||||
|
||||
return CloudflareZone.createFromApiObject(response.result as any, this.cfAccount);
|
||||
} catch (error) {
|
||||
logger.log('error', `Failed to activate zone with ID ${zoneId}: ${error.message}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
3
ts/cloudflare.logger.ts
Normal file
3
ts/cloudflare.logger.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
|
||||
export const logger = new plugins.smartlog.ConsoleLog();
|
24
ts/cloudflare.plugins.ts
Normal file
24
ts/cloudflare.plugins.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import * as smartpromise from '@push.rocks/smartpromise';
|
||||
import * as smartdelay from '@push.rocks/smartdelay';
|
||||
import * as smartrequest from '@push.rocks/smartrequest';
|
||||
import * as smartstring from '@push.rocks/smartstring';
|
||||
import * as tsclass from '@tsclass/tsclass';
|
||||
|
||||
export { smartlog, smartpromise, smartdelay, smartrequest, smartstring, tsclass };
|
||||
|
||||
// third party
|
||||
import * as cloudflare from 'cloudflare';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import type { Zone } from 'cloudflare/resources/zones/zones.js';
|
||||
import type { Record } from 'cloudflare/resources/dns/records.js';
|
||||
import type { Script } from 'cloudflare/resources/workers/scripts/index.js';
|
||||
|
||||
export interface ICloudflareTypes {
|
||||
Account: interfaces.ICloudflareApiAccountObject;
|
||||
Record: Record;
|
||||
Zone: Zone;
|
||||
Script: Script;
|
||||
}
|
||||
|
||||
export { cloudflare };
|
130
ts/cloudflare.utils.ts
Normal file
130
ts/cloudflare.utils.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import * as plugins from './cloudflare.plugins.js';
|
||||
import { logger } from './cloudflare.logger.js';
|
||||
|
||||
export class CloudflareUtils {
|
||||
/**
|
||||
* Validates if a domain name is properly formatted
|
||||
* @param domainName Domain name to validate
|
||||
* @returns True if the domain is valid
|
||||
*/
|
||||
public static isValidDomain(domainName: string): boolean {
|
||||
try {
|
||||
const domain = new plugins.smartstring.Domain(domainName);
|
||||
return domain.isValid();
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the zone name (apex domain) from a full domain
|
||||
* @param domainName Domain name to process
|
||||
* @returns Zone name (apex domain)
|
||||
*/
|
||||
public static getZoneName(domainName: string): string {
|
||||
try {
|
||||
const domain = new plugins.smartstring.Domain(domainName);
|
||||
return domain.zoneName;
|
||||
} catch (error) {
|
||||
logger.log('error', `Invalid domain name: ${domainName}`);
|
||||
throw new Error(`Invalid domain name: ${domainName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string is a valid Cloudflare API token
|
||||
* @param token API token to validate
|
||||
* @returns True if the token format is valid
|
||||
*/
|
||||
public static isValidApiToken(token: string): boolean {
|
||||
// Cloudflare API tokens are typically 40+ characters long and start with specific patterns
|
||||
return /^[A-Za-z0-9_-]{40,}$/.test(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a DNS record type
|
||||
* @param type DNS record type to validate
|
||||
* @returns True if it's a valid DNS record type
|
||||
*/
|
||||
public static isValidRecordType(type: string): boolean {
|
||||
const validTypes: plugins.tsclass.network.TDnsRecordType[] = [
|
||||
'A', 'AAAA', 'CNAME', 'TXT', 'SRV', 'LOC', 'MX',
|
||||
'NS', 'SPF', 'CERT', 'DNSKEY', 'DS', 'NAPTR', 'SMIMEA',
|
||||
'SSHFP', 'TLSA', 'URI'
|
||||
];
|
||||
return validTypes.includes(type as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a URL for cache purging (ensures it starts with http/https)
|
||||
* @param url URL to format
|
||||
* @returns Properly formatted URL
|
||||
*/
|
||||
public static formatUrlForPurge(url: string): string {
|
||||
if (!url.startsWith('http://') && !url.startsWith('https://')) {
|
||||
return `https://${url}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a TTL value in seconds to a human-readable string
|
||||
* @param ttl TTL in seconds
|
||||
* @returns Human-readable TTL
|
||||
*/
|
||||
public static formatTtl(ttl: number): string {
|
||||
if (ttl === 1) {
|
||||
return 'Automatic';
|
||||
} else if (ttl === 120) {
|
||||
return '2 minutes';
|
||||
} else if (ttl === 300) {
|
||||
return '5 minutes';
|
||||
} else if (ttl === 600) {
|
||||
return '10 minutes';
|
||||
} else if (ttl === 900) {
|
||||
return '15 minutes';
|
||||
} else if (ttl === 1800) {
|
||||
return '30 minutes';
|
||||
} else if (ttl === 3600) {
|
||||
return '1 hour';
|
||||
} else if (ttl === 7200) {
|
||||
return '2 hours';
|
||||
} else if (ttl === 18000) {
|
||||
return '5 hours';
|
||||
} else if (ttl === 43200) {
|
||||
return '12 hours';
|
||||
} else if (ttl === 86400) {
|
||||
return '1 day';
|
||||
} else {
|
||||
return `${ttl} seconds`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely handles API pagination for Cloudflare requests
|
||||
* @param makeRequest Function that makes the API request with page parameters
|
||||
* @returns Combined results from all pages
|
||||
*/
|
||||
public static async paginateResults<T>(
|
||||
makeRequest: (page: number, perPage: number) => Promise<{ result: T[], result_info: { total_pages: number } }>
|
||||
): Promise<T[]> {
|
||||
const perPage = 50; // Cloudflare's maximum
|
||||
let page = 1;
|
||||
let totalPages = 1;
|
||||
const allResults: T[] = [];
|
||||
|
||||
do {
|
||||
try {
|
||||
const response = await makeRequest(page, perPage);
|
||||
allResults.push(...response.result);
|
||||
totalPages = response.result_info.total_pages;
|
||||
page++;
|
||||
} catch (error) {
|
||||
logger.log('error', `Pagination error on page ${page}: ${error.message}`);
|
||||
break;
|
||||
}
|
||||
} while (page <= totalPages);
|
||||
|
||||
return allResults;
|
||||
}
|
||||
}
|
13
ts/index.ts
13
ts/index.ts
@ -1,2 +1,11 @@
|
||||
import 'typings-global'
|
||||
export {CflareAccount} from "./cflare.classes.cflareaccount";
|
||||
export { CloudflareAccount } from './cloudflare.classes.account.js';
|
||||
export { CloudflareWorker, type IWorkerRoute, type IWorkerRouteDefinition } from './cloudflare.classes.worker.js';
|
||||
export { WorkerManager } from './cloudflare.classes.workermanager.js';
|
||||
export { CloudflareRecord, type ICloudflareRecordInfo } from './cloudflare.classes.record.js';
|
||||
export { CloudflareZone } from './cloudflare.classes.zone.js';
|
||||
export { ZoneManager } from './cloudflare.classes.zonemanager.js';
|
||||
export { CloudflareUtils } from './cloudflare.utils.js';
|
||||
export { commitinfo } from './00_commitinfo_data.js';
|
||||
|
||||
// Re-export interfaces
|
||||
export * from './interfaces/index.js';
|
20
ts/interfaces/cloudflare.api.account.ts
Normal file
20
ts/interfaces/cloudflare.api.account.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export interface ICloudflareApiAccountObject {
|
||||
id: string;
|
||||
name: string;
|
||||
type: 'standard' | 'enterprise' | 'pro' | 'free'; // Assuming other possible types
|
||||
settings: {
|
||||
enforce_twofactor: boolean;
|
||||
api_access_enabled: boolean | null;
|
||||
access_approval_expiry: string | null; // Assuming ISO date string or null
|
||||
use_account_custom_ns_by_default: boolean;
|
||||
default_nameservers: string;
|
||||
};
|
||||
legacy_flags: {
|
||||
enterprise_zone_quota: {
|
||||
maximum: number;
|
||||
current: number;
|
||||
available: number;
|
||||
};
|
||||
};
|
||||
created_on: string; // Assuming ISO date string
|
||||
}
|
5
ts/interfaces/cloudflare.api.workerroute.ts
Normal file
5
ts/interfaces/cloudflare.api.workerroute.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface ICflareWorkerRoute {
|
||||
id: string;
|
||||
pattern: string;
|
||||
script: string;
|
||||
}
|
45
ts/interfaces/cloudflare.api.zone.ts
Normal file
45
ts/interfaces/cloudflare.api.zone.ts
Normal file
@ -0,0 +1,45 @@
|
||||
export interface ICflareZone {
|
||||
id: string;
|
||||
name: string;
|
||||
status: 'active' | 'pending' | 'initializing' | 'moved' | 'deleted' | 'deactivated';
|
||||
paused: boolean;
|
||||
type: 'full' | 'partial' | 'secondary';
|
||||
development_mode: number;
|
||||
name_servers: string[];
|
||||
original_name_servers: string[];
|
||||
original_registrar: string | null;
|
||||
original_dnshost: string | null;
|
||||
modified_on: string;
|
||||
created_on: string;
|
||||
activated_on: string;
|
||||
meta: {
|
||||
step: number;
|
||||
wildcard_proxiable: boolean;
|
||||
custom_certificate_quota: number;
|
||||
page_rule_quota: number;
|
||||
phishing_detected: boolean;
|
||||
multiple_railguns_allowed: boolean;
|
||||
};
|
||||
owner: {
|
||||
id: string | null;
|
||||
type: 'user' | 'organization';
|
||||
email: string | null;
|
||||
};
|
||||
account: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
permissions: string[];
|
||||
plan: {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
currency: string;
|
||||
frequency: string;
|
||||
is_subscribed: boolean;
|
||||
can_subscribe: boolean;
|
||||
legacy_id: string;
|
||||
legacy_discount: boolean;
|
||||
externally_managed: boolean;
|
||||
};
|
||||
}
|
3
ts/interfaces/index.ts
Normal file
3
ts/interfaces/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './cloudflare.api.account.js';
|
||||
export * from './cloudflare.api.workerroute.js';
|
||||
export * from './cloudflare.api.zone.js';
|
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "tslint-config-standard"
|
||||
}
|
634
yarn.lock
634
yarn.lock
@ -1,634 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/chai-as-promised@0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-0.0.29.tgz#43d52892aa998e185a3de3e2477edb8573be1d77"
|
||||
dependencies:
|
||||
"@types/chai" "*"
|
||||
"@types/promises-a-plus" "*"
|
||||
|
||||
"@types/chai-string@^1.1.30":
|
||||
version "1.1.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/chai-string/-/chai-string-1.1.30.tgz#4d8744b31a5a2295fc01c981ed1e2d4c8a070f0a"
|
||||
dependencies:
|
||||
"@types/chai" "*"
|
||||
|
||||
"@types/chai@*", "@types/chai@^3.4.35":
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e"
|
||||
|
||||
"@types/fs-extra@3.x.x":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-3.0.3.tgz#1d66eb670ebf657e57c0fda014df340c19d8aa0c"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/lodash@^4.14.55":
|
||||
version "4.14.65"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.65.tgz#a0f78d71ffcd3c02628d5f616410c98c424326d5"
|
||||
|
||||
"@types/node@*":
|
||||
version "7.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.27.tgz#ba5e1a87aca2b4f5817289615ffe56472927687e"
|
||||
|
||||
"@types/promises-a-plus@*":
|
||||
version "0.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@types/promises-a-plus/-/promises-a-plus-0.0.27.tgz#c64651134614c84b8f5d7114ce8901d36a609780"
|
||||
|
||||
"@types/vinyl@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.0.tgz#fd213bf7f4136dde21fe1895500b12c186f8c268"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
ansi-256-colors@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-256-colors/-/ansi-256-colors-1.1.0.tgz#910de50efcc7c09e3d82f2f87abd6b700c18818a"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
|
||||
ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
|
||||
argparse@^1.0.7:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
assertion-error@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c"
|
||||
|
||||
balanced-match@^0.4.1:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
|
||||
|
||||
beautycolor@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/beautycolor/-/beautycolor-1.0.7.tgz#a4715738ac4c8221371e9cbeb5a6cc6d11ecbf7c"
|
||||
dependencies:
|
||||
ansi-256-colors "^1.1.0"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
beautylog@^6.1.1:
|
||||
version "6.1.10"
|
||||
resolved "https://registry.yarnpkg.com/beautylog/-/beautylog-6.1.10.tgz#9c27e566937684cb689f9372d98cfa5415d50b72"
|
||||
dependencies:
|
||||
"@types/lodash" "^4.14.55"
|
||||
beautycolor "^1.0.7"
|
||||
figlet "^1.2.0"
|
||||
lodash "^4.17.4"
|
||||
ora "^1.1.0"
|
||||
smartenv "^2.0.0"
|
||||
smartq "^1.1.1"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
bindings@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59"
|
||||
dependencies:
|
||||
balanced-match "^0.4.1"
|
||||
concat-map "0.0.1"
|
||||
|
||||
chai-as-promised@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6"
|
||||
dependencies:
|
||||
check-error "^1.0.2"
|
||||
|
||||
chai-string@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/chai-string/-/chai-string-1.3.0.tgz#df6139f294391b1035be5606f60a843b3a5041e7"
|
||||
|
||||
chai@^3.5.0:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247"
|
||||
dependencies:
|
||||
assertion-error "^1.0.1"
|
||||
deep-eql "^0.1.3"
|
||||
type-detect "^1.0.0"
|
||||
|
||||
chalk@^1.0.0, chalk@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
dependencies:
|
||||
ansi-styles "^2.2.1"
|
||||
escape-string-regexp "^1.0.2"
|
||||
has-ansi "^2.0.0"
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
check-error@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||
|
||||
cli-cursor@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
|
||||
dependencies:
|
||||
restore-cursor "^2.0.0"
|
||||
|
||||
cli-spinners@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.0.0.tgz#ef987ed3d48391ac3dab9180b406a742180d6e6a"
|
||||
|
||||
clone-buffer@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
|
||||
|
||||
clone-stats@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
|
||||
|
||||
clone@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
|
||||
|
||||
cloneable-readable@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117"
|
||||
dependencies:
|
||||
inherits "^2.0.1"
|
||||
process-nextick-args "^1.0.6"
|
||||
through2 "^2.0.1"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
deep-eql@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
|
||||
dependencies:
|
||||
type-detect "0.1.1"
|
||||
|
||||
early@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/early/-/early-2.1.1.tgz#841e23254ea5dc54d8afaeee82f5ab65c00ee23c"
|
||||
dependencies:
|
||||
beautycolor "^1.0.7"
|
||||
smartq "^1.1.1"
|
||||
typings-global "^1.0.16"
|
||||
|
||||
escape-string-regexp@^1.0.2:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
|
||||
esprima@^3.1.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
|
||||
|
||||
figlet@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.2.0.tgz#6c46537378fab649146b5a6143dda019b430b410"
|
||||
|
||||
first-chunk-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
|
||||
dependencies:
|
||||
readable-stream "^2.0.2"
|
||||
|
||||
fs-extra@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^3.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
|
||||
glob@^7.0.0, glob@^7.1.1:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
home@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/home/-/home-1.0.1.tgz#96a423ceb49b98378ff5ef3ceae059a557f9dd35"
|
||||
dependencies:
|
||||
os-homedir "^1.0.1"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.1, inherits@~2.0.1:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
interpret@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
|
||||
|
||||
is-stream@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
|
||||
|
||||
is-utf8@^0.2.0, is-utf8@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||
|
||||
isarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
|
||||
|
||||
js-base64@^2.1.9:
|
||||
version "2.1.9"
|
||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
|
||||
|
||||
js-yaml@^3.8.3:
|
||||
version "3.8.4"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^3.1.1"
|
||||
|
||||
jsonfile@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.0.tgz#92e7c7444e5ffd5fa32e6a9ae8b85034df8347d0"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
leakage@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/leakage/-/leakage-0.2.0.tgz#9e7a8cc1d241d8c8427e348769e192e172fd8733"
|
||||
dependencies:
|
||||
left-pad "^1.1.3"
|
||||
memwatch-next "^0.3.0"
|
||||
minimist "^1.2.0"
|
||||
pretty-bytes "^4.0.2"
|
||||
|
||||
left-pad@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.1.3.tgz#612f61c033f3a9e08e939f1caebeea41b6f3199a"
|
||||
|
||||
lodash@^4.17.4:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
log-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
|
||||
dependencies:
|
||||
chalk "^1.0.0"
|
||||
|
||||
memwatch-next@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/memwatch-next/-/memwatch-next-0.3.0.tgz#2111050f9a906e0aa2d72a4ec0f0089c78726f8f"
|
||||
dependencies:
|
||||
bindings "^1.2.1"
|
||||
nan "^2.3.2"
|
||||
|
||||
mimic-fn@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
nan@^2.3.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
onetime@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
|
||||
dependencies:
|
||||
mimic-fn "^1.0.0"
|
||||
|
||||
ora@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-1.2.0.tgz#32fb3183500efe83f5ea89101785f0ee6060fec9"
|
||||
dependencies:
|
||||
chalk "^1.1.1"
|
||||
cli-cursor "^2.1.0"
|
||||
cli-spinners "^1.0.0"
|
||||
log-symbols "^1.0.2"
|
||||
|
||||
os-homedir@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
path-parse@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
||||
|
||||
pify@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
|
||||
pretty-bytes@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
|
||||
|
||||
process-nextick-args@^1.0.6, process-nextick-args@~1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
|
||||
qenv@^1.1.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/qenv/-/qenv-1.1.7.tgz#d03f8bf8fe37494cf08d0919fe765dca84d9afae"
|
||||
dependencies:
|
||||
lodash "^4.17.4"
|
||||
smartfile "^4.2.11"
|
||||
typings-global "^1.0.16"
|
||||
|
||||
readable-stream@^2.0.2, readable-stream@^2.1.5:
|
||||
version "2.2.10"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.10.tgz#effe72bb7c884c0dd335e2379d526196d9d011ee"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~1.0.6"
|
||||
safe-buffer "^5.0.1"
|
||||
string_decoder "~1.0.0"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
rechoir@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
||||
dependencies:
|
||||
resolve "^1.1.6"
|
||||
|
||||
remove-trailing-separator@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4"
|
||||
|
||||
replace-ext@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
|
||||
|
||||
require-reload@0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/require-reload/-/require-reload-0.2.2.tgz#29a7591846caf91b6e8a3cda991683f95f8d7d42"
|
||||
|
||||
resolve@^1.1.6:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||
dependencies:
|
||||
onetime "^2.0.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
safe-buffer@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223"
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
|
||||
|
||||
shelljs@^0.7.7:
|
||||
version "0.7.7"
|
||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1"
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
signal-exit@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||
|
||||
smartchai@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/smartchai/-/smartchai-1.0.3.tgz#de6d010bb8b5aef24cb70b31a5f5334e8c41b72f"
|
||||
dependencies:
|
||||
"@types/chai" "^3.4.35"
|
||||
"@types/chai-as-promised" "0.0.29"
|
||||
"@types/chai-string" "^1.1.30"
|
||||
chai "^3.5.0"
|
||||
chai-as-promised "^6.0.0"
|
||||
chai-string "^1.3.0"
|
||||
|
||||
smartdelay@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/smartdelay/-/smartdelay-1.0.1.tgz#687f8bcc09d7c62c9c5a8a1771c1aba3aff54156"
|
||||
dependencies:
|
||||
typings-global "^1.0.14"
|
||||
|
||||
smartenv@^2.0.0:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/smartenv/-/smartenv-2.0.6.tgz#b38c679b0c151b9af548f68c3a072c29d1417e8d"
|
||||
dependencies:
|
||||
lodash "^4.17.4"
|
||||
smartq "^1.1.1"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
smartfile@^4.2.11:
|
||||
version "4.2.17"
|
||||
resolved "https://registry.yarnpkg.com/smartfile/-/smartfile-4.2.17.tgz#9eba8f65eea7e4db51aa30562f6039815a88b125"
|
||||
dependencies:
|
||||
"@types/fs-extra" "3.x.x"
|
||||
"@types/vinyl" "^2.0.0"
|
||||
fs-extra "^3.0.1"
|
||||
glob "^7.1.1"
|
||||
js-yaml "^3.8.3"
|
||||
require-reload "0.2.2"
|
||||
smartpath "^3.2.8"
|
||||
smartq "^1.1.1"
|
||||
smartrequest "^1.0.4"
|
||||
typings-global "^1.0.16"
|
||||
vinyl "^2.0.2"
|
||||
vinyl-file "^3.0.0"
|
||||
|
||||
smartpath@^3.2.8:
|
||||
version "3.2.8"
|
||||
resolved "https://registry.yarnpkg.com/smartpath/-/smartpath-3.2.8.tgz#4834bd3a8bae2295baacadba23c87a501952f940"
|
||||
dependencies:
|
||||
home "^1.0.1"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
smartq@^1.1.0, smartq@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/smartq/-/smartq-1.1.1.tgz#efb358705260d41ae18aef7ffd815f7b6fe17dd3"
|
||||
dependencies:
|
||||
typed-promisify "^0.3.0"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
smartrequest@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/smartrequest/-/smartrequest-1.0.4.tgz#86af2163ae28f1031b01c2d8ad8c429733920611"
|
||||
dependencies:
|
||||
smartq "^1.1.0"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
smartstring@^2.0.22:
|
||||
version "2.0.24"
|
||||
resolved "https://registry.yarnpkg.com/smartstring/-/smartstring-2.0.24.tgz#dc1c5efb738c10a2d7daeea3d800ad2ecc65a26c"
|
||||
dependencies:
|
||||
js-base64 "^2.1.9"
|
||||
typings-global "^1.0.14"
|
||||
|
||||
sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
||||
string_decoder@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98"
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
strip-ansi@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
strip-bom-buf@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
|
||||
dependencies:
|
||||
is-utf8 "^0.2.1"
|
||||
|
||||
strip-bom-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
|
||||
dependencies:
|
||||
first-chunk-stream "^2.0.0"
|
||||
strip-bom "^2.0.0"
|
||||
|
||||
strip-bom@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
|
||||
dependencies:
|
||||
is-utf8 "^0.2.0"
|
||||
|
||||
supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
|
||||
|
||||
tapbundle@^1.0.13:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/tapbundle/-/tapbundle-1.0.13.tgz#0b274aed6a386c0c01d8d517709381ce96e3971e"
|
||||
dependencies:
|
||||
early "^2.1.1"
|
||||
leakage "^0.2.0"
|
||||
smartchai "^1.0.3"
|
||||
smartdelay "^1.0.1"
|
||||
smartq "^1.1.1"
|
||||
typings-global "^1.0.16"
|
||||
|
||||
through2@^2.0.1:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
|
||||
dependencies:
|
||||
readable-stream "^2.1.5"
|
||||
xtend "~4.0.1"
|
||||
|
||||
type-detect@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
|
||||
|
||||
type-detect@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2"
|
||||
|
||||
typed-promisify@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/typed-promisify/-/typed-promisify-0.3.0.tgz#1ba0af5e444c87d8047406f18ce49092a1191853"
|
||||
|
||||
typings-global@^1.0.14, typings-global@^1.0.16:
|
||||
version "1.0.16"
|
||||
resolved "https://registry.yarnpkg.com/typings-global/-/typings-global-1.0.16.tgz#489b71781af24268750c2899316400a5e482961f"
|
||||
dependencies:
|
||||
semver "^5.3.0"
|
||||
shelljs "^0.7.7"
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.0.tgz#9eb1c4651debcc670cc94f1a75762332bb967778"
|
||||
|
||||
util-deprecate@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
||||
vinyl-file@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
pify "^2.3.0"
|
||||
strip-bom-buf "^1.0.0"
|
||||
strip-bom-stream "^2.0.0"
|
||||
vinyl "^2.0.1"
|
||||
|
||||
vinyl@^2.0.1, vinyl@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c"
|
||||
dependencies:
|
||||
clone "^1.0.0"
|
||||
clone-buffer "^1.0.0"
|
||||
clone-stats "^1.0.0"
|
||||
cloneable-readable "^1.0.0"
|
||||
is-stream "^1.1.0"
|
||||
remove-trailing-separator "^1.0.1"
|
||||
replace-ext "^1.0.0"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
xtend@~4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
Reference in New Issue
Block a user