@hyperscale0/hsx 3.2.0 → 4.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/dist/src/ast.d.ts +17 -2
  4. package/dist/src/ast.d.ts.map +1 -1
  5. package/dist/src/ast.js.map +1 -1
  6. package/dist/src/cli.js +1 -1
  7. package/dist/src/compile.d.ts +6 -0
  8. package/dist/src/compile.d.ts.map +1 -1
  9. package/dist/src/compile.js +1194 -97
  10. package/dist/src/compile.js.map +1 -1
  11. package/dist/src/cost.d.ts +1 -1
  12. package/dist/src/cost.d.ts.map +1 -1
  13. package/dist/src/cost.js +52 -9
  14. package/dist/src/cost.js.map +1 -1
  15. package/dist/src/headers.d.ts +2 -2
  16. package/dist/src/headers.d.ts.map +1 -1
  17. package/dist/src/headers.js +3 -2
  18. package/dist/src/headers.js.map +1 -1
  19. package/dist/src/index.d.ts +3 -2
  20. package/dist/src/index.d.ts.map +1 -1
  21. package/dist/src/index.js.map +1 -1
  22. package/dist/src/lex.d.ts +1 -1
  23. package/dist/src/lex.d.ts.map +1 -1
  24. package/dist/src/lex.js +5 -0
  25. package/dist/src/lex.js.map +1 -1
  26. package/dist/src/parse.js +91 -5
  27. package/dist/src/parse.js.map +1 -1
  28. package/dist/src/std-bundle.d.ts.map +1 -1
  29. package/dist/src/std-bundle.js +10 -9
  30. package/dist/src/std-bundle.js.map +1 -1
  31. package/dist/src/version.d.ts +2 -2
  32. package/dist/src/version.js +2 -2
  33. package/docs/README.md +51 -27
  34. package/docs/headers.md +43 -40
  35. package/examples/cost-table.json +40 -324
  36. package/examples/library.hsx +12 -57
  37. package/package.json +7 -5
  38. package/src/ast.ts +11 -1
  39. package/src/cli.ts +1 -1
  40. package/src/compile.ts +1630 -114
  41. package/src/cost.ts +60 -16
  42. package/src/headers.ts +3 -2
  43. package/src/index.ts +12 -1
  44. package/src/lex.ts +5 -0
  45. package/src/parse.ts +87 -5
  46. package/src/std-bundle.ts +10 -9
  47. package/src/version.ts +2 -2
  48. package/std/approvals.hsx +3 -3
  49. package/std/collections.hsx +45 -4
  50. package/std/escrow.hsx +17 -8
  51. package/std/financing.hsx +292 -42
  52. package/std/insurance.hsx +4 -5
  53. package/std/lending.hsx +7 -8
  54. package/std/marketplace.hsx +90 -6
  55. package/std/money.hsx +15 -49
  56. package/std/reporting.hsx +1286 -0
  57. package/std/travel.hsx +5 -6
package/docs/README.md CHANGED
@@ -1,24 +1,41 @@
1
- # HSX 3
1
+ # HSX 4
2
2
 
3
- A program declares parties and objects from headers. Currency defaults to SAR.
4
- A party binds its account and optional role at admission. A program never carries
5
- account ids, reference filters, credentials or bank beneficiary ids.
3
+ A program declares business objects and financial instruments. Objects contain
4
+ optional metadata. Attachments expose named actions against an object.
6
5
 
7
6
  ```hsx
8
- program shop "Shop"
9
- use marketplace
7
+ program cars "Cars"
10
8
  use escrow
11
- party buyer: person
12
- party seller: business
13
- listing = marketplace.listing { seller: seller }
14
- order = marketplace.order { listing: listing, buyer: buyer }
15
- sale = escrow.hold {
16
- payer: buyer, payee: seller, for: order, accept_within: 48h
17
- fee { seller: 1% cap 750 SAR, tax: 15% }
18
- dispute { refund_after: return_verified }
9
+ object car "Cars" {
10
+ fields { make: text, model: text, year: integer }
11
+ columns: [make, model, year]
12
+ attach sale = escrow.hold { payer: actor, payee: owner, expose fund as sell }
19
13
  }
20
14
  ```
