Skip to content

Commit 1c6a890

Browse files
Merge pull request #24 from no-witness-labs/feat/experimental-release-1
chore(changeset): experimental release 1
2 parents ec99aa1 + 7ea5cf7 commit 1c6a890

33 files changed

+1330
-430
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@evolution-sdk/evolution": minor
3+
---
4+
5+
Experimental release 1:
6+
- Introduce experimental modules and docs flow
7+
- Add runnable Data examples with MDX generation
8+
- ESM Next/Nextra configuration for docs

.github/workflows/update-dependencies.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
name: Update Dependencies
22

3+
permissions:
4+
contents: write
5+
pull-requests: write
6+
37
on:
48
schedule:
59
# Run every Monday at 9:00 AM UTC

docs/examples/address.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Examples for Address getting-started page
2+
// Run with: pnpm -w -C docs ts-node examples/address.ts (or a small runner)
3+
4+
// #region address-example
5+
import assert from "node:assert/strict"
6+
import { Address } from "@evolution-sdk/evolution"
7+
8+
const hexAddress = "60ba1d6b6283c219a0530e3682c316215d55819cf97bbf26552c6f8530"
9+
const expectedBech32 = "addr_test1vzap66mzs0ppngznpcmg9scky9w4tqvul9am7fj493hc2vq4ry02m"
10+
11+
// Decode from hex
12+
const address = Address.fromHex(hexAddress)
13+
14+
// Encode to bech32
15+
const actualBech32 = Address.toBech32(address)
16+
17+
// Verify the conversion is correct
18+
assert.strictEqual(actualBech32, expectedBech32)
19+
// #endregion address-example
20+
21+
if (import.meta.url === `file://${process.argv[1]}`) {
22+
console.log("Address example OK")
23+
}

