vet-sdk-core-ts 0.4.17 → 0.4.19
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/README.md +17 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/payment.d.ts +10 -0
- package/dist/payment.js +49 -0
- package/docs/LOCAL_FIRST_RELEASE_CONTRACT.md +100 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
# VetChain Core SDK
|
|
2
2
|
|
|
3
|
+
Development and releases follow the mandatory
|
|
4
|
+
[`local-first TDD and release contract`](docs/LOCAL_FIRST_RELEASE_CONTRACT.md).
|
|
5
|
+
|
|
3
6
|
Browser-safe VetChain domain contracts. This repository is independent from
|
|
4
7
|
UHC SDK packages and must not import them.
|
|
5
8
|
|
|
6
9
|
The SDK consumes governed browser-safe values from `vet-data-utils-ts` and
|
|
7
10
|
owns gateway request construction. GW VET remains the policy authority.
|
|
8
11
|
|
|
12
|
+
## USDC payment quotes
|
|
13
|
+
|
|
14
|
+
`vet-sdk-core-ts/payment` separates the payment provider, asset and EVM network
|
|
15
|
+
instead of treating every token named USDC as equivalent. It pins Circle USDC
|
|
16
|
+
on Base Sepolia and Base mainnet, validates the server-authored recipient,
|
|
17
|
+
integer six-decimal amount and expiry, and keeps mainnet disabled unless the
|
|
18
|
+
caller supplies a separately approved release policy. Local Anvil deployments
|
|
19
|
+
provide their deployed mock-token contract through the same network contract;
|
|
20
|
+
they never reuse a production address.
|
|
21
|
+
|
|
22
|
+
The quote authorizes no payment by itself. A server payment adapter must still
|
|
23
|
+
verify the receipt, Transfer log, payer, recipient, amount, confirmation depth,
|
|
24
|
+
invoice state and transaction-hash idempotency before reconciling the payment.
|
|
25
|
+
|
|
9
26
|
## Research studies
|
|
10
27
|
|
|
11
28
|
`buildVeterinaryResearchStudyCreateWorkflowIds` accepts a client-generated
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type EvmPaymentNetworkId, type EvmTransferNetwork, type EvmTransferPaymentQuote } from 'vet-data-utils-ts/payment';
|
|
2
|
+
export { EvmPaymentNetworkIds, PaymentAssetIds, PaymentCurrencyCodes, PaymentProviderIds, USDC_BASE_NETWORKS, USDC_DECIMALS, VET_PAYMENT_TEST_DATA, type EvmPaymentNetworkId, type PaymentProviderId, type EvmTransferNetwork, type EvmTransferPaymentConfirmation, type EvmTransferPaymentQuote, usdOfferToUsdcMinor, } from 'vet-data-utils-ts/payment';
|
|
3
|
+
export type EvmTransferPaymentQuotePolicy = Readonly<{
|
|
4
|
+
now: Date;
|
|
5
|
+
recipient: `0x${string}`;
|
|
6
|
+
allowMainnet: boolean;
|
|
7
|
+
networks?: Readonly<Partial<Record<EvmPaymentNetworkId, EvmTransferNetwork>>>;
|
|
8
|
+
}>;
|
|
9
|
+
/** Validates a server-authored quote without trusting browser network fields. */
|
|
10
|
+
export declare function validateEvmTransferPaymentQuote(value: unknown, policy: EvmTransferPaymentQuotePolicy): EvmTransferPaymentQuote;
|
package/dist/payment.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { PaymentProviderIds, PaymentAssetIds, USDC_DECIMALS, USDC_BASE_NETWORKS, } from 'vet-data-utils-ts/payment';
|
|
2
|
+
export { EvmPaymentNetworkIds, PaymentAssetIds, PaymentCurrencyCodes, PaymentProviderIds, USDC_BASE_NETWORKS, USDC_DECIMALS, VET_PAYMENT_TEST_DATA, usdOfferToUsdcMinor, } from 'vet-data-utils-ts/payment';
|
|
3
|
+
const EVM_ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
4
|
+
const POSITIVE_INTEGER_PATTERN = /^[1-9][0-9]*$/;
|
|
5
|
+
function paymentContractError(code) {
|
|
6
|
+
throw new Error(code);
|
|
7
|
+
}
|
|
8
|
+
/** Validates a server-authored quote without trusting browser network fields. */
|
|
9
|
+
export function validateEvmTransferPaymentQuote(value, policy) {
|
|
10
|
+
if (!value || typeof value !== "object")
|
|
11
|
+
paymentContractError("payment_quote_invalid");
|
|
12
|
+
const quote = value;
|
|
13
|
+
if (quote.version !== 1
|
|
14
|
+
|| quote.provider !== PaymentProviderIds.EvmTransfer
|
|
15
|
+
|| quote.asset !== PaymentAssetIds.Usdc) {
|
|
16
|
+
paymentContractError("payment_quote_invalid");
|
|
17
|
+
}
|
|
18
|
+
const networks = policy.networks || USDC_BASE_NETWORKS;
|
|
19
|
+
const network = quote.network ? networks[quote.network] : undefined;
|
|
20
|
+
if (!network || quote.chainId !== network.chainId)
|
|
21
|
+
paymentContractError("payment_network_not_allowed");
|
|
22
|
+
if (network.mainnet && !policy.allowMainnet)
|
|
23
|
+
paymentContractError("payment_mainnet_not_enabled");
|
|
24
|
+
if (!EVM_ADDRESS_PATTERN.test(String(quote.tokenContract || ""))
|
|
25
|
+
|| quote.asset !== network.asset
|
|
26
|
+
|| quote.tokenContract?.toLowerCase() !== network.tokenContract.toLowerCase()) {
|
|
27
|
+
paymentContractError("payment_token_contract_not_allowed");
|
|
28
|
+
}
|
|
29
|
+
if (!EVM_ADDRESS_PATTERN.test(String(quote.recipient || ""))
|
|
30
|
+
|| quote.recipient?.toLowerCase() !== policy.recipient.toLowerCase()) {
|
|
31
|
+
paymentContractError("payment_recipient_mismatch");
|
|
32
|
+
}
|
|
33
|
+
if (!POSITIVE_INTEGER_PATTERN.test(String(quote.amountMinor || "")) || quote.decimals !== USDC_DECIMALS) {
|
|
34
|
+
paymentContractError("payment_amount_invalid");
|
|
35
|
+
}
|
|
36
|
+
if (!String(quote.paymentReference || "").trim()
|
|
37
|
+
|| !String(quote.invoiceId || "").trim()
|
|
38
|
+
|| !String(quote.offerId || "").trim()) {
|
|
39
|
+
paymentContractError("payment_reference_invalid");
|
|
40
|
+
}
|
|
41
|
+
const expiresAt = Date.parse(String(quote.expiresAt || ""));
|
|
42
|
+
const createdAt = Date.parse(String(quote.createdAt || ""));
|
|
43
|
+
if (!Number.isFinite(createdAt) || !Number.isFinite(expiresAt) || createdAt >= expiresAt) {
|
|
44
|
+
paymentContractError("payment_quote_invalid");
|
|
45
|
+
}
|
|
46
|
+
if (expiresAt <= policy.now.getTime())
|
|
47
|
+
paymentContractError("payment_quote_expired");
|
|
48
|
+
return quote;
|
|
49
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Local-first TDD and release contract
|
|
2
|
+
|
|
3
|
+
This contract is mandatory for behavior changes, shared packages, gateways and
|
|
4
|
+
portals. Repository skills and release-continuity tests enforce it.
|
|
5
|
+
|
|
6
|
+
## 1. Canonical types and reusable test data
|
|
7
|
+
|
|
8
|
+
Before inventing a type, enum, code, identifier, claim, vocabulary or test
|
|
9
|
+
literal, search the applicable standards and the owning shared packages.
|
|
10
|
+
|
|
11
|
+
Use the canonical type or terminology from HL7/FHIR, LOINC, SNOMED CT, ICD-10,
|
|
12
|
+
WHO ATC, Schema.org or the applicable governed standard. Then reuse the
|
|
13
|
+
exported type, builder or fixture from the versioned domain data package
|
|
14
|
+
(`<version>-data` or `<version>-data-utils`) or `common-utils`.
|
|
15
|
+
|
|
16
|
+
If it does not exist, add it first to the owning shared package with its own
|
|
17
|
+
red-green test and export it. Consumers import that export. They must not copy
|
|
18
|
+
or locally recreate governed strings, object shapes or identifiers.
|
|
19
|
+
|
|
20
|
+
## 2. TDD contract
|
|
21
|
+
|
|
22
|
+
Every new or modified test file starts on its first line with a
|
|
23
|
+
`// Flow contract:` comment that links this document and names the production
|
|
24
|
+
journey, authorization boundary and persistence invariant under proof.
|
|
25
|
+
|
|
26
|
+
Apply strict `red -> green -> refactor`:
|
|
27
|
+
|
|
28
|
+
1. Write the smallest executable contract and run it red.
|
|
29
|
+
2. The red result must fail because the required production behavior is absent
|
|
30
|
+
or wrong, not because the test is malformed or setup is missing.
|
|
31
|
+
3. Implement only enough production code to make that contract green.
|
|
32
|
+
4. Run the smallest affected integration and real-boundary gate.
|
|
33
|
+
5. Refactor while keeping the focused contract green.
|
|
34
|
+
|
|
35
|
+
A skip, accepted error, placeholder, pending setup, fixture-only UI or mock that
|
|
36
|
+
replaces the real boundary is never a green result. Unit mocks may isolate code,
|
|
37
|
+
but local service and Playwright proof must exercise the real UI -> BFF ->
|
|
38
|
+
high-level SDK -> GW/DataConv boundary when that journey is affected.
|
|
39
|
+
|
|
40
|
+
## 3. Local-first gates and failure continuation
|
|
41
|
+
|
|
42
|
+
Promotion order is cumulative:
|
|
43
|
+
|
|
44
|
+
`test -> local-network -> test-network/staging -> network/production`
|
|
45
|
+
|
|
46
|
+
The `test` stage includes every affected unit, integration, local service,
|
|
47
|
+
real UI and Playwright gate without blockchain. After a failure, resume only
|
|
48
|
+
the smallest failed gate. Do not repeat a green gate unless the fix changed its
|
|
49
|
+
boundary, it creates required state, or the environment is no longer
|
|
50
|
+
trustworthy. Run the complete affected local matrix once at branch closure.
|
|
51
|
+
|
|
52
|
+
## 4. Unpublished package iteration
|
|
53
|
+
|
|
54
|
+
Keep all participating repositories on pushed but unmerged branches while the
|
|
55
|
+
local matrix is still being corrected. Build an immutable tarball with
|
|
56
|
+
`npm pack` and install it in downstream branches with `--no-save`.
|
|
57
|
+
|
|
58
|
+
Start every downstream proof from its committed lockfile with `npm ci`. If a
|
|
59
|
+
normal `npm install --no-save <tarball>` would re-resolve unrelated dependency
|
|
60
|
+
ranges, do not use that resolver path: overlay the exact packed contents in the
|
|
61
|
+
matching `node_modules` package directory, or use an equivalent isolated
|
|
62
|
+
installation that leaves `package.json` and the lockfile unchanged. Before
|
|
63
|
+
testing, verify the exact local package versions and any runtime-sensitive
|
|
64
|
+
baseline dependencies. A later `npm ci` must remove the temporary overlay.
|
|
65
|
+
|
|
66
|
+
The tarball is temporary test input. Never commit a `file:`, Git, workspace or
|
|
67
|
+
vendored tarball dependency or its generated lockfile state. An npm
|
|
68
|
+
authorization or publication failure must never stop the local `test` stage.
|
|
69
|
+
|
|
70
|
+
Do not attempt `npm publish` until every affected local gate in section 3 is
|
|
71
|
+
green.
|
|
72
|
+
|
|
73
|
+
## 5. Publication and merge order
|
|
74
|
+
|
|
75
|
+
After all local gates are green:
|
|
76
|
+
|
|
77
|
+
1. Publish and verify immutable npm packages from the lowest changed dependency
|
|
78
|
+
upward.
|
|
79
|
+
2. In gateway consumers, replace the temporary tarball with the exact published
|
|
80
|
+
registry version; commit the registry dependency and lockfile.
|
|
81
|
+
3. Run only the minimal clean-install, import/export and startup smoke needed to
|
|
82
|
+
prove the registry artifact matches the tested tarball. Do not repeat the
|
|
83
|
+
green local matrix unless the artifact differs or invalidates prior evidence.
|
|
84
|
+
4. Merge and push package repositories to `main`.
|
|
85
|
+
5. Merge and push gateway consumers to `main` only with exact registry
|
|
86
|
+
versions installed, then build immutable GW images and run `local-network`.
|
|
87
|
+
6. Portal consumers remain on pushed, unmerged branches with the immutable
|
|
88
|
+
tarball during `local-network`; do not reinstall or repeat their already-green
|
|
89
|
+
local matrix. The gateway image and Fabric gate do not require changing a
|
|
90
|
+
portal that already proved the same package tarball locally.
|
|
91
|
+
7. After `local-network` is green, install the exact registry version in each
|
|
92
|
+
affected portal, commit its registry dependency and lockfile, and run only
|
|
93
|
+
the minimal artifact smoke.
|
|
94
|
+
8. Merge portal consumers to `main`, continue to `test-network`/staging and
|
|
95
|
+
finally `network`/production. No tarball or local dependency may reach
|
|
96
|
+
`main`.
|
|
97
|
+
|
|
98
|
+
Missing exact registry publication blocks consumer merge, image build and
|
|
99
|
+
environment promotion. It does not block continued local testing with the
|
|
100
|
+
immutable tarball.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vet-sdk-core-ts",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.19",
|
|
4
4
|
"description": "Browser-safe VetChain core contracts and governed animal species identifiers",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Connecting Solution & Applications Ltd",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"./research-study": {
|
|
40
40
|
"types": "./dist/research-study.d.ts",
|
|
41
41
|
"default": "./dist/research-study.js"
|
|
42
|
+
},
|
|
43
|
+
"./payment": {
|
|
44
|
+
"types": "./dist/payment.d.ts",
|
|
45
|
+
"default": "./dist/payment.js"
|
|
42
46
|
}
|
|
43
47
|
},
|
|
44
48
|
"files": [
|
|
@@ -64,6 +68,6 @@
|
|
|
64
68
|
"dependencies": {
|
|
65
69
|
"@noble/hashes": "^2.2.0",
|
|
66
70
|
"gdc-common-utils-ts": "2.9.4",
|
|
67
|
-
"vet-data-utils-ts": "0.5.
|
|
71
|
+
"vet-data-utils-ts": "0.5.5"
|
|
68
72
|
}
|
|
69
73
|
}
|