21
15
 
16
+ Every attached party parameter binds to `owner`, `actor`, or `operator`.
17
+ `owner` is the object's resolved customer or business, `actor` is the authenticated
18
+ caller, and `operator` is the program operator. A parameter with one of these
19
+ names binds by name. Other party parameters require an explicit binding.
20
+ Unbound parameters report `subject_party_unbound`. These bindings are frozen in
21
+ UDL `objects[].attachments[].parties`; no caller supplies party IDs at creation.
22
+
23
+ Object `fields` are authored metadata. `columns` names up to eight normalized
24
+ fields. An action's `subject { price: money }` declares its metadata requirement;
25
+ `subject { adapter: verification }` inherits a selected ADL declaration. The
26
+ compiler freezes the adapter identity, digest and requirements. An unavailable
27
+ declaration leaves a null snapshot and an unavailable action.
28
+
29
+ An attachment can use `rename { price: salePrice }` to separate requirements with
30
+ different meanings. Matching names must match types and constraints. The compiler
31
+ reports `subject_field_conflict` with both origins, or `subject_field_unknown` for
32
+ unknown rename sources, columns or subject expressions. Action admission reports
33
+ `subject_requirement_missing` or `subject_adapter_unbound` before dispatch.
34
+
35
+ Creation accepts `{}`. Every normalized field, including adapter requirements,
36
+ is optional at creation. Only a named action requires its subject metadata.
37
+ Use `attach` inside the object block to configure its financial instruments.
38
+
22
39
  The header defines the available policies. The company chooses percentages, amounts, durations,
23
40
  parties and typed references. `funds: sale` links the stored records through the
24
41
  library's declared reference type. References can name a child, such as
@@ -38,11 +55,11 @@ Tax binds `programTax`. Fees default to `programOperator`. Fine, recovery and
38
55
  residual destinations are party tunables. Unused `programFines` and `programCosts`
39
56
  bindings are omitted.
40
57
 
41
- Every action is public with a generated camelCase name: `createSale`,
42
- `acceptSale`. `expose sale.accept as acceptDelivery` renames it;
43
- `hide sale.refund` removes it from the public API. Visibility grants no authority.
44
- Parent and clock actions still require their executor principal. Exposure paths
45
- can name children: `hide plan.payment.refund`.
58
+ Attached actions are private unless the attachment exposes them with
59
+ `expose fund as sell`. Exposure grants no authority. Clock and parent actions
60
+ remain executor-owned. Instruments have no standalone create route: an
61
+ attachment exposes its create action by name (`expose create as finance`) or
62
+ keeps it internal. Callers create objects and run their attached actions.
46
63
 
47
64
  Accounts use cash or claim books. A move stays in one book. `account of buyer`
48
65
  aliases the default cash account; `account of self` provisions an owned account.
@@ -143,6 +160,12 @@ when disburse_to is borrower {
143
160
  }
144
161
  ```
145
162
 
163
+ `when <reference tunable> has <field>` includes its clauses only when the bound
164
+ object declares that field. The compiler checks the object's declared shape,
165
+ regardless of declaration order, and emits no runtime branch. Financing uses
166
+ this to commit marketplace orders for order-backed holds while plain money
167
+ holds need no order relation.
168
+
146
169
  `when <enum tunable> is <value>` accepts requirements, calculations, moves and
147
170
  invocations, including nested branches. The compiler emits only the selected
148
171
  clauses and preserves their order within each UDL phase. Lifecycle and actor
@@ -160,13 +183,6 @@ requires a valid hours interval. `at_most` and `greater_than` are also supported
160
183
  A refusal names the tunable. Empty `all(type)` selections lower to zero aggregates
161
184
  or no invocations, so a plan does not require a late-charge object.
162
185
 
163
- The permutation spec builds a dependency-closed program per object. It takes each
164
- enum value and the minimum, default or example value, and a large numeric value.
165
- It uses the full product through 512 cases and pair coverage above that. Invalid
166
- bound combinations must refuse with a named diagnostic. Valid cases must produce
167
- valid UDL and retain public names on every caller action. This proves compilation,
168
- not executed balances or bank settlement.
169
-
170
186
  Build with `hsx build company.hsx --out company.udl.json`; check with
171
187
  `hsx check company.hsx`; print instruction counts with `hsx cost company.hsx`.
172
188
  Print the compiler-owned object manifest with `hsx headers --json`.
@@ -175,5 +191,13 @@ The compiler API is `compile(source)`. A valid result contains `artifacts.docume
175
191
  promise of provider execution cost.
