@run-iq/plugin-fiscal 0.1.0

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 ADDED
@@ -0,0 +1,60 @@
1
+ Run-IQ Source-Available License v1.0
2
+
3
+ Copyright (c) 2025 Abdou-Raouf ATARMLA. All rights reserved.
4
+
5
+
6
+ 1. DEFINITIONS
7
+
8
+ "Software" means the source code, object code, documentation, and any
9
+ associated files distributed under this license.
10
+
11
+ "Commercial Use" means any use of the Software intended for or directed toward
12
+ commercial advantage or monetary compensation, including but not limited to:
13
+ (a) incorporating the Software into a product or service sold to third parties;
14
+ (b) using the Software to provide paid consulting, managed, or SaaS services;
15
+ (c) using the Software in internal business operations that generate revenue.
16
+
17
+ "Non-Commercial Use" means personal use, academic research, educational
18
+ purposes, and evaluation, provided no Commercial Use is involved.
19
+
20
+
21
+ 2. GRANT — NON-COMMERCIAL USE
22
+
23
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
24
+ the Software, to use, copy, modify, and distribute the Software solely for
25
+ Non-Commercial Use, subject to the following conditions:
26
+
27
+ (a) The above copyright notice and this license shall be included in all
28
+ copies or substantial portions of the Software.
29
+ (b) Modified versions must be clearly marked as such and must not be
30
+ misrepresented as the original Software.
31
+
32
+
33
+ 3. COMMERCIAL USE — LICENSE REQUIRED
34
+
35
+ Any Commercial Use of the Software requires a separate commercial license
36
+ agreement with the copyright holder. To obtain a commercial license, contact:
37
+
38
+ Abdou-Raouf ATARMLA
39
+ contact@run-iq.org
40
+
41
+
42
+ 4. RESTRICTIONS
43
+
44
+ You may not:
45
+ (a) remove or alter any copyright, trademark, or attribution notices;
46
+ (b) sublicense, sell, or redistribute the Software for Commercial Use
47
+ without a commercial license;
48
+ (c) use the name "Run-IQ" or the copyright holder's name to endorse or
49
+ promote products derived from the Software without prior written consent.
50
+
51
+
52
+ 5. NO WARRANTY
53
+
54
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # @run-iq/plugin-fiscal
2
+
3
+ Fiscal domain plugin for the PPE engine — provides tax calculation models, jurisdiction resolution, and fiscal rule validation.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @run-iq/plugin-fiscal
9
+ ```
10
+
11
+ **Peer dependencies:** `@run-iq/core >= 0.1.0`, `@run-iq/plugin-sdk >= 0.1.0`
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { PPEEngine } from '@run-iq/core';
17
+ import { JsonLogicEvaluator } from '@run-iq/dsl-jsonlogic';
18
+ import { FiscalPlugin } from '@run-iq/plugin-fiscal';
19
+
20
+ const engine = new PPEEngine({
21
+ plugins: [new FiscalPlugin()],
22
+ dsls: [new JsonLogicEvaluator()],
23
+ strict: true,
24
+ });
25
+
26
+ const result = await engine.evaluate(rules, {
27
+ requestId: 'calc-001',
28
+ data: { grossSalary: 2_500_000, country: 'TG' },
29
+ meta: { tenantId: 'tenant-1' },
30
+ });
31
+ ```
32
+
33
+ ## Calculation models
34
+
35
+ | Model | Key | Description |
36
+ |---|---|---|
37
+ | `FlatRateModel` | `FLAT_RATE` | `base x rate` |
38
+ | `ProgressiveBracketModel` | `PROGRESSIVE_BRACKET` | Cumulative tax brackets |
39
+ | `MinimumTaxModel` | `MINIMUM_TAX` | `max(base x rate, minimum)` |
40
+ | `ThresholdModel` | `THRESHOLD` | Applies above a threshold value |
41
+ | `FixedAmountModel` | `FIXED_AMOUNT` | Fixed amount regardless of input |
42
+ | `CompositeModel` | `COMPOSITE` | Aggregates sub-models via `SUM`, `MAX`, or `MIN` |
43
+
44
+ All models use `decimal.js` for arithmetic — no floating-point drift.
45
+
46
+ ## Jurisdiction resolution
47
+
48
+ `JurisdictionResolver` scores rules by jurisdiction level, `ScopeResolver` by scope:
49
+
50
+ | Jurisdiction | Base score |
51
+ |---|---|
52
+ | `NATIONAL` | 3000 |
53
+ | `REGIONAL` | 2000 |
54
+ | `MUNICIPAL` | 1000 |
55
+
56
+ | Scope | Multiplier |
57
+ |---|---|
58
+ | `GLOBAL` | x1.0 |
59
+ | `ORGANIZATION` | x1.1 |
60
+ | `USER` | x1.2 |
61
+
62
+ Higher score wins. Example: `NATIONAL + ORGANIZATION` (3300) beats `NATIONAL + GLOBAL` (3000).
63
+
64
+ ## Plugin hooks
65
+
66
+ `FiscalPlugin` implements:
67
+
68
+ - **`beforeEvaluate`** — filters rules by jurisdiction and country
69
+ - **`afterEvaluate`** — enriches result with `fiscalBreakdown` grouped by tax category
70
+
71
+ ## Exports
72
+
73
+ ```typescript
74
+ // Plugin
75
+ FiscalPlugin
76
+
77
+ // Models
78
+ FlatRateModel, ProgressiveBracketModel, MinimumTaxModel,
79
+ ThresholdModel, FixedAmountModel, CompositeModel
80
+
81
+ // Jurisdiction
82
+ JurisdictionResolver, ScopeResolver
83
+
84
+ // Validators
85
+ FiscalRuleValidator, ParamsValidator
86
+
87
+ // Types
88
+ FiscalRule, FiscalScope, FiscalJurisdiction,
89
+ FiscalCalculationModel, FlatRateParams, BracketParams,
90
+ MinimumTaxParams, ThresholdParams, FixedAmountParams, CompositeParams
91
+ ```
92
+
93
+ ## Requirements
94
+
95
+ - Node.js >= 20
96
+ - `@run-iq/core` >= 0.1.0
97
+ - `@run-iq/plugin-sdk` >= 0.1.0
98
+
99
+ ## License
100
+
101
+ Source-Available — commercial use requires a paid license. See [LICENSE](./LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,376 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ CompositeModel: () => CompositeModel,
34
+ FiscalPlugin: () => FiscalPlugin,
35
+ FiscalRuleValidator: () => FiscalRuleValidator,
36
+ FixedAmountModel: () => FixedAmountModel,
37
+ FlatRateModel: () => FlatRateModel,
38
+ JurisdictionResolver: () => JurisdictionResolver,
39
+ MinimumTaxModel: () => MinimumTaxModel,
40
+ ParamsValidator: () => ParamsValidator,
41
+ ProgressiveBracketModel: () => ProgressiveBracketModel,
42
+ ScopeResolver: () => ScopeResolver,
43
+ ThresholdModel: () => ThresholdModel
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/FiscalPlugin.ts
48
+ var import_plugin_sdk7 = require("@run-iq/plugin-sdk");
49
+
50
+ // src/jurisdiction/JurisdictionResolver.ts
51
+ var JURISDICTION_BASE = {
52
+ NATIONAL: 3e3,
53
+ REGIONAL: 2e3,
54
+ MUNICIPAL: 1e3
55
+ };
56
+ var SCOPE_MULTIPLIER = {
57
+ GLOBAL: 1,
58
+ ORGANIZATION: 1.1,
59
+ USER: 1.2
60
+ };
61
+ var JurisdictionResolver = class {
62
+ static resolve(jurisdiction, scope) {
63
+ const base = JURISDICTION_BASE[jurisdiction];
64
+ const multiplier = SCOPE_MULTIPLIER[scope];
65
+ return Math.round(base * multiplier);
66
+ }
67
+ };
68
+
69
+ // src/models/FlatRateModel.ts
70
+ var import_decimal = __toESM(require("decimal.js"), 1);
71
+ var import_plugin_sdk = require("@run-iq/plugin-sdk");
72
+ var FlatRateModel = class extends import_plugin_sdk.BaseModel {
73
+ name = "FLAT_RATE";
74
+ version = "1.0.0";
75
+ validateParams(params) {
76
+ return import_plugin_sdk.SchemaValidator.validate(params, {
77
+ rate: { type: "number", min: 0, max: 1 },
78
+ base: { type: "string" }
79
+ });
80
+ }
81
+ calculate(input, _matchedRule, params) {
82
+ const p = params;
83
+ const baseValue = new import_decimal.default(String(input[p.base] ?? 0));
84
+ const rate = new import_decimal.default(String(p.rate));
85
+ return baseValue.mul(rate).toNumber();
86
+ }
87
+ };
88
+
89
+ // src/models/ProgressiveBracketModel.ts
90
+ var import_decimal2 = __toESM(require("decimal.js"), 1);
91
+ var import_plugin_sdk2 = require("@run-iq/plugin-sdk");
92
+ var ProgressiveBracketModel = class extends import_plugin_sdk2.BaseModel {
93
+ name = "PROGRESSIVE_BRACKET";
94
+ version = "1.0.0";
95
+ validateParams(params) {
96
+ if (params === null || typeof params !== "object") {
97
+ return { valid: false, errors: ["params must be an object"] };
98
+ }
99
+ const p = params;
100
+ const errors = [];
101
+ if (typeof p["base"] !== "string") {
102
+ errors.push('"base" must be a string');
103
+ }
104
+ if (!Array.isArray(p["brackets"]) || p["brackets"].length === 0) {
105
+ errors.push('"brackets" must be a non-empty array');
106
+ }
107
+ return errors.length > 0 ? { valid: false, errors } : { valid: true };
108
+ }
109
+ calculate(input, _matchedRule, params) {
110
+ const p = params;
111
+ const baseValue = new import_decimal2.default(String(input[p.base] ?? 0));
112
+ let total = new import_decimal2.default(0);
113
+ for (const bracket of p.brackets) {
114
+ const from = new import_decimal2.default(String(bracket.from));
115
+ const to = bracket.to !== null ? new import_decimal2.default(String(bracket.to)) : null;
116
+ const rate = new import_decimal2.default(String(bracket.rate));
117
+ if (baseValue.lte(from)) {
118
+ break;
119
+ }
120
+ const taxableInBracket = to !== null ? import_decimal2.default.min(baseValue, to).minus(from) : baseValue.minus(from);
121
+ if (taxableInBracket.gt(0)) {
122
+ total = total.plus(taxableInBracket.mul(rate));
123
+ }
124
+ }
125
+ return total.toNumber();
126
+ }
127
+ };
128
+
129
+ // src/models/MinimumTaxModel.ts
130
+ var import_decimal3 = __toESM(require("decimal.js"), 1);
131
+ var import_plugin_sdk3 = require("@run-iq/plugin-sdk");
132
+ var MinimumTaxModel = class extends import_plugin_sdk3.BaseModel {
133
+ name = "MINIMUM_TAX";
134
+ version = "1.0.0";
135
+ validateParams(params) {
136
+ return import_plugin_sdk3.SchemaValidator.validate(params, {
137
+ rate: { type: "number", min: 0, max: 1 },
138
+ base: { type: "string" },
139
+ minimum: { type: "number", min: 0 }
140
+ });
141
+ }
142
+ calculate(input, _matchedRule, params) {
143
+ const p = params;
144
+ const baseValue = new import_decimal3.default(String(input[p.base] ?? 0));
145
+ const rate = new import_decimal3.default(String(p.rate));
146
+ const minimum = new import_decimal3.default(String(p.minimum));
147
+ const computed = baseValue.mul(rate);
148
+ return import_decimal3.default.max(computed, minimum).toNumber();
149
+ }
150
+ };
151
+
152
+ // src/models/ThresholdModel.ts
153
+ var import_decimal4 = __toESM(require("decimal.js"), 1);
154
+ var import_plugin_sdk4 = require("@run-iq/plugin-sdk");
155
+ var ThresholdModel = class extends import_plugin_sdk4.BaseModel {
156
+ name = "THRESHOLD_BASED";
157
+ version = "1.0.0";
158
+ validateParams(params) {
159
+ return import_plugin_sdk4.SchemaValidator.validate(params, {
160
+ base: { type: "string" },
161
+ threshold: { type: "number", min: 0 },
162
+ rate: { type: "number", min: 0, max: 1 },
163
+ above_only: { type: "boolean" }
164
+ });
165
+ }
166
+ calculate(input, _matchedRule, params) {
167
+ const p = params;
168
+ const baseValue = new import_decimal4.default(String(input[p.base] ?? 0));
169
+ const threshold = new import_decimal4.default(String(p.threshold));
170
+ const rate = new import_decimal4.default(String(p.rate));
171
+ if (baseValue.lte(threshold)) {
172
+ return 0;
173
+ }
174
+ if (p.above_only) {
175
+ return baseValue.minus(threshold).mul(rate).toNumber();
176
+ }
177
+ return baseValue.mul(rate).toNumber();
178
+ }
179
+ };
180
+
181
+ // src/models/FixedAmountModel.ts
182
+ var import_plugin_sdk5 = require("@run-iq/plugin-sdk");
183
+ var FixedAmountModel = class extends import_plugin_sdk5.BaseModel {
184
+ name = "FIXED_AMOUNT";
185
+ version = "1.0.0";
186
+ validateParams(params) {
187
+ return import_plugin_sdk5.SchemaValidator.validate(params, {
188
+ amount: { type: "number", min: 0 },
189
+ currency: { type: "string" }
190
+ });
191
+ }
192
+ calculate(_input, _matchedRule, params) {
193
+ const p = params;
194
+ return p.amount;
195
+ }
196
+ };
197
+
198
+ // src/models/CompositeModel.ts
199
+ var import_decimal5 = __toESM(require("decimal.js"), 1);
200
+ var import_plugin_sdk6 = require("@run-iq/plugin-sdk");
201
+ var SUB_MODELS = {
202
+ FLAT_RATE: new FlatRateModel(),
203
+ PROGRESSIVE_BRACKET: new ProgressiveBracketModel(),
204
+ MINIMUM_TAX: new MinimumTaxModel(),
205
+ THRESHOLD_BASED: new ThresholdModel(),
206
+ FIXED_AMOUNT: new FixedAmountModel()
207
+ };
208
+ var CompositeModel = class extends import_plugin_sdk6.BaseModel {
209
+ name = "COMPOSITE";
210
+ version = "1.0.0";
211
+ validateParams(params) {
212
+ if (params === null || typeof params !== "object") {
213
+ return { valid: false, errors: ["params must be an object"] };
214
+ }
215
+ const p = params;
216
+ const errors = [];
217
+ if (!Array.isArray(p["steps"]) || p["steps"].length === 0) {
218
+ errors.push('"steps" must be a non-empty array');
219
+ }
220
+ const agg = p["aggregation"];
221
+ if (agg !== "SUM" && agg !== "MAX" && agg !== "MIN") {
222
+ errors.push('"aggregation" must be SUM, MAX, or MIN');
223
+ }
224
+ return errors.length > 0 ? { valid: false, errors } : { valid: true };
225
+ }
226
+ calculate(input, matchedRule, params) {
227
+ const p = params;
228
+ const contributions = [];
229
+ for (const step of p.steps) {
230
+ const subModel = SUB_MODELS[step.model];
231
+ if (!subModel) {
232
+ continue;
233
+ }
234
+ const value = subModel.calculate(input, matchedRule, step.params);
235
+ contributions.push(new import_decimal5.default(String(value)));
236
+ }
237
+ if (contributions.length === 0) {
238
+ return 0;
239
+ }
240
+ switch (p.aggregation) {
241
+ case "SUM":
242
+ return contributions.reduce((acc, v) => acc.plus(v), new import_decimal5.default(0)).toNumber();
243
+ case "MAX":
244
+ return import_decimal5.default.max(...contributions).toNumber();
245
+ case "MIN":
246
+ return import_decimal5.default.min(...contributions).toNumber();
247
+ }
248
+ }
249
+ };
250
+
251
+ // src/FiscalPlugin.ts
252
+ var FiscalPlugin = class extends import_plugin_sdk7.BasePlugin {
253
+ name = "@run-iq/plugin-fiscal";
254
+ version = "0.1.0";
255
+ models = [
256
+ new FlatRateModel(),
257
+ new ProgressiveBracketModel(),
258
+ new MinimumTaxModel(),
259
+ new ThresholdModel(),
260
+ new FixedAmountModel(),
261
+ new CompositeModel()
262
+ ];
263
+ beforeEvaluate(input, rules) {
264
+ const fiscalRules = rules;
265
+ const resolvedRules = fiscalRules.map((rule) => ({
266
+ ...rule,
267
+ priority: JurisdictionResolver.resolve(rule.jurisdiction, rule.scope)
268
+ }));
269
+ const country = input.meta.context?.["country"];
270
+ const filteredRules = country ? resolvedRules.filter((r) => r.country === country) : resolvedRules;
271
+ return {
272
+ ...input,
273
+ data: {
274
+ ...input.data,
275
+ _resolvedRules: filteredRules
276
+ }
277
+ };
278
+ }
279
+ afterEvaluate(_input, result) {
280
+ const fiscalBreakdown = {};
281
+ for (const item of result.breakdown) {
282
+ const rule = result.appliedRules.find((r) => r.id === item.ruleId);
283
+ const category = rule?.category ?? "unknown";
284
+ fiscalBreakdown[category] = (fiscalBreakdown[category] ?? 0) + item.contribution;
285
+ }
286
+ return {
287
+ ...result,
288
+ meta: { ...result.meta, fiscalBreakdown }
289
+ };
290
+ }
291
+ };
292
+
293
+ // src/jurisdiction/ScopeResolver.ts
294
+ var SCOPE_MULTIPLIER2 = {
295
+ GLOBAL: 1,
296
+ ORGANIZATION: 1.1,
297
+ USER: 1.2
298
+ };
299
+ var ScopeResolver = class {
300
+ static getMultiplier(scope) {
301
+ return SCOPE_MULTIPLIER2[scope];
302
+ }
303
+ };
304
+
305
+ // src/validators/FiscalRuleValidator.ts
306
+ var VALID_JURISDICTIONS = ["NATIONAL", "REGIONAL", "MUNICIPAL"];
307
+ var VALID_SCOPES = ["GLOBAL", "ORGANIZATION", "USER"];
308
+ var FiscalRuleValidator = class {
309
+ static validate(rule) {
310
+ const errors = [];
311
+ if (rule === null || typeof rule !== "object") {
312
+ return { valid: false, errors: ["rule must be an object"] };
313
+ }
314
+ const r = rule;
315
+ if (!r.jurisdiction || !VALID_JURISDICTIONS.includes(r.jurisdiction)) {
316
+ errors.push(`jurisdiction must be one of: ${VALID_JURISDICTIONS.join(", ")}`);
317
+ }
318
+ if (!r.scope || !VALID_SCOPES.includes(r.scope)) {
319
+ errors.push(`scope must be one of: ${VALID_SCOPES.join(", ")}`);
320
+ }
321
+ if (typeof r.country !== "string" || r.country.length === 0) {
322
+ errors.push("country must be a non-empty string");
323
+ }
324
+ if (typeof r.category !== "string" || r.category.length === 0) {
325
+ errors.push("category must be a non-empty string");
326
+ }
327
+ return { valid: errors.length === 0, errors };
328
+ }
329
+ };
330
+
331
+ // src/validators/ParamsValidator.ts
332
+ var import_plugin_sdk8 = require("@run-iq/plugin-sdk");
333
+ var ParamsValidator = class {
334
+ static validateFlatRate(params) {
335
+ return import_plugin_sdk8.SchemaValidator.validate(params, {
336
+ rate: { type: "number", min: 0, max: 1 },
337
+ base: { type: "string" }
338
+ });
339
+ }
340
+ static validateMinimumTax(params) {
341
+ return import_plugin_sdk8.SchemaValidator.validate(params, {
342
+ rate: { type: "number", min: 0, max: 1 },
343
+ base: { type: "string" },
344
+ minimum: { type: "number", min: 0 }
345
+ });
346
+ }
347
+ static validateThreshold(params) {
348
+ return import_plugin_sdk8.SchemaValidator.validate(params, {
349
+ base: { type: "string" },
350
+ threshold: { type: "number", min: 0 },
351
+ rate: { type: "number", min: 0, max: 1 },
352
+ above_only: { type: "boolean" }
353
+ });
354
+ }
355
+ static validateFixedAmount(params) {
356
+ return import_plugin_sdk8.SchemaValidator.validate(params, {
357
+ amount: { type: "number", min: 0 },
358
+ currency: { type: "string" }
359
+ });
360
+ }
361
+ };
362
+ // Annotate the CommonJS export names for ESM import in node:
363
+ 0 && (module.exports = {
364
+ CompositeModel,
365
+ FiscalPlugin,
366
+ FiscalRuleValidator,
367
+ FixedAmountModel,
368
+ FlatRateModel,
369
+ JurisdictionResolver,
370
+ MinimumTaxModel,
371
+ ParamsValidator,
372
+ ProgressiveBracketModel,
373
+ ScopeResolver,
374
+ ThresholdModel
375
+ });
376
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/FiscalPlugin.ts","../src/jurisdiction/JurisdictionResolver.ts","../src/models/FlatRateModel.ts","../src/models/ProgressiveBracketModel.ts","../src/models/MinimumTaxModel.ts","../src/models/ThresholdModel.ts","../src/models/FixedAmountModel.ts","../src/models/CompositeModel.ts","../src/jurisdiction/ScopeResolver.ts","../src/validators/FiscalRuleValidator.ts","../src/validators/ParamsValidator.ts"],"sourcesContent":["export { FiscalPlugin } from './FiscalPlugin.js';\nexport { FlatRateModel } from './models/FlatRateModel.js';\nexport { ProgressiveBracketModel } from './models/ProgressiveBracketModel.js';\nexport { MinimumTaxModel } from './models/MinimumTaxModel.js';\nexport { ThresholdModel } from './models/ThresholdModel.js';\nexport { FixedAmountModel } from './models/FixedAmountModel.js';\nexport { CompositeModel } from './models/CompositeModel.js';\nexport { JurisdictionResolver } from './jurisdiction/JurisdictionResolver.js';\nexport { ScopeResolver } from './jurisdiction/ScopeResolver.js';\nexport { FiscalRuleValidator } from './validators/FiscalRuleValidator.js';\nexport { ParamsValidator } from './validators/ParamsValidator.js';\nexport type { FiscalRule, FiscalScope } from './types/fiscal-rule.js';\nexport type { FiscalJurisdiction } from './types/jurisdiction.js';\nexport type { FiscalCalculationModel } from './types/models.js';\nexport type {\n FlatRateParams,\n BracketParams,\n MinimumTaxParams,\n ThresholdParams,\n FixedAmountParams,\n CompositeParams,\n} from './types/params.js';\n","import { BasePlugin } from '@run-iq/plugin-sdk';\nimport type { EvaluationInput, EvaluationResult, Rule, CalculationModel } from '@run-iq/core';\nimport type { FiscalRule } from './types/fiscal-rule.js';\nimport { JurisdictionResolver } from './jurisdiction/JurisdictionResolver.js';\nimport { FlatRateModel } from './models/FlatRateModel.js';\nimport { ProgressiveBracketModel } from './models/ProgressiveBracketModel.js';\nimport { MinimumTaxModel } from './models/MinimumTaxModel.js';\nimport { ThresholdModel } from './models/ThresholdModel.js';\nimport { FixedAmountModel } from './models/FixedAmountModel.js';\nimport { CompositeModel } from './models/CompositeModel.js';\n\nexport class FiscalPlugin extends BasePlugin {\n readonly name = '@run-iq/plugin-fiscal' as const;\n readonly version = '0.1.0';\n\n readonly models: CalculationModel[] = [\n new FlatRateModel(),\n new ProgressiveBracketModel(),\n new MinimumTaxModel(),\n new ThresholdModel(),\n new FixedAmountModel(),\n new CompositeModel(),\n ];\n\n override beforeEvaluate(input: EvaluationInput, rules: ReadonlyArray<Rule>): EvaluationInput {\n const fiscalRules = rules as ReadonlyArray<FiscalRule>;\n\n // 1. Resolve priorities from jurisdiction + scope\n const resolvedRules = fiscalRules.map((rule) => ({\n ...rule,\n priority: JurisdictionResolver.resolve(rule.jurisdiction, rule.scope),\n }));\n\n // 2. Filter by country if provided in context\n const country = input.meta.context?.['country'] as string | undefined;\n const filteredRules = country\n ? resolvedRules.filter((r) => r.country === country)\n : resolvedRules;\n\n // IMMUTABLE — return new values\n return {\n ...input,\n data: {\n ...input.data,\n _resolvedRules: filteredRules,\n },\n };\n }\n\n override afterEvaluate(_input: EvaluationInput, result: EvaluationResult): EvaluationResult {\n // Enrich result with fiscal breakdown by category\n const fiscalBreakdown: Record<string, number> = {};\n\n for (const item of result.breakdown) {\n const rule = result.appliedRules.find((r) => r.id === item.ruleId) as FiscalRule | undefined;\n const category = rule?.category ?? 'unknown';\n fiscalBreakdown[category] = (fiscalBreakdown[category] ?? 0) + (item.contribution as number);\n }\n\n return {\n ...result,\n meta: { ...result.meta, fiscalBreakdown },\n };\n }\n}\n","import type { FiscalJurisdiction } from '../types/jurisdiction.js';\nimport type { FiscalScope } from '../types/fiscal-rule.js';\n\nconst JURISDICTION_BASE: Record<FiscalJurisdiction, number> = {\n NATIONAL: 3000,\n REGIONAL: 2000,\n MUNICIPAL: 1000,\n};\n\nconst SCOPE_MULTIPLIER: Record<FiscalScope, number> = {\n GLOBAL: 1.0,\n ORGANIZATION: 1.1,\n USER: 1.2,\n};\n\nexport class JurisdictionResolver {\n static resolve(jurisdiction: FiscalJurisdiction, scope: FiscalScope): number {\n const base = JURISDICTION_BASE[jurisdiction];\n const multiplier = SCOPE_MULTIPLIER[scope];\n return Math.round(base * multiplier);\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { FlatRateParams } from '../types/params.js';\n\nexport class FlatRateModel extends BaseModel {\n readonly name = 'FLAT_RATE' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as FlatRateParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const rate = new Decimal(String(p.rate));\n return baseValue.mul(rate).toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { BracketParams } from '../types/params.js';\n\nexport class ProgressiveBracketModel extends BaseModel {\n readonly name = 'PROGRESSIVE_BRACKET' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n if (params === null || typeof params !== 'object') {\n return { valid: false, errors: ['params must be an object'] };\n }\n const p = params as Record<string, unknown>;\n const errors: string[] = [];\n\n if (typeof p['base'] !== 'string') {\n errors.push('\"base\" must be a string');\n }\n if (!Array.isArray(p['brackets']) || p['brackets'].length === 0) {\n errors.push('\"brackets\" must be a non-empty array');\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true };\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as BracketParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n let total = new Decimal(0);\n\n for (const bracket of p.brackets) {\n const from = new Decimal(String(bracket.from));\n const to = bracket.to !== null ? new Decimal(String(bracket.to)) : null;\n const rate = new Decimal(String(bracket.rate));\n\n if (baseValue.lte(from)) {\n break;\n }\n\n const taxableInBracket =\n to !== null ? Decimal.min(baseValue, to).minus(from) : baseValue.minus(from);\n\n if (taxableInBracket.gt(0)) {\n total = total.plus(taxableInBracket.mul(rate));\n }\n }\n\n return total.toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { MinimumTaxParams } from '../types/params.js';\n\nexport class MinimumTaxModel extends BaseModel {\n readonly name = 'MINIMUM_TAX' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n minimum: { type: 'number', min: 0 },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as MinimumTaxParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const rate = new Decimal(String(p.rate));\n const minimum = new Decimal(String(p.minimum));\n const computed = baseValue.mul(rate);\n return Decimal.max(computed, minimum).toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { ThresholdParams } from '../types/params.js';\n\nexport class ThresholdModel extends BaseModel {\n readonly name = 'THRESHOLD_BASED' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n base: { type: 'string' },\n threshold: { type: 'number', min: 0 },\n rate: { type: 'number', min: 0, max: 1 },\n above_only: { type: 'boolean' },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as ThresholdParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const threshold = new Decimal(String(p.threshold));\n const rate = new Decimal(String(p.rate));\n\n if (baseValue.lte(threshold)) {\n return 0;\n }\n\n if (p.above_only) {\n return baseValue.minus(threshold).mul(rate).toNumber();\n }\n\n return baseValue.mul(rate).toNumber();\n }\n}\n","import { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { FixedAmountParams } from '../types/params.js';\n\nexport class FixedAmountModel extends BaseModel {\n readonly name = 'FIXED_AMOUNT' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n amount: { type: 'number', min: 0 },\n currency: { type: 'string' },\n });\n }\n\n calculate(\n _input: Record<string, unknown>,\n _matchedRule: Readonly<Rule>,\n params: unknown,\n ): number {\n const p = params as FixedAmountParams;\n return p.amount;\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule, CalculationModel } from '@run-iq/core';\nimport type { CompositeParams } from '../types/params.js';\nimport { FlatRateModel } from './FlatRateModel.js';\nimport { ProgressiveBracketModel } from './ProgressiveBracketModel.js';\nimport { MinimumTaxModel } from './MinimumTaxModel.js';\nimport { ThresholdModel } from './ThresholdModel.js';\nimport { FixedAmountModel } from './FixedAmountModel.js';\n\nconst SUB_MODELS: Record<string, CalculationModel> = {\n FLAT_RATE: new FlatRateModel(),\n PROGRESSIVE_BRACKET: new ProgressiveBracketModel(),\n MINIMUM_TAX: new MinimumTaxModel(),\n THRESHOLD_BASED: new ThresholdModel(),\n FIXED_AMOUNT: new FixedAmountModel(),\n};\n\nexport class CompositeModel extends BaseModel {\n readonly name = 'COMPOSITE' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n if (params === null || typeof params !== 'object') {\n return { valid: false, errors: ['params must be an object'] };\n }\n const p = params as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!Array.isArray(p['steps']) || p['steps'].length === 0) {\n errors.push('\"steps\" must be a non-empty array');\n }\n\n const agg = p['aggregation'];\n if (agg !== 'SUM' && agg !== 'MAX' && agg !== 'MIN') {\n errors.push('\"aggregation\" must be SUM, MAX, or MIN');\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true };\n }\n\n calculate(input: Record<string, unknown>, matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as CompositeParams;\n const contributions: Decimal[] = [];\n\n for (const step of p.steps) {\n const subModel = SUB_MODELS[step.model];\n if (!subModel) {\n continue;\n }\n const value = subModel.calculate(input, matchedRule, step.params);\n contributions.push(new Decimal(String(value)));\n }\n\n if (contributions.length === 0) {\n return 0;\n }\n\n switch (p.aggregation) {\n case 'SUM':\n return contributions.reduce((acc, v) => acc.plus(v), new Decimal(0)).toNumber();\n case 'MAX':\n return Decimal.max(...contributions).toNumber();\n case 'MIN':\n return Decimal.min(...contributions).toNumber();\n }\n }\n}\n","import type { FiscalScope } from '../types/fiscal-rule.js';\n\nconst SCOPE_MULTIPLIER: Record<FiscalScope, number> = {\n GLOBAL: 1.0,\n ORGANIZATION: 1.1,\n USER: 1.2,\n};\n\nexport class ScopeResolver {\n static getMultiplier(scope: FiscalScope): number {\n return SCOPE_MULTIPLIER[scope];\n }\n}\n","import type { FiscalRule } from '../types/fiscal-rule.js';\n\nconst VALID_JURISDICTIONS = ['NATIONAL', 'REGIONAL', 'MUNICIPAL'];\nconst VALID_SCOPES = ['GLOBAL', 'ORGANIZATION', 'USER'];\n\nexport class FiscalRuleValidator {\n static validate(rule: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n if (rule === null || typeof rule !== 'object') {\n return { valid: false, errors: ['rule must be an object'] };\n }\n\n const r = rule as Partial<FiscalRule>;\n\n if (!r.jurisdiction || !VALID_JURISDICTIONS.includes(r.jurisdiction)) {\n errors.push(`jurisdiction must be one of: ${VALID_JURISDICTIONS.join(', ')}`);\n }\n if (!r.scope || !VALID_SCOPES.includes(r.scope)) {\n errors.push(`scope must be one of: ${VALID_SCOPES.join(', ')}`);\n }\n if (typeof r.country !== 'string' || r.country.length === 0) {\n errors.push('country must be a non-empty string');\n }\n if (typeof r.category !== 'string' || r.category.length === 0) {\n errors.push('category must be a non-empty string');\n }\n\n return { valid: errors.length === 0, errors };\n }\n}\n","import { SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult } from '@run-iq/core';\n\nexport class ParamsValidator {\n static validateFlatRate(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n });\n }\n\n static validateMinimumTax(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n minimum: { type: 'number', min: 0 },\n });\n }\n\n static validateThreshold(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n base: { type: 'string' },\n threshold: { type: 'number', min: 0 },\n rate: { type: 'number', min: 0, max: 1 },\n above_only: { type: 'boolean' },\n });\n }\n\n static validateFixedAmount(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n amount: { type: 'number', min: 0 },\n currency: { type: 'string' },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,qBAA2B;;;ACG3B,IAAM,oBAAwD;AAAA,EAC5D,UAAU;AAAA,EACV,UAAU;AAAA,EACV,WAAW;AACb;AAEA,IAAM,mBAAgD;AAAA,EACpD,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AACR;AAEO,IAAM,uBAAN,MAA2B;AAAA,EAChC,OAAO,QAAQ,cAAkC,OAA4B;AAC3E,UAAM,OAAO,kBAAkB,YAAY;AAC3C,UAAM,aAAa,iBAAiB,KAAK;AACzC,WAAO,KAAK,MAAM,OAAO,UAAU;AAAA,EACrC;AACF;;;ACrBA,qBAAoB;AACpB,wBAA2C;AAIpC,IAAM,gBAAN,cAA4B,4BAAU;AAAA,EAClC,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,WAAO,kCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,MAAM,EAAE,MAAM,SAAS;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAgC,cAA8B,QAAyB;AAC/F,UAAM,IAAI;AACV,UAAM,YAAY,IAAI,eAAAC,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC;AACxD,UAAM,OAAO,IAAI,eAAAA,QAAQ,OAAO,EAAE,IAAI,CAAC;AACvC,WAAO,UAAU,IAAI,IAAI,EAAE,SAAS;AAAA,EACtC;AACF;;;ACtBA,IAAAC,kBAAoB;AACpB,IAAAC,qBAA0B;AAInB,IAAM,0BAAN,cAAsC,6BAAU;AAAA,EAC5C,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,QAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,aAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,0BAA0B,EAAE;AAAA,IAC9D;AACA,UAAM,IAAI;AACV,UAAM,SAAmB,CAAC;AAE1B,QAAI,OAAO,EAAE,MAAM,MAAM,UAAU;AACjC,aAAO,KAAK,yBAAyB;AAAA,IACvC;AACA,QAAI,CAAC,MAAM,QAAQ,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,GAAG;AAC/D,aAAO,KAAK,sCAAsC;AAAA,IACpD;AAEA,WAAO,OAAO,SAAS,IAAI,EAAE,OAAO,OAAO,OAAO,IAAI,EAAE,OAAO,KAAK;AAAA,EACtE;AAAA,EAEA,UAAU,OAAgC,cAA8B,QAAyB;AAC/F,UAAM,IAAI;AACV,UAAM,YAAY,IAAI,gBAAAC,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC;AACxD,QAAI,QAAQ,IAAI,gBAAAA,QAAQ,CAAC;AAEzB,eAAW,WAAW,EAAE,UAAU;AAChC,YAAM,OAAO,IAAI,gBAAAA,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAC7C,YAAM,KAAK,QAAQ,OAAO,OAAO,IAAI,gBAAAA,QAAQ,OAAO,QAAQ,EAAE,CAAC,IAAI;AACnE,YAAM,OAAO,IAAI,gBAAAA,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAE7C,UAAI,UAAU,IAAI,IAAI,GAAG;AACvB;AAAA,MACF;AAEA,YAAM,mBACJ,OAAO,OAAO,gBAAAA,QAAQ,IAAI,WAAW,EAAE,EAAE,MAAM,IAAI,IAAI,UAAU,MAAM,IAAI;AAE7E,UAAI,iBAAiB,GAAG,CAAC,GAAG;AAC1B,gBAAQ,MAAM,KAAK,iBAAiB,IAAI,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AAEA,WAAO,MAAM,SAAS;AAAA,EACxB;AACF;;;AClDA,IAAAC,kBAAoB;AACpB,IAAAC,qBAA2C;AAIpC,IAAM,kBAAN,cAA8B,6BAAU;AAAA,EACpC,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,SAAS,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAgC,cAA8B,QAAyB;AAC/F,UAAM,IAAI;AACV,UAAM,YAAY,IAAI,gBAAAC,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC;AACxD,UAAM,OAAO,IAAI,gBAAAA,QAAQ,OAAO,EAAE,IAAI,CAAC;AACvC,UAAM,UAAU,IAAI,gBAAAA,QAAQ,OAAO,EAAE,OAAO,CAAC;AAC7C,UAAM,WAAW,UAAU,IAAI,IAAI;AACnC,WAAO,gBAAAA,QAAQ,IAAI,UAAU,OAAO,EAAE,SAAS;AAAA,EACjD;AACF;;;ACzBA,IAAAC,kBAAoB;AACpB,IAAAC,qBAA2C;AAIpC,IAAM,iBAAN,cAA6B,6BAAU;AAAA,EACnC,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,WAAW,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,MACpC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,YAAY,EAAE,MAAM,UAAU;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,OAAgC,cAA8B,QAAyB;AAC/F,UAAM,IAAI;AACV,UAAM,YAAY,IAAI,gBAAAC,QAAQ,OAAO,MAAM,EAAE,IAAI,KAAK,CAAC,CAAC;AACxD,UAAM,YAAY,IAAI,gBAAAA,QAAQ,OAAO,EAAE,SAAS,CAAC;AACjD,UAAM,OAAO,IAAI,gBAAAA,QAAQ,OAAO,EAAE,IAAI,CAAC;AAEvC,QAAI,UAAU,IAAI,SAAS,GAAG;AAC5B,aAAO;AAAA,IACT;AAEA,QAAI,EAAE,YAAY;AAChB,aAAO,UAAU,MAAM,SAAS,EAAE,IAAI,IAAI,EAAE,SAAS;AAAA,IACvD;AAEA,WAAO,UAAU,IAAI,IAAI,EAAE,SAAS;AAAA,EACtC;AACF;;;AClCA,IAAAC,qBAA2C;AAIpC,IAAM,mBAAN,cAA+B,6BAAU;AAAA,EACrC,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,QAAQ,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,MACjC,UAAU,EAAE,MAAM,SAAS;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,UACE,QACA,cACA,QACQ;AACR,UAAM,IAAI;AACV,WAAO,EAAE;AAAA,EACX;AACF;;;ACvBA,IAAAC,kBAAoB;AACpB,IAAAC,qBAA0B;AAS1B,IAAM,aAA+C;AAAA,EACnD,WAAW,IAAI,cAAc;AAAA,EAC7B,qBAAqB,IAAI,wBAAwB;AAAA,EACjD,aAAa,IAAI,gBAAgB;AAAA,EACjC,iBAAiB,IAAI,eAAe;AAAA,EACpC,cAAc,IAAI,iBAAiB;AACrC;AAEO,IAAM,iBAAN,cAA6B,6BAAU;AAAA,EACnC,OAAO;AAAA,EACP,UAAU;AAAA,EAEnB,eAAe,QAAmC;AAChD,QAAI,WAAW,QAAQ,OAAO,WAAW,UAAU;AACjD,aAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,0BAA0B,EAAE;AAAA,IAC9D;AACA,UAAM,IAAI;AACV,UAAM,SAAmB,CAAC;AAE1B,QAAI,CAAC,MAAM,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,GAAG;AACzD,aAAO,KAAK,mCAAmC;AAAA,IACjD;AAEA,UAAM,MAAM,EAAE,aAAa;AAC3B,QAAI,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO;AACnD,aAAO,KAAK,wCAAwC;AAAA,IACtD;AAEA,WAAO,OAAO,SAAS,IAAI,EAAE,OAAO,OAAO,OAAO,IAAI,EAAE,OAAO,KAAK;AAAA,EACtE;AAAA,EAEA,UAAU,OAAgC,aAA6B,QAAyB;AAC9F,UAAM,IAAI;AACV,UAAM,gBAA2B,CAAC;AAElC,eAAW,QAAQ,EAAE,OAAO;AAC1B,YAAM,WAAW,WAAW,KAAK,KAAK;AACtC,UAAI,CAAC,UAAU;AACb;AAAA,MACF;AACA,YAAM,QAAQ,SAAS,UAAU,OAAO,aAAa,KAAK,MAAM;AAChE,oBAAc,KAAK,IAAI,gBAAAC,QAAQ,OAAO,KAAK,CAAC,CAAC;AAAA,IAC/C;AAEA,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO;AAAA,IACT;AAEA,YAAQ,EAAE,aAAa;AAAA,MACrB,KAAK;AACH,eAAO,cAAc,OAAO,CAAC,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,gBAAAA,QAAQ,CAAC,CAAC,EAAE,SAAS;AAAA,MAChF,KAAK;AACH,eAAO,gBAAAA,QAAQ,IAAI,GAAG,aAAa,EAAE,SAAS;AAAA,MAChD,KAAK;AACH,eAAO,gBAAAA,QAAQ,IAAI,GAAG,aAAa,EAAE,SAAS;AAAA,IAClD;AAAA,EACF;AACF;;;APxDO,IAAM,eAAN,cAA2B,8BAAW;AAAA,EAClC,OAAO;AAAA,EACP,UAAU;AAAA,EAEV,SAA6B;AAAA,IACpC,IAAI,cAAc;AAAA,IAClB,IAAI,wBAAwB;AAAA,IAC5B,IAAI,gBAAgB;AAAA,IACpB,IAAI,eAAe;AAAA,IACnB,IAAI,iBAAiB;AAAA,IACrB,IAAI,eAAe;AAAA,EACrB;AAAA,EAES,eAAe,OAAwB,OAA6C;AAC3F,UAAM,cAAc;AAGpB,UAAM,gBAAgB,YAAY,IAAI,CAAC,UAAU;AAAA,MAC/C,GAAG;AAAA,MACH,UAAU,qBAAqB,QAAQ,KAAK,cAAc,KAAK,KAAK;AAAA,IACtE,EAAE;AAGF,UAAM,UAAU,MAAM,KAAK,UAAU,SAAS;AAC9C,UAAM,gBAAgB,UAClB,cAAc,OAAO,CAAC,MAAM,EAAE,YAAY,OAAO,IACjD;AAGJ,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,QACJ,GAAG,MAAM;AAAA,QACT,gBAAgB;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAAA,EAES,cAAc,QAAyB,QAA4C;AAE1F,UAAM,kBAA0C,CAAC;AAEjD,eAAW,QAAQ,OAAO,WAAW;AACnC,YAAM,OAAO,OAAO,aAAa,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM;AACjE,YAAM,WAAW,MAAM,YAAY;AACnC,sBAAgB,QAAQ,KAAK,gBAAgB,QAAQ,KAAK,KAAM,KAAK;AAAA,IACvE;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,EAAE,GAAG,OAAO,MAAM,gBAAgB;AAAA,IAC1C;AAAA,EACF;AACF;;;AQ9DA,IAAMC,oBAAgD;AAAA,EACpD,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,MAAM;AACR;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACzB,OAAO,cAAc,OAA4B;AAC/C,WAAOA,kBAAiB,KAAK;AAAA,EAC/B;AACF;;;ACVA,IAAM,sBAAsB,CAAC,YAAY,YAAY,WAAW;AAChE,IAAM,eAAe,CAAC,UAAU,gBAAgB,MAAM;AAE/C,IAAM,sBAAN,MAA0B;AAAA,EAC/B,OAAO,SAAS,MAAqD;AACnE,UAAM,SAAmB,CAAC;AAC1B,QAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;AAC7C,aAAO,EAAE,OAAO,OAAO,QAAQ,CAAC,wBAAwB,EAAE;AAAA,IAC5D;AAEA,UAAM,IAAI;AAEV,QAAI,CAAC,EAAE,gBAAgB,CAAC,oBAAoB,SAAS,EAAE,YAAY,GAAG;AACpE,aAAO,KAAK,gCAAgC,oBAAoB,KAAK,IAAI,CAAC,EAAE;AAAA,IAC9E;AACA,QAAI,CAAC,EAAE,SAAS,CAAC,aAAa,SAAS,EAAE,KAAK,GAAG;AAC/C,aAAO,KAAK,yBAAyB,aAAa,KAAK,IAAI,CAAC,EAAE;AAAA,IAChE;AACA,QAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW,GAAG;AAC3D,aAAO,KAAK,oCAAoC;AAAA,IAClD;AACA,QAAI,OAAO,EAAE,aAAa,YAAY,EAAE,SAAS,WAAW,GAAG;AAC7D,aAAO,KAAK,qCAAqC;AAAA,IACnD;AAEA,WAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAAA,EAC9C;AACF;;;AC7BA,IAAAC,qBAAgC;AAGzB,IAAM,kBAAN,MAAsB;AAAA,EAC3B,OAAO,iBAAiB,QAAmC;AACzD,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,MAAM,EAAE,MAAM,SAAS;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,mBAAmB,QAAmC;AAC3D,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,SAAS,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,kBAAkB,QAAmC;AAC1D,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,WAAW,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,MACpC,MAAM,EAAE,MAAM,UAAU,KAAK,GAAG,KAAK,EAAE;AAAA,MACvC,YAAY,EAAE,MAAM,UAAU;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,oBAAoB,QAAmC;AAC5D,WAAO,mCAAgB,SAAS,QAAQ;AAAA,MACtC,QAAQ,EAAE,MAAM,UAAU,KAAK,EAAE;AAAA,MACjC,UAAU,EAAE,MAAM,SAAS;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;","names":["import_plugin_sdk","Decimal","import_decimal","import_plugin_sdk","Decimal","import_decimal","import_plugin_sdk","Decimal","import_decimal","import_plugin_sdk","Decimal","import_plugin_sdk","import_decimal","import_plugin_sdk","Decimal","SCOPE_MULTIPLIER","import_plugin_sdk"]}
@@ -0,0 +1,126 @@
1
+ import { BasePlugin, BaseModel } from '@run-iq/plugin-sdk';
2
+ import { CalculationModel, EvaluationInput, Rule, EvaluationResult, ValidationResult } from '@run-iq/core';
3
+
4
+ declare class FiscalPlugin extends BasePlugin {
5
+ readonly name: "@run-iq/plugin-fiscal";
6
+ readonly version = "0.1.0";
7
+ readonly models: CalculationModel[];
8
+ beforeEvaluate(input: EvaluationInput, rules: ReadonlyArray<Rule>): EvaluationInput;
9
+ afterEvaluate(_input: EvaluationInput, result: EvaluationResult): EvaluationResult;
10
+ }
11
+
12
+ declare class FlatRateModel extends BaseModel {
13
+ readonly name: "FLAT_RATE";
14
+ readonly version = "1.0.0";
15
+ validateParams(params: unknown): ValidationResult;
16
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
17
+ }
18
+
19
+ declare class ProgressiveBracketModel extends BaseModel {
20
+ readonly name: "PROGRESSIVE_BRACKET";
21
+ readonly version = "1.0.0";
22
+ validateParams(params: unknown): ValidationResult;
23
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
24
+ }
25
+
26
+ declare class MinimumTaxModel extends BaseModel {
27
+ readonly name: "MINIMUM_TAX";
28
+ readonly version = "1.0.0";
29
+ validateParams(params: unknown): ValidationResult;
30
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
31
+ }
32
+
33
+ declare class ThresholdModel extends BaseModel {
34
+ readonly name: "THRESHOLD_BASED";
35
+ readonly version = "1.0.0";
36
+ validateParams(params: unknown): ValidationResult;
37
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
38
+ }
39
+
40
+ declare class FixedAmountModel extends BaseModel {
41
+ readonly name: "FIXED_AMOUNT";
42
+ readonly version = "1.0.0";
43
+ validateParams(params: unknown): ValidationResult;
44
+ calculate(_input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
45
+ }
46
+
47
+ declare class CompositeModel extends BaseModel {
48
+ readonly name: "COMPOSITE";
49
+ readonly version = "1.0.0";
50
+ validateParams(params: unknown): ValidationResult;
51
+ calculate(input: Record<string, unknown>, matchedRule: Readonly<Rule>, params: unknown): number;
52
+ }
53
+
54
+ type FiscalJurisdiction = 'NATIONAL' | 'REGIONAL' | 'MUNICIPAL';
55
+
56
+ type FiscalCalculationModel = 'FLAT_RATE' | 'PROGRESSIVE_BRACKET' | 'MINIMUM_TAX' | 'THRESHOLD_BASED' | 'FIXED_AMOUNT' | 'COMPOSITE' | 'META_INHIBITION' | 'META_SUBSTITUTION' | 'META_SHORT_CIRCUIT';
57
+
58
+ interface FlatRateParams {
59
+ readonly rate: number;
60
+ readonly base: string;
61
+ }
62
+ interface BracketParams {
63
+ readonly base: string;
64
+ readonly brackets: ReadonlyArray<{
65
+ readonly from: number;
66
+ readonly to: number | null;
67
+ readonly rate: number;
68
+ }>;
69
+ }
70
+ interface MinimumTaxParams {
71
+ readonly rate: number;
72
+ readonly base: string;
73
+ readonly minimum: number;
74
+ }
75
+ interface ThresholdParams {
76
+ readonly base: string;
77
+ readonly threshold: number;
78
+ readonly rate: number;
79
+ readonly above_only: boolean;
80
+ }
81
+ interface FixedAmountParams {
82
+ readonly amount: number;
83
+ readonly currency: string;
84
+ }
85
+ interface CompositeParams {
86
+ readonly steps: ReadonlyArray<{
87
+ readonly model: string;
88
+ readonly params: unknown;
89
+ readonly label?: string | undefined;
90
+ }>;
91
+ readonly aggregation: 'SUM' | 'MAX' | 'MIN';
92
+ }
93
+
94
+ type FiscalScope = 'GLOBAL' | 'ORGANIZATION' | 'USER';
95
+ interface FiscalRule extends Rule {
96
+ readonly model: FiscalCalculationModel;
97
+ readonly jurisdiction: FiscalJurisdiction;
98
+ readonly scope: FiscalScope;
99
+ readonly country: string;
100
+ readonly category: string;
101
+ readonly params: FlatRateParams | BracketParams | MinimumTaxParams | ThresholdParams | FixedAmountParams | CompositeParams;
102
+ }
103
+
104
+ declare class JurisdictionResolver {
105
+ static resolve(jurisdiction: FiscalJurisdiction, scope: FiscalScope): number;
106
+ }
107
+
108
+ declare class ScopeResolver {
109
+ static getMultiplier(scope: FiscalScope): number;
110
+ }
111
+
112
+ declare class FiscalRuleValidator {
113
+ static validate(rule: unknown): {
114
+ valid: boolean;
115
+ errors: string[];
116
+ };
117
+ }
118
+
119
+ declare class ParamsValidator {
120
+ static validateFlatRate(params: unknown): ValidationResult;
121
+ static validateMinimumTax(params: unknown): ValidationResult;
122
+ static validateThreshold(params: unknown): ValidationResult;
123
+ static validateFixedAmount(params: unknown): ValidationResult;
124
+ }
125
+
126
+ export { type BracketParams, CompositeModel, type CompositeParams, type FiscalCalculationModel, type FiscalJurisdiction, FiscalPlugin, type FiscalRule, FiscalRuleValidator, type FiscalScope, FixedAmountModel, type FixedAmountParams, FlatRateModel, type FlatRateParams, JurisdictionResolver, MinimumTaxModel, type MinimumTaxParams, ParamsValidator, ProgressiveBracketModel, ScopeResolver, ThresholdModel, type ThresholdParams };
@@ -0,0 +1,126 @@
1
+ import { BasePlugin, BaseModel } from '@run-iq/plugin-sdk';
2
+ import { CalculationModel, EvaluationInput, Rule, EvaluationResult, ValidationResult } from '@run-iq/core';
3
+
4
+ declare class FiscalPlugin extends BasePlugin {
5
+ readonly name: "@run-iq/plugin-fiscal";
6
+ readonly version = "0.1.0";
7
+ readonly models: CalculationModel[];
8
+ beforeEvaluate(input: EvaluationInput, rules: ReadonlyArray<Rule>): EvaluationInput;
9
+ afterEvaluate(_input: EvaluationInput, result: EvaluationResult): EvaluationResult;
10
+ }
11
+
12
+ declare class FlatRateModel extends BaseModel {
13
+ readonly name: "FLAT_RATE";
14
+ readonly version = "1.0.0";
15
+ validateParams(params: unknown): ValidationResult;
16
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
17
+ }
18
+
19
+ declare class ProgressiveBracketModel extends BaseModel {
20
+ readonly name: "PROGRESSIVE_BRACKET";
21
+ readonly version = "1.0.0";
22
+ validateParams(params: unknown): ValidationResult;
23
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
24
+ }
25
+
26
+ declare class MinimumTaxModel extends BaseModel {
27
+ readonly name: "MINIMUM_TAX";
28
+ readonly version = "1.0.0";
29
+ validateParams(params: unknown): ValidationResult;
30
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
31
+ }
32
+
33
+ declare class ThresholdModel extends BaseModel {
34
+ readonly name: "THRESHOLD_BASED";
35
+ readonly version = "1.0.0";
36
+ validateParams(params: unknown): ValidationResult;
37
+ calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
38
+ }
39
+
40
+ declare class FixedAmountModel extends BaseModel {
41
+ readonly name: "FIXED_AMOUNT";
42
+ readonly version = "1.0.0";
43
+ validateParams(params: unknown): ValidationResult;
44
+ calculate(_input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number;
45
+ }
46
+
47
+ declare class CompositeModel extends BaseModel {
48
+ readonly name: "COMPOSITE";
49
+ readonly version = "1.0.0";
50
+ validateParams(params: unknown): ValidationResult;
51
+ calculate(input: Record<string, unknown>, matchedRule: Readonly<Rule>, params: unknown): number;
52
+ }
53
+
54
+ type FiscalJurisdiction = 'NATIONAL' | 'REGIONAL' | 'MUNICIPAL';
55
+
56
+ type FiscalCalculationModel = 'FLAT_RATE' | 'PROGRESSIVE_BRACKET' | 'MINIMUM_TAX' | 'THRESHOLD_BASED' | 'FIXED_AMOUNT' | 'COMPOSITE' | 'META_INHIBITION' | 'META_SUBSTITUTION' | 'META_SHORT_CIRCUIT';
57
+
58
+ interface FlatRateParams {
59
+ readonly rate: number;
60
+ readonly base: string;
61
+ }
62
+ interface BracketParams {
63
+ readonly base: string;
64
+ readonly brackets: ReadonlyArray<{
65
+ readonly from: number;
66
+ readonly to: number | null;
67
+ readonly rate: number;
68
+ }>;
69
+ }
70
+ interface MinimumTaxParams {
71
+ readonly rate: number;
72
+ readonly base: string;
73
+ readonly minimum: number;
74
+ }
75
+ interface ThresholdParams {
76
+ readonly base: string;
77
+ readonly threshold: number;
78
+ readonly rate: number;
79
+ readonly above_only: boolean;
80
+ }
81
+ interface FixedAmountParams {
82
+ readonly amount: number;
83
+ readonly currency: string;
84
+ }
85
+ interface CompositeParams {
86
+ readonly steps: ReadonlyArray<{
87
+ readonly model: string;
88
+ readonly params: unknown;
89
+ readonly label?: string | undefined;
90
+ }>;
91
+ readonly aggregation: 'SUM' | 'MAX' | 'MIN';
92
+ }
93
+
94
+ type FiscalScope = 'GLOBAL' | 'ORGANIZATION' | 'USER';
95
+ interface FiscalRule extends Rule {
96
+ readonly model: FiscalCalculationModel;
97
+ readonly jurisdiction: FiscalJurisdiction;
98
+ readonly scope: FiscalScope;
99
+ readonly country: string;
100
+ readonly category: string;
101
+ readonly params: FlatRateParams | BracketParams | MinimumTaxParams | ThresholdParams | FixedAmountParams | CompositeParams;
102
+ }
103
+
104
+ declare class JurisdictionResolver {
105
+ static resolve(jurisdiction: FiscalJurisdiction, scope: FiscalScope): number;
106
+ }
107
+
108
+ declare class ScopeResolver {
109
+ static getMultiplier(scope: FiscalScope): number;
110
+ }
111
+
112
+ declare class FiscalRuleValidator {
113
+ static validate(rule: unknown): {
114
+ valid: boolean;
115
+ errors: string[];
116
+ };
117
+ }
118
+
119
+ declare class ParamsValidator {
120
+ static validateFlatRate(params: unknown): ValidationResult;
121
+ static validateMinimumTax(params: unknown): ValidationResult;
122
+ static validateThreshold(params: unknown): ValidationResult;
123
+ static validateFixedAmount(params: unknown): ValidationResult;
124
+ }
125
+
126
+ export { type BracketParams, CompositeModel, type CompositeParams, type FiscalCalculationModel, type FiscalJurisdiction, FiscalPlugin, type FiscalRule, FiscalRuleValidator, type FiscalScope, FixedAmountModel, type FixedAmountParams, FlatRateModel, type FlatRateParams, JurisdictionResolver, MinimumTaxModel, type MinimumTaxParams, ParamsValidator, ProgressiveBracketModel, ScopeResolver, ThresholdModel, type ThresholdParams };
package/dist/index.js ADDED
@@ -0,0 +1,329 @@
1
+ // src/FiscalPlugin.ts
2
+ import { BasePlugin } from "@run-iq/plugin-sdk";
3
+
4
+ // src/jurisdiction/JurisdictionResolver.ts
5
+ var JURISDICTION_BASE = {
6
+ NATIONAL: 3e3,
7
+ REGIONAL: 2e3,
8
+ MUNICIPAL: 1e3
9
+ };
10
+ var SCOPE_MULTIPLIER = {
11
+ GLOBAL: 1,
12
+ ORGANIZATION: 1.1,
13
+ USER: 1.2
14
+ };
15
+ var JurisdictionResolver = class {
16
+ static resolve(jurisdiction, scope) {
17
+ const base = JURISDICTION_BASE[jurisdiction];
18
+ const multiplier = SCOPE_MULTIPLIER[scope];
19
+ return Math.round(base * multiplier);
20
+ }
21
+ };
22
+
23
+ // src/models/FlatRateModel.ts
24
+ import Decimal from "decimal.js";
25
+ import { BaseModel, SchemaValidator } from "@run-iq/plugin-sdk";
26
+ var FlatRateModel = class extends BaseModel {
27
+ name = "FLAT_RATE";
28
+ version = "1.0.0";
29
+ validateParams(params) {
30
+ return SchemaValidator.validate(params, {
31
+ rate: { type: "number", min: 0, max: 1 },
32
+ base: { type: "string" }
33
+ });
34
+ }
35
+ calculate(input, _matchedRule, params) {
36
+ const p = params;
37
+ const baseValue = new Decimal(String(input[p.base] ?? 0));
38
+ const rate = new Decimal(String(p.rate));
39
+ return baseValue.mul(rate).toNumber();
40
+ }
41
+ };
42
+
43
+ // src/models/ProgressiveBracketModel.ts
44
+ import Decimal2 from "decimal.js";
45
+ import { BaseModel as BaseModel2 } from "@run-iq/plugin-sdk";
46
+ var ProgressiveBracketModel = class extends BaseModel2 {
47
+ name = "PROGRESSIVE_BRACKET";
48
+ version = "1.0.0";
49
+ validateParams(params) {
50
+ if (params === null || typeof params !== "object") {
51
+ return { valid: false, errors: ["params must be an object"] };
52
+ }
53
+ const p = params;
54
+ const errors = [];
55
+ if (typeof p["base"] !== "string") {
56
+ errors.push('"base" must be a string');
57
+ }
58
+ if (!Array.isArray(p["brackets"]) || p["brackets"].length === 0) {
59
+ errors.push('"brackets" must be a non-empty array');
60
+ }
61
+ return errors.length > 0 ? { valid: false, errors } : { valid: true };
62
+ }
63
+ calculate(input, _matchedRule, params) {
64
+ const p = params;
65
+ const baseValue = new Decimal2(String(input[p.base] ?? 0));
66
+ let total = new Decimal2(0);
67
+ for (const bracket of p.brackets) {
68
+ const from = new Decimal2(String(bracket.from));
69
+ const to = bracket.to !== null ? new Decimal2(String(bracket.to)) : null;
70
+ const rate = new Decimal2(String(bracket.rate));
71
+ if (baseValue.lte(from)) {
72
+ break;
73
+ }
74
+ const taxableInBracket = to !== null ? Decimal2.min(baseValue, to).minus(from) : baseValue.minus(from);
75
+ if (taxableInBracket.gt(0)) {
76
+ total = total.plus(taxableInBracket.mul(rate));
77
+ }
78
+ }
79
+ return total.toNumber();
80
+ }
81
+ };
82
+
83
+ // src/models/MinimumTaxModel.ts
84
+ import Decimal3 from "decimal.js";
85
+ import { BaseModel as BaseModel3, SchemaValidator as SchemaValidator2 } from "@run-iq/plugin-sdk";
86
+ var MinimumTaxModel = class extends BaseModel3 {
87
+ name = "MINIMUM_TAX";
88
+ version = "1.0.0";
89
+ validateParams(params) {
90
+ return SchemaValidator2.validate(params, {
91
+ rate: { type: "number", min: 0, max: 1 },
92
+ base: { type: "string" },
93
+ minimum: { type: "number", min: 0 }
94
+ });
95
+ }
96
+ calculate(input, _matchedRule, params) {
97
+ const p = params;
98
+ const baseValue = new Decimal3(String(input[p.base] ?? 0));
99
+ const rate = new Decimal3(String(p.rate));
100
+ const minimum = new Decimal3(String(p.minimum));
101
+ const computed = baseValue.mul(rate);
102
+ return Decimal3.max(computed, minimum).toNumber();
103
+ }
104
+ };
105
+
106
+ // src/models/ThresholdModel.ts
107
+ import Decimal4 from "decimal.js";
108
+ import { BaseModel as BaseModel4, SchemaValidator as SchemaValidator3 } from "@run-iq/plugin-sdk";
109
+ var ThresholdModel = class extends BaseModel4 {
110
+ name = "THRESHOLD_BASED";
111
+ version = "1.0.0";
112
+ validateParams(params) {
113
+ return SchemaValidator3.validate(params, {
114
+ base: { type: "string" },
115
+ threshold: { type: "number", min: 0 },
116
+ rate: { type: "number", min: 0, max: 1 },
117
+ above_only: { type: "boolean" }
118
+ });
119
+ }
120
+ calculate(input, _matchedRule, params) {
121
+ const p = params;
122
+ const baseValue = new Decimal4(String(input[p.base] ?? 0));
123
+ const threshold = new Decimal4(String(p.threshold));
124
+ const rate = new Decimal4(String(p.rate));
125
+ if (baseValue.lte(threshold)) {
126
+ return 0;
127
+ }
128
+ if (p.above_only) {
129
+ return baseValue.minus(threshold).mul(rate).toNumber();
130
+ }
131
+ return baseValue.mul(rate).toNumber();
132
+ }
133
+ };
134
+
135
+ // src/models/FixedAmountModel.ts
136
+ import { BaseModel as BaseModel5, SchemaValidator as SchemaValidator4 } from "@run-iq/plugin-sdk";
137
+ var FixedAmountModel = class extends BaseModel5 {
138
+ name = "FIXED_AMOUNT";
139
+ version = "1.0.0";
140
+ validateParams(params) {
141
+ return SchemaValidator4.validate(params, {
142
+ amount: { type: "number", min: 0 },
143
+ currency: { type: "string" }
144
+ });
145
+ }
146
+ calculate(_input, _matchedRule, params) {
147
+ const p = params;
148
+ return p.amount;
149
+ }
150
+ };
151
+
152
+ // src/models/CompositeModel.ts
153
+ import Decimal5 from "decimal.js";
154
+ import { BaseModel as BaseModel6 } from "@run-iq/plugin-sdk";
155
+ var SUB_MODELS = {
156
+ FLAT_RATE: new FlatRateModel(),
157
+ PROGRESSIVE_BRACKET: new ProgressiveBracketModel(),
158
+ MINIMUM_TAX: new MinimumTaxModel(),
159
+ THRESHOLD_BASED: new ThresholdModel(),
160
+ FIXED_AMOUNT: new FixedAmountModel()
161
+ };
162
+ var CompositeModel = class extends BaseModel6 {
163
+ name = "COMPOSITE";
164
+ version = "1.0.0";
165
+ validateParams(params) {
166
+ if (params === null || typeof params !== "object") {
167
+ return { valid: false, errors: ["params must be an object"] };
168
+ }
169
+ const p = params;
170
+ const errors = [];
171
+ if (!Array.isArray(p["steps"]) || p["steps"].length === 0) {
172
+ errors.push('"steps" must be a non-empty array');
173
+ }
174
+ const agg = p["aggregation"];
175
+ if (agg !== "SUM" && agg !== "MAX" && agg !== "MIN") {
176
+ errors.push('"aggregation" must be SUM, MAX, or MIN');
177
+ }
178
+ return errors.length > 0 ? { valid: false, errors } : { valid: true };
179
+ }
180
+ calculate(input, matchedRule, params) {
181
+ const p = params;
182
+ const contributions = [];
183
+ for (const step of p.steps) {
184
+ const subModel = SUB_MODELS[step.model];
185
+ if (!subModel) {
186
+ continue;
187
+ }
188
+ const value = subModel.calculate(input, matchedRule, step.params);
189
+ contributions.push(new Decimal5(String(value)));
190
+ }
191
+ if (contributions.length === 0) {
192
+ return 0;
193
+ }
194
+ switch (p.aggregation) {
195
+ case "SUM":
196
+ return contributions.reduce((acc, v) => acc.plus(v), new Decimal5(0)).toNumber();
197
+ case "MAX":
198
+ return Decimal5.max(...contributions).toNumber();
199
+ case "MIN":
200
+ return Decimal5.min(...contributions).toNumber();
201
+ }
202
+ }
203
+ };
204
+
205
+ // src/FiscalPlugin.ts
206
+ var FiscalPlugin = class extends BasePlugin {
207
+ name = "@run-iq/plugin-fiscal";
208
+ version = "0.1.0";
209
+ models = [
210
+ new FlatRateModel(),
211
+ new ProgressiveBracketModel(),
212
+ new MinimumTaxModel(),
213
+ new ThresholdModel(),
214
+ new FixedAmountModel(),
215
+ new CompositeModel()
216
+ ];
217
+ beforeEvaluate(input, rules) {
218
+ const fiscalRules = rules;
219
+ const resolvedRules = fiscalRules.map((rule) => ({
220
+ ...rule,
221
+ priority: JurisdictionResolver.resolve(rule.jurisdiction, rule.scope)
222
+ }));
223
+ const country = input.meta.context?.["country"];
224
+ const filteredRules = country ? resolvedRules.filter((r) => r.country === country) : resolvedRules;
225
+ return {
226
+ ...input,
227
+ data: {
228
+ ...input.data,
229
+ _resolvedRules: filteredRules
230
+ }
231
+ };
232
+ }
233
+ afterEvaluate(_input, result) {
234
+ const fiscalBreakdown = {};
235
+ for (const item of result.breakdown) {
236
+ const rule = result.appliedRules.find((r) => r.id === item.ruleId);
237
+ const category = rule?.category ?? "unknown";
238
+ fiscalBreakdown[category] = (fiscalBreakdown[category] ?? 0) + item.contribution;
239
+ }
240
+ return {
241
+ ...result,
242
+ meta: { ...result.meta, fiscalBreakdown }
243
+ };
244
+ }
245
+ };
246
+
247
+ // src/jurisdiction/ScopeResolver.ts
248
+ var SCOPE_MULTIPLIER2 = {
249
+ GLOBAL: 1,
250
+ ORGANIZATION: 1.1,
251
+ USER: 1.2
252
+ };
253
+ var ScopeResolver = class {
254
+ static getMultiplier(scope) {
255
+ return SCOPE_MULTIPLIER2[scope];
256
+ }
257
+ };
258
+
259
+ // src/validators/FiscalRuleValidator.ts
260
+ var VALID_JURISDICTIONS = ["NATIONAL", "REGIONAL", "MUNICIPAL"];
261
+ var VALID_SCOPES = ["GLOBAL", "ORGANIZATION", "USER"];
262
+ var FiscalRuleValidator = class {
263
+ static validate(rule) {
264
+ const errors = [];
265
+ if (rule === null || typeof rule !== "object") {
266
+ return { valid: false, errors: ["rule must be an object"] };
267
+ }
268
+ const r = rule;
269
+ if (!r.jurisdiction || !VALID_JURISDICTIONS.includes(r.jurisdiction)) {
270
+ errors.push(`jurisdiction must be one of: ${VALID_JURISDICTIONS.join(", ")}`);
271
+ }
272
+ if (!r.scope || !VALID_SCOPES.includes(r.scope)) {
273
+ errors.push(`scope must be one of: ${VALID_SCOPES.join(", ")}`);
274
+ }
275
+ if (typeof r.country !== "string" || r.country.length === 0) {
276
+ errors.push("country must be a non-empty string");
277
+ }
278
+ if (typeof r.category !== "string" || r.category.length === 0) {
279
+ errors.push("category must be a non-empty string");
280
+ }
281
+ return { valid: errors.length === 0, errors };
282
+ }
283
+ };
284
+
285
+ // src/validators/ParamsValidator.ts
286
+ import { SchemaValidator as SchemaValidator5 } from "@run-iq/plugin-sdk";
287
+ var ParamsValidator = class {
288
+ static validateFlatRate(params) {
289
+ return SchemaValidator5.validate(params, {
290
+ rate: { type: "number", min: 0, max: 1 },
291
+ base: { type: "string" }
292
+ });
293
+ }
294
+ static validateMinimumTax(params) {
295
+ return SchemaValidator5.validate(params, {
296
+ rate: { type: "number", min: 0, max: 1 },
297
+ base: { type: "string" },
298
+ minimum: { type: "number", min: 0 }
299
+ });
300
+ }
301
+ static validateThreshold(params) {
302
+ return SchemaValidator5.validate(params, {
303
+ base: { type: "string" },
304
+ threshold: { type: "number", min: 0 },
305
+ rate: { type: "number", min: 0, max: 1 },
306
+ above_only: { type: "boolean" }
307
+ });
308
+ }
309
+ static validateFixedAmount(params) {
310
+ return SchemaValidator5.validate(params, {
311
+ amount: { type: "number", min: 0 },
312
+ currency: { type: "string" }
313
+ });
314
+ }
315
+ };
316
+ export {
317
+ CompositeModel,
318
+ FiscalPlugin,
319
+ FiscalRuleValidator,
320
+ FixedAmountModel,
321
+ FlatRateModel,
322
+ JurisdictionResolver,
323
+ MinimumTaxModel,
324
+ ParamsValidator,
325
+ ProgressiveBracketModel,
326
+ ScopeResolver,
327
+ ThresholdModel
328
+ };
329
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/FiscalPlugin.ts","../src/jurisdiction/JurisdictionResolver.ts","../src/models/FlatRateModel.ts","../src/models/ProgressiveBracketModel.ts","../src/models/MinimumTaxModel.ts","../src/models/ThresholdModel.ts","../src/models/FixedAmountModel.ts","../src/models/CompositeModel.ts","../src/jurisdiction/ScopeResolver.ts","../src/validators/FiscalRuleValidator.ts","../src/validators/ParamsValidator.ts"],"sourcesContent":["import { BasePlugin } from '@run-iq/plugin-sdk';\nimport type { EvaluationInput, EvaluationResult, Rule, CalculationModel } from '@run-iq/core';\nimport type { FiscalRule } from './types/fiscal-rule.js';\nimport { JurisdictionResolver } from './jurisdiction/JurisdictionResolver.js';\nimport { FlatRateModel } from './models/FlatRateModel.js';\nimport { ProgressiveBracketModel } from './models/ProgressiveBracketModel.js';\nimport { MinimumTaxModel } from './models/MinimumTaxModel.js';\nimport { ThresholdModel } from './models/ThresholdModel.js';\nimport { FixedAmountModel } from './models/FixedAmountModel.js';\nimport { CompositeModel } from './models/CompositeModel.js';\n\nexport class FiscalPlugin extends BasePlugin {\n readonly name = '@run-iq/plugin-fiscal' as const;\n readonly version = '0.1.0';\n\n readonly models: CalculationModel[] = [\n new FlatRateModel(),\n new ProgressiveBracketModel(),\n new MinimumTaxModel(),\n new ThresholdModel(),\n new FixedAmountModel(),\n new CompositeModel(),\n ];\n\n override beforeEvaluate(input: EvaluationInput, rules: ReadonlyArray<Rule>): EvaluationInput {\n const fiscalRules = rules as ReadonlyArray<FiscalRule>;\n\n // 1. Resolve priorities from jurisdiction + scope\n const resolvedRules = fiscalRules.map((rule) => ({\n ...rule,\n priority: JurisdictionResolver.resolve(rule.jurisdiction, rule.scope),\n }));\n\n // 2. Filter by country if provided in context\n const country = input.meta.context?.['country'] as string | undefined;\n const filteredRules = country\n ? resolvedRules.filter((r) => r.country === country)\n : resolvedRules;\n\n // IMMUTABLE — return new values\n return {\n ...input,\n data: {\n ...input.data,\n _resolvedRules: filteredRules,\n },\n };\n }\n\n override afterEvaluate(_input: EvaluationInput, result: EvaluationResult): EvaluationResult {\n // Enrich result with fiscal breakdown by category\n const fiscalBreakdown: Record<string, number> = {};\n\n for (const item of result.breakdown) {\n const rule = result.appliedRules.find((r) => r.id === item.ruleId) as FiscalRule | undefined;\n const category = rule?.category ?? 'unknown';\n fiscalBreakdown[category] = (fiscalBreakdown[category] ?? 0) + (item.contribution as number);\n }\n\n return {\n ...result,\n meta: { ...result.meta, fiscalBreakdown },\n };\n }\n}\n","import type { FiscalJurisdiction } from '../types/jurisdiction.js';\nimport type { FiscalScope } from '../types/fiscal-rule.js';\n\nconst JURISDICTION_BASE: Record<FiscalJurisdiction, number> = {\n NATIONAL: 3000,\n REGIONAL: 2000,\n MUNICIPAL: 1000,\n};\n\nconst SCOPE_MULTIPLIER: Record<FiscalScope, number> = {\n GLOBAL: 1.0,\n ORGANIZATION: 1.1,\n USER: 1.2,\n};\n\nexport class JurisdictionResolver {\n static resolve(jurisdiction: FiscalJurisdiction, scope: FiscalScope): number {\n const base = JURISDICTION_BASE[jurisdiction];\n const multiplier = SCOPE_MULTIPLIER[scope];\n return Math.round(base * multiplier);\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { FlatRateParams } from '../types/params.js';\n\nexport class FlatRateModel extends BaseModel {\n readonly name = 'FLAT_RATE' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as FlatRateParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const rate = new Decimal(String(p.rate));\n return baseValue.mul(rate).toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { BracketParams } from '../types/params.js';\n\nexport class ProgressiveBracketModel extends BaseModel {\n readonly name = 'PROGRESSIVE_BRACKET' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n if (params === null || typeof params !== 'object') {\n return { valid: false, errors: ['params must be an object'] };\n }\n const p = params as Record<string, unknown>;\n const errors: string[] = [];\n\n if (typeof p['base'] !== 'string') {\n errors.push('\"base\" must be a string');\n }\n if (!Array.isArray(p['brackets']) || p['brackets'].length === 0) {\n errors.push('\"brackets\" must be a non-empty array');\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true };\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as BracketParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n let total = new Decimal(0);\n\n for (const bracket of p.brackets) {\n const from = new Decimal(String(bracket.from));\n const to = bracket.to !== null ? new Decimal(String(bracket.to)) : null;\n const rate = new Decimal(String(bracket.rate));\n\n if (baseValue.lte(from)) {\n break;\n }\n\n const taxableInBracket =\n to !== null ? Decimal.min(baseValue, to).minus(from) : baseValue.minus(from);\n\n if (taxableInBracket.gt(0)) {\n total = total.plus(taxableInBracket.mul(rate));\n }\n }\n\n return total.toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { MinimumTaxParams } from '../types/params.js';\n\nexport class MinimumTaxModel extends BaseModel {\n readonly name = 'MINIMUM_TAX' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n minimum: { type: 'number', min: 0 },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as MinimumTaxParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const rate = new Decimal(String(p.rate));\n const minimum = new Decimal(String(p.minimum));\n const computed = baseValue.mul(rate);\n return Decimal.max(computed, minimum).toNumber();\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { ThresholdParams } from '../types/params.js';\n\nexport class ThresholdModel extends BaseModel {\n readonly name = 'THRESHOLD_BASED' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n base: { type: 'string' },\n threshold: { type: 'number', min: 0 },\n rate: { type: 'number', min: 0, max: 1 },\n above_only: { type: 'boolean' },\n });\n }\n\n calculate(input: Record<string, unknown>, _matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as ThresholdParams;\n const baseValue = new Decimal(String(input[p.base] ?? 0));\n const threshold = new Decimal(String(p.threshold));\n const rate = new Decimal(String(p.rate));\n\n if (baseValue.lte(threshold)) {\n return 0;\n }\n\n if (p.above_only) {\n return baseValue.minus(threshold).mul(rate).toNumber();\n }\n\n return baseValue.mul(rate).toNumber();\n }\n}\n","import { BaseModel, SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule } from '@run-iq/core';\nimport type { FixedAmountParams } from '../types/params.js';\n\nexport class FixedAmountModel extends BaseModel {\n readonly name = 'FIXED_AMOUNT' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n amount: { type: 'number', min: 0 },\n currency: { type: 'string' },\n });\n }\n\n calculate(\n _input: Record<string, unknown>,\n _matchedRule: Readonly<Rule>,\n params: unknown,\n ): number {\n const p = params as FixedAmountParams;\n return p.amount;\n }\n}\n","import Decimal from 'decimal.js';\nimport { BaseModel } from '@run-iq/plugin-sdk';\nimport type { ValidationResult, Rule, CalculationModel } from '@run-iq/core';\nimport type { CompositeParams } from '../types/params.js';\nimport { FlatRateModel } from './FlatRateModel.js';\nimport { ProgressiveBracketModel } from './ProgressiveBracketModel.js';\nimport { MinimumTaxModel } from './MinimumTaxModel.js';\nimport { ThresholdModel } from './ThresholdModel.js';\nimport { FixedAmountModel } from './FixedAmountModel.js';\n\nconst SUB_MODELS: Record<string, CalculationModel> = {\n FLAT_RATE: new FlatRateModel(),\n PROGRESSIVE_BRACKET: new ProgressiveBracketModel(),\n MINIMUM_TAX: new MinimumTaxModel(),\n THRESHOLD_BASED: new ThresholdModel(),\n FIXED_AMOUNT: new FixedAmountModel(),\n};\n\nexport class CompositeModel extends BaseModel {\n readonly name = 'COMPOSITE' as const;\n readonly version = '1.0.0';\n\n validateParams(params: unknown): ValidationResult {\n if (params === null || typeof params !== 'object') {\n return { valid: false, errors: ['params must be an object'] };\n }\n const p = params as Record<string, unknown>;\n const errors: string[] = [];\n\n if (!Array.isArray(p['steps']) || p['steps'].length === 0) {\n errors.push('\"steps\" must be a non-empty array');\n }\n\n const agg = p['aggregation'];\n if (agg !== 'SUM' && agg !== 'MAX' && agg !== 'MIN') {\n errors.push('\"aggregation\" must be SUM, MAX, or MIN');\n }\n\n return errors.length > 0 ? { valid: false, errors } : { valid: true };\n }\n\n calculate(input: Record<string, unknown>, matchedRule: Readonly<Rule>, params: unknown): number {\n const p = params as CompositeParams;\n const contributions: Decimal[] = [];\n\n for (const step of p.steps) {\n const subModel = SUB_MODELS[step.model];\n if (!subModel) {\n continue;\n }\n const value = subModel.calculate(input, matchedRule, step.params);\n contributions.push(new Decimal(String(value)));\n }\n\n if (contributions.length === 0) {\n return 0;\n }\n\n switch (p.aggregation) {\n case 'SUM':\n return contributions.reduce((acc, v) => acc.plus(v), new Decimal(0)).toNumber();\n case 'MAX':\n return Decimal.max(...contributions).toNumber();\n case 'MIN':\n return Decimal.min(...contributions).toNumber();\n }\n }\n}\n","import type { FiscalScope } from '../types/fiscal-rule.js';\n\nconst SCOPE_MULTIPLIER: Record<FiscalScope, number> = {\n GLOBAL: 1.0,\n ORGANIZATION: 1.1,\n USER: 1.2,\n};\n\nexport class ScopeResolver {\n static getMultiplier(scope: FiscalScope): number {\n return SCOPE_MULTIPLIER[scope];\n }\n}\n","import type { FiscalRule } from '../types/fiscal-rule.js';\n\nconst VALID_JURISDICTIONS = ['NATIONAL', 'REGIONAL', 'MUNICIPAL'];\nconst VALID_SCOPES = ['GLOBAL', 'ORGANIZATION', 'USER'];\n\nexport class FiscalRuleValidator {\n static validate(rule: unknown): { valid: boolean; errors: string[] } {\n const errors: string[] = [];\n if (rule === null || typeof rule !== 'object') {\n return { valid: false, errors: ['rule must be an object'] };\n }\n\n const r = rule as Partial<FiscalRule>;\n\n if (!r.jurisdiction || !VALID_JURISDICTIONS.includes(r.jurisdiction)) {\n errors.push(`jurisdiction must be one of: ${VALID_JURISDICTIONS.join(', ')}`);\n }\n if (!r.scope || !VALID_SCOPES.includes(r.scope)) {\n errors.push(`scope must be one of: ${VALID_SCOPES.join(', ')}`);\n }\n if (typeof r.country !== 'string' || r.country.length === 0) {\n errors.push('country must be a non-empty string');\n }\n if (typeof r.category !== 'string' || r.category.length === 0) {\n errors.push('category must be a non-empty string');\n }\n\n return { valid: errors.length === 0, errors };\n }\n}\n","import { SchemaValidator } from '@run-iq/plugin-sdk';\nimport type { ValidationResult } from '@run-iq/core';\n\nexport class ParamsValidator {\n static validateFlatRate(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n });\n }\n\n static validateMinimumTax(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n rate: { type: 'number', min: 0, max: 1 },\n base: { type: 'string' },\n minimum: { type: 'number', min: 0 },\n });\n }\n\n static validateThreshold(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n base: { type: 'string' },\n threshold: { type: 'number', min: 0 },\n rate: { type: 'number', min: 0, max: 1 },\n above_only: { type: 'boolean' },\n });\n }\n\n static validateFixedAmount(params: unknown): ValidationResult {\n return SchemaValidator.validate(params, {\n amount: { type: 'number', min: 0 },\n currency: { type: 'string' },\n });\n }\n}\n"],"mappings":"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","names":["Decimal","BaseModel","Decimal","BaseModel","SchemaValidator","Decimal","BaseModel","SchemaValidator","BaseModel","SchemaValidator","Decimal","BaseModel","BaseModel","Decimal","SCOPE_MULTIPLIER","SchemaValidator"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@run-iq/plugin-fiscal",
3
+ "version": "0.1.0",
4
+ "description": "Fiscal domain plugin for PPE — tax calculation models",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": ["dist"],
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "test": "vitest run",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "eslint src/ tests/ && prettier --check src/ tests/",
27
+ "lint:fix": "eslint src/ tests/ --fix && prettier --write src/ tests/"
28
+ },
29
+ "peerDependencies": {
30
+ "@run-iq/core": "^0.1.0",
31
+ "@run-iq/plugin-sdk": "^0.1.0"
32
+ },
33
+ "dependencies": {
34
+ "decimal.js": "^10.4.3"
35
+ },
36
+ "devDependencies": {
37
+ "@run-iq/dsl-jsonlogic": "^0.1.0",
38
+ "@types/node": "^20.11.0",
39
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
40
+ "@typescript-eslint/parser": "^7.0.0",
41
+ "eslint": "^8.57.0",
42
+ "prettier": "^3.2.0",
43
+ "tsup": "^8.0.0",
44
+ "typescript": "^5.4.0",
45
+ "vitest": "^1.3.0"
46
+ },
47
+ "author": "Abdou-Raouf ATARMLA",
48
+ "license": "SEE LICENSE IN LICENSE",
49
+ "engines": {
50
+ "node": ">=20.0.0"
51
+ }
52
+ }