docs/examples/data.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Examples for Data getting-started page
2+
3+
// #region data-nested-canonical
4+
import assert from "node:assert/strict"
5+
import { CBOR, Data } from "@evolution-sdk/evolution"
6+
// Create a complex nested data structure with:
7+
// - Constructor with index 1 containing multiple fields
8+
// - Nested constructors with different indices
9+
// - A Map with mixed key-value pairs
10+
// - An array of numbers
11+
const nestedUnsortedData = new Data.Constr({
12+
index: 1n,
13+
fields: [
14+
// Nested constructor: 121_0([123_0([])])
15+
new Data.Constr({
16+
index: 0n,
17+
fields: [
18+
new Data.Constr({
19+
index: 2n,
20+
fields: []
21+
})
22+
]
23+
}),
24+
// Map with unsorted keys (will be sorted in canonical mode)
25+
new Map<Data.Data, Data.Data>([
26+
["deadbeef01", new Data.Constr({ index: 0n, fields: [] })],
27+
["beef", 19n],
28+
["deadbeef03", new Data.Constr({ index: 1n, fields: [] })]
29+
]),
30+
// Array of numbers
31+
[10n, 5n, 2n, 3n, 1n, 4n]
32+
]
33+
})
34+
35+
// Encode using default options (indefinite-length encoding for Data)
36+
const cborHex = Data.toCBORHex(nestedUnsortedData)
37+
38+
const decodedData = Data.fromCBORHex(cborHex)
39+
40+
// Create a canonical codec for deterministic encoding
41+
// This ensures consistent output and sorted map keys
42+
// Encode using canonical mode (definite-length, sorted keys)
43+
const canonicalCborHex = Data.toCBORHex(nestedUnsortedData, CBOR.CANONICAL_OPTIONS)
44+
45+
// Verify that decoding works correctly
46+
assert.deepStrictEqual(decodedData, nestedUnsortedData)
47+
// #endregion data-nested-canonical
48+
49+
if (import.meta.url === `file://${process.argv[1]}`) {
50+
console.log("Data example OK")
51+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// @title: Basic Data Construction
2+
// @description: Learn how to create fundamental Data types using constructors.
3+
import assert from "node:assert/strict"
4+
import { Data } from "@evolution-sdk/evolution"
5+
6+
// #region main
7+
// Create a simple constructor with no fields
8+
const unit = new Data.Constr({ index: 0n, fields: [] })
9+
console.log("Unit constructor:", unit)
10+
11+
// Create a constructor with primitive fields
12+
const person = new Data.Constr({
13+
index: 1n,
14+
fields: ["416c696365", 30n] // 'Alice' as hex and age
15+
})
16+
console.log("Person constructor:", person)
17+
18+
// Create a constructor with mixed field types
19+
const record = new Data.Constr({
20+
index: 2n,
21+
fields: [
22+
"deadbeef", // bytes as hex string (ByteArray)
23+
42n, // big integer (Int)
24+
[1n, 2n, 3n], // array of big integers (List)
25+
new Data.Constr({ index: 0n, fields: [] }) // nested constructor
26+
]
27+
})
28+
29+
// Verify the construction worked
30+
assert.equal(person.index, 1n)
31+
assert.equal(person.fields.length, 2)
32+
assert.equal(person.fields[0], "416c696365") // 'Alice' in hex
33+
assert.equal(person.fields[1], 30n)
34+
// #endregion main
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @title: Validate bytes
2+
// @description: Quick check for hex-like bytes strings using Data.isBytes.
3+
import assert from "node:assert/strict"
4+
import { Data } from "@evolution-sdk/evolution"
5+
6+
// #region main
7+
const hex = "deadbeef"
8+
assert.equal(Data.isBytes(hex), true)
9+
10+
const invalid = "not-hex"
11+
assert.equal(Data.isBytes(invalid), false)
12+
// #endregion main
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// @title: CBOR Encoding Options
2+
// @description: Compare different CBOR encoding strategies for the same data.
3+
import assert from "node:assert/strict"
4+
import { CBOR, Data } from "@evolution-sdk/evolution"
5+
6+
// #region main
7+
// Create complex data with unsorted elements (Maps should be standalone, not in constructor fields)
8+
const unsortedMap = new Map<Data.Data, Data.Data>([
9+
["7a65627261", 1n], // 'zebra' in hex
10+
["6170706c65", 2n], // 'apple' in hex
11+
["62616e616e61", 3n] // 'banana' in hex
12+
])
13+
14+
// Create a constructor with only valid field types
15+
const complexData = new Data.Constr({
16+
index: 1n,
17+
fields: [
18+
// List with mixed order
19+
[100n, 1n, 50n, 25n],
20+
"deadbeef",
21+
42n // additional data
22+
]
23+
})
24+
25+
// Standard encoding (preserves original order)
26+
const standardHex = Data.toCBORHex(complexData)
27+
console.log("Standard CBOR:", standardHex)
28+
29+
// Canonical encoding (sorted for deterministic output)
30+
const canonicalHex = Data.toCBORHex(complexData, CBOR.CANONICAL_OPTIONS)
31+
console.log("Canonical CBOR:", canonicalHex)
32+
33+
// Test with the standalone map
34+
const mapStandardHex = Data.toCBORHex(unsortedMap)
35+
const mapCanonicalHex = Data.toCBORHex(unsortedMap, CBOR.CANONICAL_OPTIONS)
36+
37+
// Both should decode to equivalent data
38+
const fromStandard = Data.fromCBORHex(standardHex)
39+
const fromCanonical = Data.fromCBORHex(canonicalHex)
40+
41+
assert.deepStrictEqual(fromStandard, complexData)
42+
assert.deepStrictEqual(fromCanonical, complexData)
43+
assert.deepStrictEqual(fromStandard, fromCanonical)
44+
45+
// Demonstrate that canonical encoding is deterministic
46+
const secondCanonical = Data.toCBORHex(complexData, CBOR.CANONICAL_OPTIONS)
47+
assert.equal(canonicalHex, secondCanonical)
48+
49+
console.log("Map encoding also works:", mapStandardHex.length > 0)
50+
// #endregion main
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// @title: Complex Nested Structures
2+
// @description: Build sophisticated nested data structures with multiple levels and types.
3+
import assert from "node:assert/strict"
4+
import { Data } from "@evolution-sdk/evolution"
5+
6+
// #region main
7+
// Create a complex user profile with nested data using only valid Data types
8+
const userProfile = new Data.Constr({
9+
index: 0n, // User constructor
10+
fields: [
11+
"616c696365", // username 'alice' in hex
12+
new Data.Constr({
13+
index: 1n, // Profile constructor
14+
fields: [
15+
25n, // age
16+
"deadbeef", // some profile data as hex
17+
// Nested preferences constructor
18+
new Data.Constr({
19+
index: 2n, // Preferences constructor
20+
fields: [
21+
1n, // notification setting (1 = enabled)
22+
0n, // theme setting (0 = light, 1 = dark)
23+
8n // timezone offset
24+
]
25+
})
26+
]
27+
})
28+
]
29+
})
30+
31+
// Create a transaction record with complex metadata
32+
const transaction = new Data.Constr({
33+
index: 10n, // Transaction constructor
34+
fields: [
35+
"deadbeef1234", // transaction hash
36+
1000000n, // amount in microADA
37+
new Data.Constr({
38+
index: 11n, // Address constructor
39+
fields: ["616464723174657374"] // address data in hex
40+
}),
41+
// Simple metadata as nested constructor
42+
new Data.Constr({
43+
index: 12n, // Metadata constructor
44+
fields: [
45+
1640995200n, // timestamp
46+
"7061796d656e74", // 'payment' as hex string
47+
1n // status code
48+
]
49+
})
50+
]
51+
})
52+
53+
// Test deep structure access
54+
assert.equal(userProfile.index, 0n)
55+
assert.equal(userProfile.fields[0], "616c696365") // alice in hex
56+
57+
// Verify nested constructor
58+
const profileData = userProfile.fields[1] as Data.Constr
59+
assert.equal(profileData.index, 1n)
60+
assert.equal(profileData.fields[0], 25n)
61+
62+
console.log("Complex structures created successfully")
63+
console.log("User profile index:", userProfile.index)
64+
console.log("Transaction amount:", transaction.fields[1])
65+
// #endregion main
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// @title: Error Handling Patterns
2+
// @description: Use Either patterns for safe data operations with proper error handling.
3+
import assert from "node:assert/strict"
4+
import { Either, pipe } from "effect"
5+
import { Data } from "@evolution-sdk/evolution"
6+
7+
// #region main
8+
// Use built-in Either-based functions for safe operations
9+
const safeData = new Data.Constr({ index: 0n, fields: ["74657374", 42n] }) // 'test' as hex
10+
11+
// Safe encoding using Data.Either namespace
12+
const encodingResult = Data.Either.toCBORHex(safeData)
13+
assert.equal(Either.isRight(encodingResult), true)
14+
15+
// Extract values using Either.match for type safety
16+
const encodedHex = Either.match(encodingResult, {
17+
onLeft: (error: Data.DataError) => {
18+
throw new Error(`Encoding failed: ${error.message}`)
19+
},
20+
onRight: (hex: string) => {
21+
console.log("Encoded successfully:", hex)
22+
return hex
23+
}
24+
})
25+
26+
// Safe decoding using the encoded hex
27+
const decodingResult = Data.Either.fromCBORHex(encodedHex)
28+
assert.equal(Either.isRight(decodingResult), true)
29+
30+
Either.match(decodingResult, {
31+
onLeft: (error: Data.DataError) => {
32+
throw new Error(`Decoding failed: ${error.message}`)
33+
},
34+
onRight: (decoded: Data.Data) => {
35+
console.log("Decoded successfully")
36+
assert.deepStrictEqual(decoded, safeData)
37+
}
38+
})
39+
40+
// Test error handling with invalid input
41+
const invalidResult = Data.Either.fromCBORHex("invalid-hex-data")
42+
assert.equal(Either.isLeft(invalidResult), true)
43+
44+
Either.match(invalidResult, {
45+
onLeft: (error: Data.DataError) => {
46+
console.log("Expected error:", error.message)
47+
},
48+
onRight: () => {
49+
throw new Error("Should not succeed with invalid input")
50+
}
51+
})
52+
53+
// Compose operations using pipe and Either
54+
const processDataSafely = (data: Data.Data) =>
55+
pipe(
56+
Data.Either.toCBORHex(data),
57+
Either.flatMap((hex: string) => Data.Either.fromCBORHex(hex)),
58+
Either.map((result: Data.Data) => `Roundtrip successful`)
59+
)
60+
61+
const pipeResult = processDataSafely(safeData)
62+
assert.equal(Either.isRight(pipeResult), true)
63+
64+
// Pattern matching for comprehensive error handling
65+
const finalMessage = Either.match(pipeResult, {
66+
onLeft: (error: Data.DataError) => `Operation failed: ${error.message}`,
67+
onRight: (value: string) => `Operation succeeded: ${value}`
68+
})
69+
70+
console.log("Final result:", finalMessage)
71+
// #endregion main
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @title: Canonical nested structure
2+
// @description: Complex nested Data encoding with canonical CBOR options.
3+
import assert from "node:assert/strict"
4+
import { CBOR, Data } from "@evolution-sdk/evolution"
5+
6+
// #region main
7+
const nestedUnsortedData = new Data.Constr({
8+
index: 1n,
9+
fields: [
10+
new Data.Constr({
11+
index: 0n,
12+
fields: [new Data.Constr({ index: 2n, fields: [] })]
13+
}),
14+
new Map<Data.Data, Data.Data>([
15+
["deadbeef01", new Data.Constr({ index: 0n, fields: [] })],
16+
["beef", 19n],
17+
["deadbeef03", new Data.Constr({ index: 1n, fields: [] })]
18+
]),
19+
[10n, 5n, 2n, 3n, 1n, 4n]
20+
]
21+
})
22+
23+
const cborHex = Data.toCBORHex(nestedUnsortedData)
24+
const decoded = Data.fromCBORHex(cborHex)
25+
const canonicalCborHex = Data.toCBORHex(nestedUnsortedData, CBOR.CANONICAL_OPTIONS)
26+
27+
assert.deepStrictEqual(decoded, nestedUnsortedData)
28+
// #endregion main

0 commit comments

Comments
 (0)