176
192
 
177
193
  The [header inventory](headers.md) is generated from the declarations. The
178
- [executable inventory](../examples/library.hsx) exercises every public object.
194
+ [object example](../examples/library.hsx) shows authenticated role bindings.
179
195
  The [playground](../playground/index.html) compiles locally in the browser.
196
+
197
+ ## Financing attachments
198
+
199
+ Financing retains its authored borrower and portfolio limits. Bind every party
200
+ parameter to a subject role and link the existing escrow and limits attachments.
201
+ No limit is inferred from object metadata.
202
+
203
+ See the complete [financing object example](../examples/library.hsx).
package/docs/headers.md CHANGED
@@ -1,44 +1,47 @@
1
1
  # Header inventory
2
2
 
3
- Each company selects library policies through typed tunables.
3
+ Attach library instruments inside authored object kinds. Each program selects policies through typed tunables.
4
+ Bind party parameters to owner, actor, operator or declared parties. Configure declared businesses per Build; staff declarations name approval authority. The authoringTemplate source is an attach fragment for an object block. Expose the chosen business action; instrument creation stays internal.
4
5
  `ref<T>[]` accepts one reference or up to 16 references as one policy. `approval` accepts a party and generates the required decision records.
5
6
 
6
- | Object | Tunables |
7
- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
8
- | money.transfer | `payer: party`, `payee: party`, `amount: money = runtime` |
9
- | money.hold | `payer: party`, `payee: party`, `amount: money = runtime` |
10
- | money.split | `payer: party`, `amount: money = runtime`, `shares: split = { programOperator: 100% }` |
11
- | money.schedule | `payer: party`, `payee: party`, `amount: money = runtime`, `count: integer(1, 366) = 12` |
12
- | money.pool | `payer: party`, `payee: party`, `target: money`, `closes: date` |
13
- | money.swap | `first: party`, `second: party`, `first_amount: money`, `second_amount: money`, `expires: date` |
14
- | money.deposit | `payer: party`, `payee: party`, `amount: money`, `expires: date`, `approval: approval` |
15
- | money.payout | `payer: party`, `payee: party`, `amount: money = runtime`, `reconcile_within: duration = 3d` |
16
- | money.metered | `payer: party`, `payee: party`, `unit_price: money`, `units: integer = 1`, `fee: fee = { seller: 0% }` |
17
- | money.batch | `payer: party`, `payee: party`, `closes: date`, `approval: approval`, `reconcile_within: duration = 3d` |
18
- | marketplace.listing | `seller: party` |
19
- | marketplace.order | `listing: ref<marketplace.listing>`, `buyer: party` |
20
- | escrow.hold | `payer: party`, `payee: party`, `for: ref<marketplace.order>`, `accept_within: duration = 48h`, `fee: fee = { seller: 0%, tax: 0% }`, `dispute: policy = { refund_after: return_verified }` |
21
- | wallet.balance | `holder: party`, `spend_limit: money = 100000 SAR` |
22
- | wallet.spend | `wallet: ref<wallet.balance>`, `payee: party` |
23
- | financing.installments | `months: integer(1, 366)`, `profit: percent`, `disburse_to: enum(funds, borrower) = funds`, `profit_earned: enum(on_payment, by_schedule, at_disbursement) = on_payment`, `apply: enum(fines_profit_principal, principal_profit, pro_rata) = fines_profit_principal`, `payoff_rebate: percent = 100%`, `down_payment: percent = 0%`, `funds: ref`, `approval: approval`, `borrower: party = party(person)`, `capital: party = programOperator`, `profit_to: party = programOperator`, `limits: ref<financing.limits> = object(financing.limits)` |
24
- | financing.late_charge | `on: ref<financing.installments>[]`, `grace: duration = 3d`, `fine: money = 50 SAR`, `cap: money = 25 SAR`, `fines_to: party = programOperator`, `costs_to: party = programOperator`, `approval: approval = programOperator`, `borrower: party = party(person)` |
25
- | financing.limits | `per_borrower: money`, `portfolio: money`, `borrower: party = party(person)`, `active_plans: integer = 1` |
26
- | financing.credit_line | `borrower: party`, `lender: party`, `limit: money`, `expires: date` |
27
- | financing.advance | `line: ref<financing.credit_line>`, `amount: money = runtime` |
28
- | lending.round | `borrower: party`, `capital: party`, `plan: ref<financing.installments> = object(financing.installments)`, `months: integer(1, 366) = 3`, `profit: percent = 3%`, `minimum_ticket: money = 100 SAR`, `investor_cap: percent = 20%`, `commitments: ref<lending.commitment> = object(lending.commitment)` |
29
- | lending.commitment | `round: ref<lending.round>`, `wallet: ref<wallet.balance>`, `investor: party = party(person)` |
30
- | lending.distribution | `round: ref<lending.round>`, `receipt: ref`, `commitments: ref<lending.commitment> = object(lending.commitment)`, `mode: enum(cash, loss) = cash`, `residual_to: party = programOperator`, `fee: percent = 1%`, `tax: percent = 15%` |
31
- | insurance.cover | `holder: party`, `insurer: party`, `commission: percent = 0%`, `covers: ref`, `premium: money = runtime` |
32
- | insurance.claim | `cover: ref<insurance.cover>`, `approved_by: approval` |
33
- | approvals.decision | `for: ref`, `approved_by: party`, `action: text = "approve"` |
34
- | collections.case | `on: ref<financing.installments>[]`, `agency: approval`, `overdue: duration = 3d`, `fee: percent = 20%` |
35
- | collections.contact | `case: ref<collections.case>[]`, `agency: party`, `max_contacts: integer = 10`, `window: duration = 30d`, `contact_from: integer(0, 23) = 8`, `contact_until: integer(1, 23) = 20`, `timezone: text = "Asia/Riyadh"`; contact_from less_than contact_until |
36
- | travel.package | `price: money`, `supplier_cost: money`, `departure: date`; supplier_cost at_most price |
37
- | travel.booking | `package: ref<travel.package>`, `buyer: party`, `supplier: approval`, `cover: ref<insurance.cover>`, `deposit: percent = 30%`, `balance_before: duration = 14d`, `confirm_within: duration = 24h`, `tax: percent = 15%`, `early_before: duration = 30d`, `middle_before: duration = 15d`, `middle_penalty: percent = 10%`, `late_penalty: percent = 30%`; early_before greater_than middle_before |
38
- | cards.cardholder | `holder: party` |
39
- | cards.card | `holder: ref<cards.cardholder>`, `spend_limit: money` |
40
- | cards.authorization | `card: ref<cards.card>`, `merchant: party`, `approval: approval` |
41
- | cards.transaction | `authorization: ref<cards.authorization>` |
42
- | cards.dispute | `transaction: ref<cards.transaction>`, `approved_by: approval`, `within: duration = 90d` |
43
- | savings.circle | `contribution: money`, `members: integer(1, 366)`, `starts: date`, `memberships: ref<savings.membership> = object(savings.membership)` |
44
- | savings.membership | `circle: ref<savings.circle>`, `member: party` |
7
+ | Instrument | Tunables |
8
+ | --- | --- |
9
+ | money.transfer | `payer: party`, `payee: party`, `amount: money = runtime` |
10
+ | money.hold | `payer: party`, `payee: party`, `amount: money = runtime` |
11
+ | money.split | `payer: party`, `amount: money = runtime`, `shares: split = { programOperator: 100% }` |
12
+ | money.schedule | `payer: party`, `payee: party`, `amount: money = runtime`, `count: integer(1, 366) = 12` |
13
+ | money.pool | `payer: party`, `payee: party`, `target: money`, `closes: date` |
14
+ | money.swap | `first: party`, `second: party`, `first_amount: money`, `second_amount: money`, `expires: date` |
15
+ | money.deposit | `payer: party`, `payee: party`, `amount: money`, `expires: date`, `approval: approval` |
16
+ | money.payout | `payer: party`, `payee: party`, `adapter: text`, `max_age: duration`, `amount: money = runtime` |
17
+ | money.metered | `payer: party`, `payee: party`, `unit_price: money`, `units: integer = 1`, `fee: fee = { seller: 0% }` |
18
+ | marketplace.listing | `seller: party` |
19
+ | marketplace.order | `listing: ref<marketplace.listing>`, `buyer: party` |
20
+ | marketplace.reservation | `listing: ref<marketplace.listing>`, `funds: ref<escrow.hold>`, `plans: ref<financing.installments>[]`, `converters: ref[]`, `buyer: party`, `seller: party`, `expires_after: duration = 48h`, `deposit: money = 1000 SAR`, `cancellation_refund: percent = 100%`, `expiry_refund: percent = 100%`, `retained_to: party = programOperator`, `operator: party = programOperator`, `competing_quotes: enum(allowed, blocked) = allowed` |
21
+ | escrow.hold | `payer: party = party(person)`, `payee: party = programOperator`, `accept_within: duration = 48h`, `fee: fee = { seller: 0%, tax: 0% }`, `dispute: policy = { refund_after: return_verified }` |
22
+ | wallet.balance | `holder: party`, `spend_limit: money = 100000 SAR` |
23
+ | wallet.spend | `wallet: ref<wallet.balance>`, `payee: party` |
24
+ | financing.installments | `months: integer(1, 366)`, `charge_limit: integer(1, 3) = 3`, `profit: percent`, `disburse_to: enum(funds, borrower) = funds`, `profit_earned: enum(on_payment, by_schedule, at_disbursement) = on_payment`, `apply: enum(fines_profit_principal, principal_profit, pro_rata) = fines_profit_principal`, `payoff_rebate: percent = 100%`, `write_off_after: duration = 90d`, `max_extension: duration = 90d`, `max_amendments: integer(0, 366) = 2`, `waiver_limit: percent = 100%`, `amendment_expiry: duration = 7d`, `payoff_quote_expiry: duration = 1h`, `allow_overdue: enum(allowed, blocked) = allowed`, `assessed_fines: enum(carry, require_waiver) = carry`, `down_payment: percent = 0%`, `funds: ref = object(escrow.hold)`, `approval: approval = programOperator`, `borrower: party = party(person)`, `capital: party = programOperator`, `share: percent = 0%`, `limits: ref<financing.limits> = object(financing.limits)` |
25
+ | financing.late_charge | `on: ref<financing.installments>[]`, `grace: duration = 3d`, `fine: money = 50 SAR`, `cap: money = 25 SAR`, `fines_to: party = programOperator`, `costs_to: party = programOperator`, `approval: approval = programOperator`, `borrower: party = party(person)` |
26
+ | financing.limits | `per_borrower: money`, `portfolio: money`, `borrower: party = party(person)`, `active_plans: integer = 1` |
27
+ | financing.credit_line | `borrower: party`, `lender: party`, `limit: money`, `expires: date` |
28
+ | financing.advance | `line: ref<financing.credit_line>`, `amount: money = runtime` |
29
+ | lending.round | `borrower: party`, `plan: ref<financing.installments> = object(financing.installments)`, `minimum_ticket: money = 100 SAR`, `investor_cap: percent = 20%`, `commitments: ref<lending.commitment> = object(lending.commitment)` |
30
+ | lending.commitment | `round: ref<lending.round>`, `wallet: ref<wallet.balance>`, `investor: party = party(person)` |
31
+ | lending.distribution | `round: ref<lending.round>`, `receipt: ref`, `commitments: ref<lending.commitment> = object(lending.commitment)`, `mode: enum(cash, loss) = cash`, `residual_to: party = programOperator`, `fee: percent = 1%`, `tax: percent = 15%` |
32
+ | insurance.cover | `holder: party`, `insurer: party`, `approval: approval = programOperator`, `commission: percent = 0%`, `covers: ref`, `premium: money = runtime` |
33
+ | insurance.claim | `cover: ref<insurance.cover>`, `approved_by: approval` |
34
+ | approvals.decision | `for: ref`, `approved_by: approval`, `action: text = "approve"`, `protected_request: text = "self.target"` |
35
+ | collections.case | `on: ref<financing.installments>[]`, `agency: approval`, `overdue: duration = 3d`, `fee: percent = 20%` |
36
+ | collections.contact | `case: ref<collections.case>[]`, `agency: party`, `max_contacts: integer = 10`, `window: duration = 30d`, `contact_from: integer(0, 23) = 8`, `contact_until: integer(1, 23) = 20`, `timezone: text = "Asia/Riyadh"`; contact_from less_than contact_until |
37
+ | collections.reminder | `on: ref<financing.installments>[]`, `operator: party = programOperator`, `before_days: integer(0, 366) = 3`, `overdue_days: integer(1, 366) = 1`, `max_per_day: integer(1, 10) = 1`, `send_from: integer(0, 23) = 8`, `send_until: integer(1, 24) = 20`, `timezone: text = "Asia/Riyadh"`; send_from less_than send_until |
38
+ | travel.package | `price: money`, `supplier_cost: money`, `departure: date`; supplier_cost at_most price |
39
+ | travel.booking | `package: ref<travel.package>`, `buyer: party`, `supplier: party`, `approval: approval = programOperator`, `cover: ref<insurance.cover>`, `deposit: percent = 30%`, `balance_before: duration = 14d`, `confirm_within: duration = 24h`, `tax: percent = 15%`, `early_before: duration = 30d`, `middle_before: duration = 15d`, `middle_penalty: percent = 10%`, `late_penalty: percent = 30%`; early_before greater_than middle_before |
40
+ | cards.cardholder | `holder: party` |
41
+ | cards.card | `holder: ref<cards.cardholder>`, `spend_limit: money` |
42
+ | cards.authorization | `card: ref<cards.card>`, `merchant: party`, `approval: approval` |
43
+ | cards.transaction | `authorization: ref<cards.authorization>` |
44
+ | cards.dispute | `transaction: ref<cards.transaction>`, `approved_by: approval`, `within: duration = 90d` |
45
+ | savings.circle | `contribution: money`, `members: integer(1, 366)`, `starts: date`, `memberships: ref<savings.membership> = object(savings.membership)` |
46
+ | savings.membership | `circle: ref<savings.circle>`, `member: party` |
47
+ | reporting.portfolio | `on: ref<financing.installments>[]`, `default_days: integer(1, 3650) = 90`, `retention_years: integer(1, 100) = 10`, `aging_first_days: integer(1, 3650) = 30`, `aging_second_days: integer(1, 3650) = 60`, `aging_third_days: integer(1, 3650) = 90`, `ratio_scale: integer(1, 1000000) = 10000`, `ratio_rounding: enum(floor, halfUp) = floor`, `lock_wait_ms: integer(1, 2000) = 2000`, `capture_ms: integer(1, 10000) = 10000`, `max_rows: integer(1, 100000) = 10000`, `max_join_rows: integer(1, 1000000) = 100000`, `max_bytes: integer(1024, 16777216) = 8388608`; aging_first_days less_than aging_second_days, aging_second_days less_than aging_third_days |