@ordius/adonisjs-currencyx 1.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +508 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +50 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +13 -0
- package/build/providers/currency_provider.d.ts +34 -0
- package/build/providers/currency_provider.js +46 -0
- package/build/services/main.d.ts +19 -0
- package/build/services/main.js +29 -0
- package/build/src/define_config.d.ts +31 -0
- package/build/src/define_config.js +56 -0
- package/build/src/exchanges/database.d.ts +54 -0
- package/build/src/exchanges/database.js +361 -0
- package/build/src/symbols.d.ts +5 -0
- package/build/src/symbols.js +5 -0
- package/build/src/types.d.ts +111 -0
- package/build/src/types.js +1 -0
- package/build/stubs/config/currency.stub +97 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/main.js +7 -0
- package/build/stubs/migrations/create_currencies_table.stub +41 -0
- package/build/stubs/models/currency.stub +111 -0
- package/package.json +146 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.configPath('currency.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import env from '#start/env'
|
|
5
|
+
import { defineConfig, exchanges } from '@ordius/adonisjs-currencyx'
|
|
6
|
+
|
|
7
|
+
const currencyConfig = defineConfig({
|
|
8
|
+
/*
|
|
9
|
+
|--------------------------------------------------------------------------
|
|
10
|
+
| Default Exchange
|
|
11
|
+
|--------------------------------------------------------------------------
|
|
12
|
+
|
|
|
13
|
+
| The default currency provider to use. You can switch between exchanges
|
|
14
|
+
| at runtime using the currency.use() method.
|
|
15
|
+
|
|
|
16
|
+
*/
|
|
17
|
+
default: env.get('CURRENCY_EXCHANGE_PROVIDER', 'database') as typeof currencyConfig,
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
|--------------------------------------------------------------------------
|
|
21
|
+
| Exchange Configurations
|
|
22
|
+
|--------------------------------------------------------------------------
|
|
23
|
+
|
|
|
24
|
+
| Configure each currency provider. You can enable/disable exchanges by
|
|
25
|
+
| commenting out their configuration.
|
|
26
|
+
|
|
|
27
|
+
*/
|
|
28
|
+
exchanges: {
|
|
29
|
+
/*
|
|
30
|
+
|--------------------------------------------------------------------------
|
|
31
|
+
| Database Exchange
|
|
32
|
+
|--------------------------------------------------------------------------
|
|
33
|
+
|
|
|
34
|
+
| Uses your local database to store and retrieve exchange rates.
|
|
35
|
+
| Requires a Currency model and proper database setup.
|
|
36
|
+
|
|
|
37
|
+
*/
|
|
38
|
+
database: exchanges.database({
|
|
39
|
+
model: () => import('#models/currency'),
|
|
40
|
+
base: 'USD', // Base currency for all exchange rates
|
|
41
|
+
columns: {
|
|
42
|
+
code: 'code', // Currency code column (USD, EUR, etc.)
|
|
43
|
+
rate: 'exchange_rate', // Exchange rate column (relative to base currency)
|
|
44
|
+
updated_at: 'updated_at', // Updated at column
|
|
45
|
+
},
|
|
46
|
+
cache: {
|
|
47
|
+
service: () => import('@adonisjs/cache/services/main'),
|
|
48
|
+
ttl: '1h', // Number of time to live in milliseconds, or a human-readable string
|
|
49
|
+
prefix: 'currency', // Cache key prefix
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
|--------------------------------------------------------------------------
|
|
55
|
+
| Google Finance Exchange
|
|
56
|
+
|--------------------------------------------------------------------------
|
|
57
|
+
|
|
|
58
|
+
| Free exchange using Google Finance API. No API key required.
|
|
59
|
+
| Good for development and testing.
|
|
60
|
+
|
|
|
61
|
+
*/
|
|
62
|
+
google: exchanges.google({
|
|
63
|
+
base: env.get('CURRENCY_BASE', 'USD'),
|
|
64
|
+
timeout: 5000,
|
|
65
|
+
}),
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
|--------------------------------------------------------------------------
|
|
69
|
+
| Fixer.io Exchange
|
|
70
|
+
|--------------------------------------------------------------------------
|
|
71
|
+
|
|
|
72
|
+
| Requires API key from fixer.io. Provides accurate and up-to-date
|
|
73
|
+
| exchange rates. Uncomment and configure if you have an API key.
|
|
74
|
+
|
|
|
75
|
+
*/
|
|
76
|
+
fixer: exchanges.fixer({
|
|
77
|
+
accessKey: env.get('FIXER_API_KEY', 'your_api_key'),
|
|
78
|
+
base: env.get('CURRENCY_BASE', 'EUR'),
|
|
79
|
+
timeout: 10000,
|
|
80
|
+
}),
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
export default currencyConfig
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
|--------------------------------------------------------------------------
|
|
88
|
+
| Type Augmentation
|
|
89
|
+
|--------------------------------------------------------------------------
|
|
90
|
+
|
|
|
91
|
+
| Augment the container types to include the currency service.
|
|
92
|
+
| This provides better IntelliSense and type safety.
|
|
93
|
+
|
|
|
94
|
+
*/
|
|
95
|
+
declare module '@ordius/adonisjs-currencyx/types' {
|
|
96
|
+
interface CurrencyExchanges extends InferExchanges<typeof currencyConfig> {}
|
|
97
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { dirname } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
/**
|
|
4
|
+
* Path to the root directory where the stubs are stored. We use
|
|
5
|
+
* this path within commands and the configure hook
|
|
6
|
+
*/
|
|
7
|
+
export const stubsRoot = dirname(fileURLToPath(import.meta.url));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{{#var migrationFileName = migration.fileName}}
|
|
2
|
+
{{{
|
|
3
|
+
exports({ to: app.migrationsPath(migrationFileName) })
|
|
4
|
+
}}}
|
|
5
|
+
import Currency from '#models/currency'
|
|
6
|
+
import { BaseSchema } from '@adonisjs/lucid/schema'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default class extends BaseSchema {
|
|
10
|
+
protected tableName = Currency.table
|
|
11
|
+
|
|
12
|
+
async up() {
|
|
13
|
+
this.schema.createTable(this.tableName, (table) => {
|
|
14
|
+
table.increments('id')
|
|
15
|
+
table.string('code', 3).notNullable().unique().comment('The currency code in ISO 4217. E.g., USD, EUR')
|
|
16
|
+
table.string('name').notNullable().comment('The currency name. E.g., US Dollar, Euro')
|
|
17
|
+
table.string('symbol').notNullable().comment('The currency symbol. E.g., $, €, £')
|
|
18
|
+
table.jsonb('countries').nullable().comment('The countries that support this currency')
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Exchange rate relative to base currency (e.g., USD)
|
|
22
|
+
* For USD itself, rate should be 1.0
|
|
23
|
+
*/
|
|
24
|
+
table.decimal('exchange_rate', 15, 8).notNullable().comment('The currency exchange rate with should be respect to USD')
|
|
25
|
+
|
|
26
|
+
table.boolean('status').defaultTo(true).comment('The status of the currency')
|
|
27
|
+
table.timestamp('created_at')
|
|
28
|
+
table.timestamp('updated_at')
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Indexes for better query performance
|
|
32
|
+
*/
|
|
33
|
+
table.index(['code'])
|
|
34
|
+
table.index(['status'])
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async down() {
|
|
39
|
+
this.schema.dropTable(this.tableName)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.modelPath('currency.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import { BaseModel, column } from '@adonisjs/lucid/orm'
|
|
5
|
+
import { DateTime } from 'luxon'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Currency model for storing exchange rates
|
|
9
|
+
*/
|
|
10
|
+
export default class Currency extends BaseModel {
|
|
11
|
+
public static table = 'currencies'
|
|
12
|
+
|
|
13
|
+
@column({ isPrimary: true })
|
|
14
|
+
declare id: number
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Currency code (e.g., USD, EUR, GBP)
|
|
18
|
+
*/
|
|
19
|
+
@column()
|
|
20
|
+
declare code: string
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Currency name (e.g., US Dollar, Euro)
|
|
24
|
+
*/
|
|
25
|
+
@column()
|
|
26
|
+
declare name: string
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Currency symbol (e.g., $, €, £)
|
|
30
|
+
*/
|
|
31
|
+
@column()
|
|
32
|
+
declare symbol: string
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Countries using this currency
|
|
36
|
+
*/
|
|
37
|
+
@column({
|
|
38
|
+
prepare: (value) => (typeof value === 'object' ? JSON.stringify(value) : value),
|
|
39
|
+
consume: (value) => (typeof value === 'string' ? JSON.parse(value) : value),
|
|
40
|
+
})
|
|
41
|
+
declare countries: string[]
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Exchange rate relative to base currency (e.g., USD)
|
|
45
|
+
* For the base currency itself (e.g., USD), this should be 1.0
|
|
46
|
+
*/
|
|
47
|
+
@column({
|
|
48
|
+
columnName: 'exchange_rate',
|
|
49
|
+
prepare: (value) => (typeof value === 'string' ? Number.parseFloat(value) : value),
|
|
50
|
+
consume: (value) => (typeof value === 'string' ? Number.parseFloat(value) : value),
|
|
51
|
+
})
|
|
52
|
+
declare exchangeRate: number
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Currency status (active/inactive)
|
|
56
|
+
*/
|
|
57
|
+
@column()
|
|
58
|
+
declare status: boolean
|
|
59
|
+
|
|
60
|
+
@column.dateTime({ autoCreate: true })
|
|
61
|
+
declare createdAt: DateTime
|
|
62
|
+
|
|
63
|
+
@column.dateTime({ autoCreate: true, autoUpdate: true })
|
|
64
|
+
declare updatedAt: DateTime
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get exchange rate for a specific currency pair
|
|
68
|
+
* Logic: assumes all rates are relative to a common base (e.g., USD)
|
|
69
|
+
*/
|
|
70
|
+
public static async getRate(from: string, to: string, baseCurrency: string = 'USD'): Promise<number | null> {
|
|
71
|
+
if (from === to) return 1
|
|
72
|
+
|
|
73
|
+
// Handle base currency conversions
|
|
74
|
+
if (from === baseCurrency && to === baseCurrency) return 1
|
|
75
|
+
|
|
76
|
+
if (from === baseCurrency) {
|
|
77
|
+
const toRate = await this.query().where('code', to).first()
|
|
78
|
+
return toRate ? toRate.exchangeRate : null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (to === baseCurrency) {
|
|
82
|
+
const fromRate = await this.query().where('code', from).first()
|
|
83
|
+
return fromRate ? 1 / fromRate.exchangeRate : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Cross rate conversion
|
|
87
|
+
const fromRate = await this.query().where('code', from).first()
|
|
88
|
+
const toRate = await this.query().where('code', to).first()
|
|
89
|
+
|
|
90
|
+
if (!fromRate || !toRate) {
|
|
91
|
+
return null
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Calculate cross rate: to_rate / from_rate
|
|
95
|
+
return toRate.exchangeRate / fromRate.exchangeRate
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get all available exchange rates
|
|
100
|
+
*/
|
|
101
|
+
public static async getAllRates() {
|
|
102
|
+
const rates = await this.query().where('status', true)
|
|
103
|
+
|
|
104
|
+
const result: Record<string, number> = {}
|
|
105
|
+
for (const rate of rates) {
|
|
106
|
+
result[rate.code] = rate.exchangeRate
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ordius/adonisjs-currencyx",
|
|
3
|
+
"description": "AdonisJS integration for CurrencyX with database exchange provider and cache support",
|
|
4
|
+
"version": "1.4.9",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20.6.0"
|
|
7
|
+
},
|
|
8
|
+
"main": "build/index.js",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"build",
|
|
12
|
+
"!build/bin",
|
|
13
|
+
"!build/tests"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./build/index.js",
|
|
17
|
+
"./types": "./build/src/types.js",
|
|
18
|
+
"./services/main": "./build/services/main.js",
|
|
19
|
+
"./currency_provider": "./build/providers/currency_provider.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "del-cli build",
|
|
23
|
+
"copy:templates": "copyfiles \"stubs/**/*.stub\" build",
|
|
24
|
+
"typecheck": "tsc --noEmit",
|
|
25
|
+
"lint": "eslint .",
|
|
26
|
+
"format": "prettier --write .",
|
|
27
|
+
"quick:test": "node --import=./tsnode.esm.js --enable-source-maps bin/test.ts",
|
|
28
|
+
"pretest": "npm run lint",
|
|
29
|
+
"test": "c8 npm run quick:test",
|
|
30
|
+
"prebuild": "npm run lint && npm run clean",
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"postbuild": "npm run copy:templates",
|
|
33
|
+
"release": "release-it",
|
|
34
|
+
"release:patch": "release-it patch",
|
|
35
|
+
"release:minor": "release-it minor",
|
|
36
|
+
"release:major": "release-it major",
|
|
37
|
+
"release:beta": "release-it --preRelease=beta",
|
|
38
|
+
"release:alpha": "release-it --preRelease=alpha",
|
|
39
|
+
"release:dry": "release-it --dry-run",
|
|
40
|
+
"version": "npm run build",
|
|
41
|
+
"prepublishOnly": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"adonisjs",
|
|
45
|
+
"currency",
|
|
46
|
+
"converter",
|
|
47
|
+
"exchange-rates",
|
|
48
|
+
"typescript",
|
|
49
|
+
"database",
|
|
50
|
+
"lucid",
|
|
51
|
+
"cache"
|
|
52
|
+
],
|
|
53
|
+
"author": "Mixxtor",
|
|
54
|
+
"license": "MIT",
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@adonisjs/assembler": "^7.8.2",
|
|
57
|
+
"@adonisjs/cache": "^1.3.1",
|
|
58
|
+
"@adonisjs/core": "^6.21.0",
|
|
59
|
+
"@adonisjs/eslint-config": "^3.0.0",
|
|
60
|
+
"@adonisjs/lucid": "^21.8.1",
|
|
61
|
+
"@adonisjs/prettier-config": "^1.4.5",
|
|
62
|
+
"@adonisjs/tsconfig": "^1.4.1",
|
|
63
|
+
"@japa/assert": "^4.2.0",
|
|
64
|
+
"@japa/runner": "^5.3.0",
|
|
65
|
+
"@release-it/conventional-changelog": "^10.0.6",
|
|
66
|
+
"@swc/core": "^1.15.21",
|
|
67
|
+
"@types/node": "^25.5.0",
|
|
68
|
+
"better-sqlite3": "^12.8.0",
|
|
69
|
+
"c8": "^11.0.0",
|
|
70
|
+
"copyfiles": "^2.4.1",
|
|
71
|
+
"cross-env": "^10.1.0",
|
|
72
|
+
"del-cli": "^7.0.0",
|
|
73
|
+
"dotenv": "^17.3.1",
|
|
74
|
+
"eslint": "^10.1.0",
|
|
75
|
+
"luxon": "^3.7.2",
|
|
76
|
+
"prettier": "^3.8.1",
|
|
77
|
+
"release-it": "^19.2.4",
|
|
78
|
+
"ts-node": "^10.9.2",
|
|
79
|
+
"tsup": "^8.5.1",
|
|
80
|
+
"typescript": "^5.9.3"
|
|
81
|
+
},
|
|
82
|
+
"peerDependencies": {
|
|
83
|
+
"@adonisjs/cache": "^1.3.1 || ^2.0.1",
|
|
84
|
+
"@adonisjs/core": "^6.21.0 || ^7.2.0",
|
|
85
|
+
"@adonisjs/lucid": "^21.8.1 || ^22.4.0"
|
|
86
|
+
},
|
|
87
|
+
"dependencies": {
|
|
88
|
+
"@mixxtor/currencyx-js": "^2.3.0"
|
|
89
|
+
},
|
|
90
|
+
"peerDependenciesMeta": {
|
|
91
|
+
"@adonisjs/cache": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"homepage": "https://github.com/ordius/adonisjs-currencyx#readme",
|
|
96
|
+
"repository": {
|
|
97
|
+
"type": "git",
|
|
98
|
+
"url": "git+https://github.com/ordius/adonisjs-currencyx.git"
|
|
99
|
+
},
|
|
100
|
+
"bugs": {
|
|
101
|
+
"url": "https://github.com/ordius/adonisjs-currencyx/issues"
|
|
102
|
+
},
|
|
103
|
+
"publishConfig": {
|
|
104
|
+
"access": "public",
|
|
105
|
+
"tag": "latest"
|
|
106
|
+
},
|
|
107
|
+
"release-it": {
|
|
108
|
+
"git": {
|
|
109
|
+
"requireCleanWorkingDir": true,
|
|
110
|
+
"requireUpstream": true,
|
|
111
|
+
"commitMessage": "chore(release): ${version}",
|
|
112
|
+
"tagAnnotation": "v${version}",
|
|
113
|
+
"push": true,
|
|
114
|
+
"tagName": "v${version}"
|
|
115
|
+
},
|
|
116
|
+
"github": {
|
|
117
|
+
"release": true,
|
|
118
|
+
"releaseName": "Release v${version}",
|
|
119
|
+
"releaseNotes": null,
|
|
120
|
+
"autoGenerate": true,
|
|
121
|
+
"draft": false,
|
|
122
|
+
"preRelease": false
|
|
123
|
+
},
|
|
124
|
+
"npm": {
|
|
125
|
+
"publish": true,
|
|
126
|
+
"skipChecks": true
|
|
127
|
+
},
|
|
128
|
+
"plugins": {
|
|
129
|
+
"@release-it/conventional-changelog": {
|
|
130
|
+
"preset": {
|
|
131
|
+
"name": "angular"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"c8": {
|
|
137
|
+
"reporter": [
|
|
138
|
+
"text",
|
|
139
|
+
"html"
|
|
140
|
+
],
|
|
141
|
+
"exclude": [
|
|
142
|
+
"tests/**"
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"prettier": "@adonisjs/prettier-config"
|
|
146
|
+
}
|