@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.
@@ -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,5 @@
1
+ /**
2
+ * Path to the root directory where the stubs are stored. We use
3
+ * this path within commands and the configure hook
4
+ */
5
+ export declare const stubsRoot: string;
@@ -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
+ }