@scrawn/core 0.0.3 → 0.0.6
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/dist/config.d.ts +41 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/core/auth/apiKeyAuth.d.ts +58 -0
- package/dist/core/auth/apiKeyAuth.d.ts.map +1 -0
- package/dist/core/auth/apiKeyAuth.js +66 -0
- package/dist/core/auth/apiKeyAuth.js.map +1 -0
- package/dist/core/auth/baseAuth.d.ts +70 -0
- package/dist/core/auth/baseAuth.d.ts.map +1 -0
- package/dist/core/auth/baseAuth.js +22 -0
- package/dist/core/auth/baseAuth.js.map +1 -0
- package/dist/core/errors/index.d.ts +192 -0
- package/dist/core/errors/index.d.ts.map +1 -0
- package/dist/core/errors/index.js +280 -0
- package/dist/core/errors/index.js.map +1 -0
- package/dist/core/grpc/callContext.d.ts +18 -0
- package/dist/core/grpc/callContext.d.ts.map +1 -0
- package/dist/core/grpc/callContext.js +35 -0
- package/dist/core/grpc/callContext.js.map +1 -0
- package/dist/core/grpc/client.d.ts +16 -0
- package/dist/core/grpc/client.d.ts.map +1 -0
- package/dist/core/grpc/client.js +30 -0
- package/dist/core/grpc/client.js.map +1 -0
- package/dist/core/grpc/index.d.ts +14 -0
- package/dist/core/grpc/index.d.ts.map +1 -0
- package/dist/core/grpc/index.js +13 -0
- package/dist/core/grpc/index.js.map +1 -0
- package/dist/core/grpc/requestBuilder.d.ts +15 -0
- package/dist/core/grpc/requestBuilder.d.ts.map +1 -0
- package/dist/core/grpc/requestBuilder.js +56 -0
- package/dist/core/grpc/requestBuilder.js.map +1 -0
- package/dist/core/grpc/streamRequestBuilder.d.ts +13 -0
- package/dist/core/grpc/streamRequestBuilder.d.ts.map +1 -0
- package/dist/core/grpc/streamRequestBuilder.js +60 -0
- package/dist/core/grpc/streamRequestBuilder.js.map +1 -0
- package/dist/core/grpc/types.d.ts +7 -0
- package/dist/core/grpc/types.d.ts.map +1 -0
- package/dist/core/grpc/types.js +2 -0
- package/dist/core/grpc/types.js.map +1 -0
- package/dist/core/pricing/builders.d.ts +157 -0
- package/dist/core/pricing/builders.d.ts.map +1 -0
- package/dist/core/pricing/builders.js +218 -0
- package/dist/core/pricing/builders.js.map +1 -0
- package/dist/core/pricing/index.d.ts +30 -0
- package/dist/core/pricing/index.d.ts.map +1 -0
- package/dist/core/pricing/index.js +32 -0
- package/dist/core/pricing/index.js.map +1 -0
- package/dist/core/pricing/resolve.d.ts +39 -0
- package/dist/core/pricing/resolve.d.ts.map +1 -0
- package/dist/core/pricing/resolve.js +50 -0
- package/dist/core/pricing/resolve.js.map +1 -0
- package/dist/core/pricing/serialize.d.ts +55 -0
- package/dist/core/pricing/serialize.d.ts.map +1 -0
- package/dist/core/pricing/serialize.js +127 -0
- package/dist/core/pricing/serialize.js.map +1 -0
- package/dist/core/pricing/types.d.ts +122 -0
- package/dist/core/pricing/types.d.ts.map +1 -0
- package/dist/core/pricing/types.js +17 -0
- package/dist/core/pricing/types.js.map +1 -0
- package/dist/core/pricing/validate.d.ts +56 -0
- package/dist/core/pricing/validate.d.ts.map +1 -0
- package/dist/core/pricing/validate.js +162 -0
- package/dist/core/pricing/validate.js.map +1 -0
- package/dist/core/scrawn.d.ts +398 -0
- package/dist/core/scrawn.d.ts.map +1 -0
- package/dist/core/scrawn.js +729 -0
- package/dist/core/scrawn.js.map +1 -0
- package/dist/core/types/auth.d.ts +31 -0
- package/dist/core/types/auth.d.ts.map +1 -0
- package/dist/core/types/auth.js +2 -0
- package/dist/core/types/auth.js.map +1 -0
- package/dist/core/types/event.d.ts +283 -0
- package/dist/core/types/event.d.ts.map +1 -0
- package/dist/core/types/event.js +143 -0
- package/dist/core/types/event.js.map +1 -0
- package/dist/gen/auth/v1/auth_grpc_pb.d.ts +3 -0
- package/dist/gen/auth/v1/auth_pb.d.ts +65 -0
- package/dist/gen/data/v1/data_grpc_pb.d.ts +5 -0
- package/dist/gen/data/v1/data_pb.d.ts +254 -0
- package/dist/gen/event/v1/event_grpc_pb.d.ts +3 -0
- package/dist/gen/event/v1/event_pb.d.ts +278 -0
- package/dist/gen/payment/v1/payment_grpc_pb.d.ts +3 -0
- package/dist/gen/payment/v1/payment_pb.d.ts +45 -0
- package/dist/gen/query/v1/query_grpc_pb.d.ts +5 -0
- package/dist/gen/query/v1/query_pb.d.ts +359 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/forkAsyncIterable.d.ts +13 -0
- package/dist/utils/forkAsyncIterable.d.ts.map +1 -0
- package/dist/utils/forkAsyncIterable.js +78 -0
- package/dist/utils/forkAsyncIterable.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +62 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/pathMatcher.d.ts +25 -0
- package/dist/utils/pathMatcher.d.ts.map +1 -0
- package/dist/utils/pathMatcher.js +46 -0
- package/dist/utils/pathMatcher.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing DSL Serialization
|
|
3
|
+
*
|
|
4
|
+
* This module converts typed pricing expression ASTs into string format
|
|
5
|
+
* that the backend can parse and evaluate.
|
|
6
|
+
*
|
|
7
|
+
* Output format examples:
|
|
8
|
+
* - Amount: 250
|
|
9
|
+
* - Tag: tag(PREMIUM_CALL)
|
|
10
|
+
* - Addition: add(100,tag(FEE),250)
|
|
11
|
+
* - Complex: add(mul(tag(PREMIUM_CALL),3),tag(EXTRA_FEE),250)
|
|
12
|
+
*
|
|
13
|
+
* The format is designed to be:
|
|
14
|
+
* - Unambiguous (parseable by the backend)
|
|
15
|
+
* - Human-readable (for debugging)
|
|
16
|
+
* - Compact (minimal whitespace, no quotes around tag names)
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Serialize a pricing expression to a string.
|
|
20
|
+
*
|
|
21
|
+
* @param expr - The expression to serialize
|
|
22
|
+
* @returns A string representation that the backend can parse
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const expr = add(mul(tag('PREMIUM'), 3), 100);
|
|
27
|
+
* const str = serializeExpr(expr);
|
|
28
|
+
* // "add(mul(tag(PREMIUM),3),100)"
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function serializeExpr(expr) {
|
|
32
|
+
switch (expr.kind) {
|
|
33
|
+
case "amount":
|
|
34
|
+
return serializeAmount(expr);
|
|
35
|
+
case "tag":
|
|
36
|
+
return serializeTag(expr);
|
|
37
|
+
case "exprRef":
|
|
38
|
+
return `expr(${expr.name})`;
|
|
39
|
+
case "op":
|
|
40
|
+
return serializeOp(expr);
|
|
41
|
+
case "inputTokens":
|
|
42
|
+
throw new Error("Cannot serialize unresolved inputTokens() placeholder. " +
|
|
43
|
+
"Token placeholders must be resolved before serialization. " +
|
|
44
|
+
"This is an SDK bug — please report it.");
|
|
45
|
+
case "outputTokens":
|
|
46
|
+
throw new Error("Cannot serialize unresolved outputTokens() placeholder. " +
|
|
47
|
+
"Token placeholders must be resolved before serialization. " +
|
|
48
|
+
"This is an SDK bug — please report it.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Serialize an amount expression.
|
|
53
|
+
* Just the integer value.
|
|
54
|
+
*/
|
|
55
|
+
function serializeAmount(expr) {
|
|
56
|
+
return expr.value.toString();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Serialize a tag expression.
|
|
60
|
+
* Format: tag(TAG_NAME)
|
|
61
|
+
* Tag names are unquoted (validation ensures valid identifier format).
|
|
62
|
+
*/
|
|
63
|
+
function serializeTag(expr) {
|
|
64
|
+
return `tag(${expr.name})`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Serialize an operation expression.
|
|
68
|
+
* Format: op(arg1,arg2,arg3,...)
|
|
69
|
+
*/
|
|
70
|
+
function serializeOp(expr) {
|
|
71
|
+
const opName = expr.op.toLowerCase();
|
|
72
|
+
const args = expr.args.map(serializeExpr).join(",");
|
|
73
|
+
return `${opName}(${args})`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Pretty-print a pricing expression with indentation.
|
|
77
|
+
* Useful for debugging and logging.
|
|
78
|
+
*
|
|
79
|
+
* @param expr - The expression to format
|
|
80
|
+
* @param indent - Number of spaces for indentation (default 2)
|
|
81
|
+
* @returns A formatted, multi-line string representation
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const expr = add(mul(tag('PREMIUM'), 3), 100);
|
|
86
|
+
* console.log(prettyPrintExpr(expr));
|
|
87
|
+
* // add(
|
|
88
|
+
* // mul(
|
|
89
|
+
* // tag(PREMIUM),
|
|
90
|
+
* // 3
|
|
91
|
+
* // ),
|
|
92
|
+
* // 100
|
|
93
|
+
* // )
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export function prettyPrintExpr(expr, indent = 2) {
|
|
97
|
+
return prettyPrintInternal(expr, 0, indent);
|
|
98
|
+
}
|
|
99
|
+
function prettyPrintInternal(expr, level, indent) {
|
|
100
|
+
const pad = " ".repeat(level * indent);
|
|
101
|
+
switch (expr.kind) {
|
|
102
|
+
case "amount":
|
|
103
|
+
return expr.value.toString();
|
|
104
|
+
case "tag":
|
|
105
|
+
return `tag(${expr.name})`;
|
|
106
|
+
case "exprRef":
|
|
107
|
+
return `expr(${expr.name})`;
|
|
108
|
+
case "inputTokens":
|
|
109
|
+
return "inputTokens()";
|
|
110
|
+
case "outputTokens":
|
|
111
|
+
return "outputTokens()";
|
|
112
|
+
case "op": {
|
|
113
|
+
const opName = expr.op.toLowerCase();
|
|
114
|
+
if (expr.args.length === 0) {
|
|
115
|
+
return `${opName}()`;
|
|
116
|
+
}
|
|
117
|
+
const args = expr.args
|
|
118
|
+
.map((arg) => {
|
|
119
|
+
const inner = prettyPrintInternal(arg, level + 1, indent);
|
|
120
|
+
return " ".repeat((level + 1) * indent) + inner;
|
|
121
|
+
})
|
|
122
|
+
.join(",\n");
|
|
123
|
+
return `${opName}(\n${args}\n${pad})`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../../src/core/pricing/serialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing DSL Types
|
|
3
|
+
*
|
|
4
|
+
* This module defines the type-safe AST for pricing expressions.
|
|
5
|
+
* The SDK builds typed expressions using these types, then serializes
|
|
6
|
+
* them to strings for the backend to parse and evaluate.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { add, mul, tag } from '@scrawn/core';
|
|
11
|
+
*
|
|
12
|
+
* // Build a pricing expression: (PREMIUM_CALL * 3) + EXTRA_FEE + 250 cents
|
|
13
|
+
* const expr = add(mul(tag('PREMIUM_CALL'), 3), tag('EXTRA_FEE'), 250);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Supported arithmetic operations for pricing expressions.
|
|
18
|
+
*/
|
|
19
|
+
export type OpType = "ADD" | "SUB" | "MUL" | "DIV";
|
|
20
|
+
/**
|
|
21
|
+
* Intellisense hint type for tag names.
|
|
22
|
+
* Tag names must be ALL CAPS with underscores only (e.g., PREMIUM_CALL, FEE, INPUT_RATE).
|
|
23
|
+
* No lowercase, digits, or hyphens allowed.
|
|
24
|
+
*
|
|
25
|
+
* This is a branded type that provides IDE hints while remaining compatible with `string`.
|
|
26
|
+
*/
|
|
27
|
+
export type TagName = Uppercase<string> & {
|
|
28
|
+
readonly __brand?: "TagName";
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* A literal amount in cents (must be an integer).
|
|
32
|
+
*/
|
|
33
|
+
export interface AmountExpr {
|
|
34
|
+
readonly kind: "amount";
|
|
35
|
+
readonly value: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A reference to a named price tag (resolved by the backend).
|
|
39
|
+
* Tag names must be ALL CAPS with underscores only (e.g., PREMIUM_CALL, FEE).
|
|
40
|
+
*
|
|
41
|
+
* @typeParam TTag - The specific tag name literal (defaults to `string` for untyped usage)
|
|
42
|
+
*/
|
|
43
|
+
export interface TagExpr<TTag extends string = string> {
|
|
44
|
+
readonly kind: "tag";
|
|
45
|
+
readonly name: TTag;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* An arithmetic operation combining multiple expressions.
|
|
49
|
+
*
|
|
50
|
+
* @typeParam TTag - The tag name type flowing through the expression tree
|
|
51
|
+
*/
|
|
52
|
+
export interface OpExpr<TTag extends string = string> {
|
|
53
|
+
readonly kind: "op";
|
|
54
|
+
readonly op: OpType;
|
|
55
|
+
readonly args: readonly PriceExpr<TTag>[];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A placeholder for the inputTokens value from an AI token usage payload.
|
|
59
|
+
* Only valid in expressions used with aiTokenStreamConsumer.
|
|
60
|
+
* Resolved SDK-side to an AmountExpr before serialization.
|
|
61
|
+
*/
|
|
62
|
+
export interface InputTokensExpr {
|
|
63
|
+
readonly kind: "inputTokens";
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A placeholder for the outputTokens value from an AI token usage payload.
|
|
67
|
+
* Only valid in expressions used with aiTokenStreamConsumer.
|
|
68
|
+
* Resolved SDK-side to an AmountExpr before serialization.
|
|
69
|
+
*/
|
|
70
|
+
export interface OutputTokensExpr {
|
|
71
|
+
readonly kind: "outputTokens";
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A reference to a persisted expression stored in the Scrawn backend.
|
|
75
|
+
* Like tags, persisted expressions have a name and resolve to a value
|
|
76
|
+
* when evaluated by the backend.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const expr = biller.expr("MY_EXPR"); // type-safe reference
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export interface ExprRef {
|
|
84
|
+
readonly kind: "exprRef";
|
|
85
|
+
readonly name: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* A wrapped pricing expression — the only type accepted by `debitExpr` fields.
|
|
89
|
+
*
|
|
90
|
+
* Created exclusively via `biller.expr()`. This wrapper ensures all expressions
|
|
91
|
+
* flow through a consistent entry point that provides type-safety for both
|
|
92
|
+
* inline expressions and persisted expression references.
|
|
93
|
+
*
|
|
94
|
+
* @typeParam TTag - The tag name type flowing through the expression tree
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* // inline expression
|
|
99
|
+
* const expr = biller.expr(mul(biller.tag("PREMIUM_CALL"), 3));
|
|
100
|
+
*
|
|
101
|
+
* // persisted expression reference
|
|
102
|
+
* const expr = biller.expr("MY_EXPR");
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export interface ScrawnExpr<TTag extends string = string> {
|
|
106
|
+
readonly _expr: PriceExpr<TTag> | ExprRef;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A pricing expression - can be a literal amount, a tag reference, an operation,
|
|
110
|
+
* a token placeholder (inputTokens/outputTokens), or a persisted expression reference.
|
|
111
|
+
*
|
|
112
|
+
* @typeParam TTag - The tag name type flowing through the expression tree
|
|
113
|
+
*/
|
|
114
|
+
export type PriceExpr<TTag extends string = string> = AmountExpr | TagExpr<TTag> | OpExpr<TTag> | InputTokensExpr | OutputTokensExpr | ExprRef;
|
|
115
|
+
/**
|
|
116
|
+
* Input type for DSL builder functions.
|
|
117
|
+
* Accepts either a PriceExpr or a raw number (interpreted as cents).
|
|
118
|
+
*
|
|
119
|
+
* @typeParam TTag - The tag name type flowing through the expression tree
|
|
120
|
+
*/
|
|
121
|
+
export type ExprInput<TTag extends string = string> = PriceExpr<TTag> | ScrawnExpr<TTag> | number;
|
|
122
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/pricing/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAE3E;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,OAAO,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACnD,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IAClD,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;CAC3C;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM;IACtD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;CAC3C;AAED;;;;;GAKG;AACH,MAAM,MAAM,SAAS,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAC9C,UAAU,GACV,OAAO,CAAC,IAAI,CAAC,GACb,MAAM,CAAC,IAAI,CAAC,GACZ,eAAe,GACf,gBAAgB,GAChB,OAAO,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,MAAM,SAAS,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing DSL Types
|
|
3
|
+
*
|
|
4
|
+
* This module defines the type-safe AST for pricing expressions.
|
|
5
|
+
* The SDK builds typed expressions using these types, then serializes
|
|
6
|
+
* them to strings for the backend to parse and evaluate.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { add, mul, tag } from '@scrawn/core';
|
|
11
|
+
*
|
|
12
|
+
* // Build a pricing expression: (PREMIUM_CALL * 3) + EXTRA_FEE + 250 cents
|
|
13
|
+
* const expr = add(mul(tag('PREMIUM_CALL'), 3), tag('EXTRA_FEE'), 250);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/pricing/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing DSL Validation
|
|
3
|
+
*
|
|
4
|
+
* This module provides light SDK-side validation for pricing expressions.
|
|
5
|
+
* The backend performs full validation; the SDK only catches obvious errors
|
|
6
|
+
* early to provide better developer experience.
|
|
7
|
+
*
|
|
8
|
+
* SDK validates:
|
|
9
|
+
* - Division by literal zero
|
|
10
|
+
* - Non-integer cents (amounts must be integers)
|
|
11
|
+
* - Non-finite numbers (NaN, Infinity)
|
|
12
|
+
* - Empty operation arguments (ops need at least 2 args)
|
|
13
|
+
* - Empty/whitespace tag names
|
|
14
|
+
* - Tag name format (must be ALL_CAPS with underscores only)
|
|
15
|
+
*
|
|
16
|
+
* SDK does NOT validate:
|
|
17
|
+
* - Tag existence (backend resolves tags)
|
|
18
|
+
* - Division by zero when divisor is a tag (backend handles)
|
|
19
|
+
* - Overflow (backend handles)
|
|
20
|
+
* - Negative results (backend handles)
|
|
21
|
+
*/
|
|
22
|
+
import type { PriceExpr } from "./types.js";
|
|
23
|
+
/**
|
|
24
|
+
* Error thrown when a pricing expression fails validation.
|
|
25
|
+
*/
|
|
26
|
+
export declare class PricingExpressionError extends Error {
|
|
27
|
+
constructor(message: string);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Validate a pricing expression.
|
|
31
|
+
* Throws PricingExpressionError if validation fails.
|
|
32
|
+
*
|
|
33
|
+
* @param expr - The expression to validate
|
|
34
|
+
* @throws PricingExpressionError if validation fails
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateExpr(expr: PriceExpr<string>): void;
|
|
37
|
+
/**
|
|
38
|
+
* Check if an expression is valid without throwing.
|
|
39
|
+
* Returns true if valid, false otherwise.
|
|
40
|
+
*
|
|
41
|
+
* @param expr - The expression to check
|
|
42
|
+
* @returns true if the expression is valid
|
|
43
|
+
*/
|
|
44
|
+
export declare function isValidExpr(expr: PriceExpr<string>): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Check if an expression tree contains any token placeholder nodes
|
|
47
|
+
* (inputTokens or outputTokens).
|
|
48
|
+
*
|
|
49
|
+
* Used to reject token placeholders in contexts where they are not valid
|
|
50
|
+
* (e.g., SDK call event payloads).
|
|
51
|
+
*
|
|
52
|
+
* @param expr - The expression to check
|
|
53
|
+
* @returns true if the expression contains any token placeholders
|
|
54
|
+
*/
|
|
55
|
+
export declare function containsTokenExpr(expr: PriceExpr<string>): boolean;
|
|
56
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/core/pricing/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAU,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,CAqB1D;AAqFD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAO5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAYlE"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pricing DSL Validation
|
|
3
|
+
*
|
|
4
|
+
* This module provides light SDK-side validation for pricing expressions.
|
|
5
|
+
* The backend performs full validation; the SDK only catches obvious errors
|
|
6
|
+
* early to provide better developer experience.
|
|
7
|
+
*
|
|
8
|
+
* SDK validates:
|
|
9
|
+
* - Division by literal zero
|
|
10
|
+
* - Non-integer cents (amounts must be integers)
|
|
11
|
+
* - Non-finite numbers (NaN, Infinity)
|
|
12
|
+
* - Empty operation arguments (ops need at least 2 args)
|
|
13
|
+
* - Empty/whitespace tag names
|
|
14
|
+
* - Tag name format (must be ALL_CAPS with underscores only)
|
|
15
|
+
*
|
|
16
|
+
* SDK does NOT validate:
|
|
17
|
+
* - Tag existence (backend resolves tags)
|
|
18
|
+
* - Division by zero when divisor is a tag (backend handles)
|
|
19
|
+
* - Overflow (backend handles)
|
|
20
|
+
* - Negative results (backend handles)
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown when a pricing expression fails validation.
|
|
24
|
+
*/
|
|
25
|
+
export class PricingExpressionError extends Error {
|
|
26
|
+
constructor(message) {
|
|
27
|
+
super(message);
|
|
28
|
+
this.name = "PricingExpressionError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Validate a pricing expression.
|
|
33
|
+
* Throws PricingExpressionError if validation fails.
|
|
34
|
+
*
|
|
35
|
+
* @param expr - The expression to validate
|
|
36
|
+
* @throws PricingExpressionError if validation fails
|
|
37
|
+
*/
|
|
38
|
+
export function validateExpr(expr) {
|
|
39
|
+
switch (expr.kind) {
|
|
40
|
+
case "amount":
|
|
41
|
+
validateAmount(expr.value);
|
|
42
|
+
break;
|
|
43
|
+
case "tag":
|
|
44
|
+
validateTagName(expr.name);
|
|
45
|
+
break;
|
|
46
|
+
case "op":
|
|
47
|
+
validateOp(expr);
|
|
48
|
+
break;
|
|
49
|
+
case "exprRef":
|
|
50
|
+
validateTagName(expr.name); // same ALL_CAPS format as tags
|
|
51
|
+
break;
|
|
52
|
+
case "inputTokens":
|
|
53
|
+
case "outputTokens":
|
|
54
|
+
// Token placeholders are valid AST nodes — no validation needed.
|
|
55
|
+
// Context-level validation (e.g., rejecting them in SDK call payloads)
|
|
56
|
+
// is handled in event.ts, not here.
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate an amount value.
|
|
62
|
+
* Must be a finite integer.
|
|
63
|
+
*/
|
|
64
|
+
function validateAmount(value) {
|
|
65
|
+
if (!Number.isFinite(value)) {
|
|
66
|
+
throw new PricingExpressionError(`Amount must be a finite number, got: ${value}`);
|
|
67
|
+
}
|
|
68
|
+
if (!Number.isInteger(value)) {
|
|
69
|
+
throw new PricingExpressionError(`Amount must be an integer (cents), got: ${value}. ` +
|
|
70
|
+
`Hint: Use cents instead of dollars (e.g., 250 instead of 2.50)`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate a tag name.
|
|
75
|
+
* Must be ALL CAPS with underscores only (e.g., PREMIUM_CALL, FEE, INPUT_RATE).
|
|
76
|
+
* No lowercase, digits, or hyphens allowed.
|
|
77
|
+
*/
|
|
78
|
+
function validateTagName(name) {
|
|
79
|
+
if (typeof name !== "string") {
|
|
80
|
+
throw new PricingExpressionError(`Tag name must be a string, got: ${typeof name}`);
|
|
81
|
+
}
|
|
82
|
+
if (name.length === 0) {
|
|
83
|
+
throw new PricingExpressionError("Tag name cannot be empty");
|
|
84
|
+
}
|
|
85
|
+
if (name.trim() !== name) {
|
|
86
|
+
throw new PricingExpressionError(`Tag name cannot have leading or trailing whitespace: "${name}"`);
|
|
87
|
+
}
|
|
88
|
+
if (name.trim().length === 0) {
|
|
89
|
+
throw new PricingExpressionError("Tag name cannot be only whitespace");
|
|
90
|
+
}
|
|
91
|
+
// Validate tag name format: ALL CAPS with underscores only
|
|
92
|
+
if (!/^[A-Z_]+$/.test(name)) {
|
|
93
|
+
throw new PricingExpressionError(`Tag name must be ALL CAPS with underscores only (e.g., PREMIUM_CALL, FEE). ` +
|
|
94
|
+
`No lowercase, digits, or hyphens allowed. Got: "${name}"`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Validate an operation expression.
|
|
99
|
+
* Must have at least 2 arguments.
|
|
100
|
+
* For division, checks for literal zero divisors.
|
|
101
|
+
*/
|
|
102
|
+
function validateOp(expr) {
|
|
103
|
+
const { op, args } = expr;
|
|
104
|
+
// Must have at least 2 arguments
|
|
105
|
+
if (args.length < 2) {
|
|
106
|
+
throw new PricingExpressionError(`Operation ${op.toLowerCase()} requires at least 2 arguments, got: ${args.length}`);
|
|
107
|
+
}
|
|
108
|
+
// Recursively validate all arguments
|
|
109
|
+
for (const arg of args) {
|
|
110
|
+
validateExpr(arg);
|
|
111
|
+
}
|
|
112
|
+
// Check for division by literal zero
|
|
113
|
+
if (op === "DIV") {
|
|
114
|
+
// Check all divisors (all args after the first)
|
|
115
|
+
for (let i = 1; i < args.length; i++) {
|
|
116
|
+
const arg = args[i];
|
|
117
|
+
if (arg.kind === "amount" && arg.value === 0) {
|
|
118
|
+
throw new PricingExpressionError(`Division by zero: divisor at position ${i + 1} is 0`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check if an expression is valid without throwing.
|
|
125
|
+
* Returns true if valid, false otherwise.
|
|
126
|
+
*
|
|
127
|
+
* @param expr - The expression to check
|
|
128
|
+
* @returns true if the expression is valid
|
|
129
|
+
*/
|
|
130
|
+
export function isValidExpr(expr) {
|
|
131
|
+
try {
|
|
132
|
+
validateExpr(expr);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if an expression tree contains any token placeholder nodes
|
|
141
|
+
* (inputTokens or outputTokens).
|
|
142
|
+
*
|
|
143
|
+
* Used to reject token placeholders in contexts where they are not valid
|
|
144
|
+
* (e.g., SDK call event payloads).
|
|
145
|
+
*
|
|
146
|
+
* @param expr - The expression to check
|
|
147
|
+
* @returns true if the expression contains any token placeholders
|
|
148
|
+
*/
|
|
149
|
+
export function containsTokenExpr(expr) {
|
|
150
|
+
switch (expr.kind) {
|
|
151
|
+
case "inputTokens":
|
|
152
|
+
case "outputTokens":
|
|
153
|
+
return true;
|
|
154
|
+
case "op":
|
|
155
|
+
return expr.args.some(containsTokenExpr);
|
|
156
|
+
case "amount":
|
|
157
|
+
case "tag":
|
|
158
|
+
case "exprRef":
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/core/pricing/validate.ts"],"names":[],"mappings":"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"}
|