@crediolabs/policy-builder-cli 0.5.4 → 1.0.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.
@@ -38,6 +38,8 @@ export async function runDeclareCommand(argv, flags) {
38
38
  args.maxAmount = pairs['max-amount'];
39
39
  if (pairs['amount-arg'] !== undefined)
40
40
  args.amountArgIndex = Number(pairs['amount-arg']);
41
+ if (pairs['amount-path'] !== undefined)
42
+ args.amountPath = parseAmountPath(pairs['amount-path']);
41
43
  if (pairs.to !== undefined) {
42
44
  args.recipients = pairs.to
43
45
  .split(',')
@@ -77,3 +79,30 @@ export async function runDeclareCommand(argv, flags) {
77
79
  }
78
80
  return data;
79
81
  }
82
+ /** `--amount-path argIndex.field[.entries]`, e.g. `0.amount` for Blend's
83
+ * `requests[].amount`, or `0.amount.3` to permit three requests.
84
+ *
85
+ * `entries` is a COUNT, not an index: every entry is capped, because a bound
86
+ * on one entry leaves the others unconstrained and the caller spends through
87
+ * an unbounded one. Split on `.` and required to be two or three segments - a
88
+ * Soroban symbol carries no dot, so a longer path is not a deeper one, it is
89
+ * a typo, and accepting it would bind a field that does not exist and deny
90
+ * every call at enforce time rather than here. */
91
+ function parseAmountPath(raw) {
92
+ const parts = raw.split('.');
93
+ if (parts.length !== 2 && parts.length !== 3) {
94
+ throw new Error(`--amount-path takes argIndex.field or argIndex.field.entries, e.g. 0.amount - got "${raw}" (${parts.length} segment(s))`);
95
+ }
96
+ const [argIndex, field, entries] = parts;
97
+ if (!/^\d+$/.test(argIndex)) {
98
+ throw new Error(`--amount-path argIndex must be a non-negative integer, got "${argIndex}"`);
99
+ }
100
+ if (entries !== undefined && !/^\d+$/.test(entries)) {
101
+ throw new Error(`--amount-path entries must be a positive integer, got "${entries}"`);
102
+ }
103
+ return {
104
+ argIndex: Number(argIndex),
105
+ field,
106
+ ...(entries !== undefined ? { elements: Number(entries) } : {}),
107
+ };
108
+ }
@@ -41,6 +41,8 @@ async function runDeclareCommand(argv, flags) {
41
41
  args.maxAmount = pairs['max-amount'];
42
42
  if (pairs['amount-arg'] !== undefined)
43
43
  args.amountArgIndex = Number(pairs['amount-arg']);
44
+ if (pairs['amount-path'] !== undefined)
45
+ args.amountPath = parseAmountPath(pairs['amount-path']);
44
46
  if (pairs.to !== undefined) {
45
47
  args.recipients = pairs.to
46
48
  .split(',')
@@ -80,3 +82,30 @@ async function runDeclareCommand(argv, flags) {
80
82
  }
81
83
  return data;
82
84
  }
85
+ /** `--amount-path argIndex.field[.entries]`, e.g. `0.amount` for Blend's
86
+ * `requests[].amount`, or `0.amount.3` to permit three requests.
87
+ *
88
+ * `entries` is a COUNT, not an index: every entry is capped, because a bound
89
+ * on one entry leaves the others unconstrained and the caller spends through
90
+ * an unbounded one. Split on `.` and required to be two or three segments - a
91
+ * Soroban symbol carries no dot, so a longer path is not a deeper one, it is
92
+ * a typo, and accepting it would bind a field that does not exist and deny
93
+ * every call at enforce time rather than here. */
94
+ function parseAmountPath(raw) {
95
+ const parts = raw.split('.');
96
+ if (parts.length !== 2 && parts.length !== 3) {
97
+ throw new Error(`--amount-path takes argIndex.field or argIndex.field.entries, e.g. 0.amount - got "${raw}" (${parts.length} segment(s))`);
98
+ }
99
+ const [argIndex, field, entries] = parts;
100
+ if (!/^\d+$/.test(argIndex)) {
101
+ throw new Error(`--amount-path argIndex must be a non-negative integer, got "${argIndex}"`);
102
+ }
103
+ if (entries !== undefined && !/^\d+$/.test(entries)) {
104
+ throw new Error(`--amount-path entries must be a positive integer, got "${entries}"`);
105
+ }
106
+ return {
107
+ argIndex: Number(argIndex),
108
+ field,
109
+ ...(entries !== undefined ? { elements: Number(entries) } : {}),
110
+ };
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crediolabs/policy-builder-cli",
3
- "version": "0.5.4",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "description": "CLI wrapper around the OZ policy-synth core (record + synthesize) for solo-dev and CI workflows.",
6
6
  "type": "module",
@@ -63,7 +63,7 @@
63
63
  "prepack": "bun run build"
64
64
  },
65
65
  "dependencies": {
66
- "@crediolabs/policy-synth": "0.5.4",
66
+ "@crediolabs/policy-synth": "1.0.0",
67
67
  "@stellar/stellar-sdk": "14.4.0",
68
68
  "zod": "3.25.76"
69
69
  },
@@ -51,6 +51,8 @@ export async function runDeclareCommand(
51
51
  }
52
52
  if (pairs['max-amount'] !== undefined) args.maxAmount = pairs['max-amount']
53
53
  if (pairs['amount-arg'] !== undefined) args.amountArgIndex = Number(pairs['amount-arg'])
54
+ if (pairs['amount-path'] !== undefined)
55
+ args.amountPath = parseAmountPath(pairs['amount-path'] as string)
54
56
  if (pairs.to !== undefined) {
55
57
  args.recipients = (pairs.to as string)
56
58
  .split(',')
@@ -89,3 +91,33 @@ export async function runDeclareCommand(
89
91
  }
90
92
  return data
91
93
  }
94
+
95
+ /** `--amount-path argIndex.field[.entries]`, e.g. `0.amount` for Blend's
96
+ * `requests[].amount`, or `0.amount.3` to permit three requests.
97
+ *
98
+ * `entries` is a COUNT, not an index: every entry is capped, because a bound
99
+ * on one entry leaves the others unconstrained and the caller spends through
100
+ * an unbounded one. Split on `.` and required to be two or three segments - a
101
+ * Soroban symbol carries no dot, so a longer path is not a deeper one, it is
102
+ * a typo, and accepting it would bind a field that does not exist and deny
103
+ * every call at enforce time rather than here. */
104
+ function parseAmountPath(raw: string): { argIndex: number; field: string; elements?: number } {
105
+ const parts = raw.split('.')
106
+ if (parts.length !== 2 && parts.length !== 3) {
107
+ throw new Error(
108
+ `--amount-path takes argIndex.field or argIndex.field.entries, e.g. 0.amount - got "${raw}" (${parts.length} segment(s))`
109
+ )
110
+ }
111
+ const [argIndex, field, entries] = parts as [string, string, string | undefined]
112
+ if (!/^\d+$/.test(argIndex)) {
113
+ throw new Error(`--amount-path argIndex must be a non-negative integer, got "${argIndex}"`)
114
+ }
115
+ if (entries !== undefined && !/^\d+$/.test(entries)) {
116
+ throw new Error(`--amount-path entries must be a positive integer, got "${entries}"`)
117
+ }
118
+ return {
119
+ argIndex: Number(argIndex),
120
+ field,
121
+ ...(entries !== undefined ? { elements: Number(entries) } : {}),
122
+ }
123
+ }