Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/experimental-release-1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@evolution-sdk/evolution": minor
---

Experimental release 1:
- Introduce experimental modules and docs flow
- Add runnable Data examples with MDX generation
- ESM Next/Nextra configuration for docs
4 changes: 4 additions & 0 deletions .github/workflows/update-dependencies.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: Update Dependencies

permissions:
contents: write
pull-requests: write

on:
schedule:
# Run every Monday at 9:00 AM UTC
Expand Down
23 changes: 23 additions & 0 deletions docs/examples/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Examples for Address getting-started page
// Run with: pnpm -w -C docs ts-node examples/address.ts (or a small runner)

// #region address-example
import assert from "node:assert/strict"
import { Address } from "@evolution-sdk/evolution"

const hexAddress = "60ba1d6b6283c219a0530e3682c316215d55819cf97bbf26552c6f8530"
const expectedBech32 = "addr_test1vzap66mzs0ppngznpcmg9scky9w4tqvul9am7fj493hc2vq4ry02m"

// Decode from hex
const address = Address.fromHex(hexAddress)

// Encode to bech32
const actualBech32 = Address.toBech32(address)

// Verify the conversion is correct
assert.strictEqual(actualBech32, expectedBech32)
// #endregion address-example

if (import.meta.url === `file://${process.argv[1]}`) {
console.log("Address example OK")
}
51 changes: 51 additions & 0 deletions docs/examples/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Examples for Data getting-started page

// #region data-nested-canonical
import assert from "node:assert/strict"
import { CBOR, Data } from "@evolution-sdk/evolution"
// Create a complex nested data structure with:
// - Constructor with index 1 containing multiple fields
// - Nested constructors with different indices
// - A Map with mixed key-value pairs
// - An array of numbers
const nestedUnsortedData = new Data.Constr({
index: 1n,
fields: [
// Nested constructor: 121_0([123_0([])])
new Data.Constr({
index: 0n,
fields: [
new Data.Constr({
index: 2n,
fields: []
})
]
}),
// Map with unsorted keys (will be sorted in canonical mode)
new Map<Data.Data, Data.Data>([
["deadbeef01", new Data.Constr({ index: 0n, fields: [] })],
["beef", 19n],
["deadbeef03", new Data.Constr({ index: 1n, fields: [] })]
]),
// Array of numbers
[10n, 5n, 2n, 3n, 1n, 4n]
]
})

// Encode using default options (indefinite-length encoding for Data)
const cborHex = Data.toCBORHex(nestedUnsortedData)

const decodedData = Data.fromCBORHex(cborHex)

// Create a canonical codec for deterministic encoding
// This ensures consistent output and sorted map keys
// Encode using canonical mode (definite-length, sorted keys)
const canonicalCborHex = Data.toCBORHex(nestedUnsortedData, CBOR.CANONICAL_OPTIONS)

// Verify that decoding works correctly
assert.deepStrictEqual(decodedData, nestedUnsortedData)
// #endregion data-nested-canonical

if (import.meta.url === `file://${process.argv[1]}`) {
console.log("Data example OK")
}
34 changes: 34 additions & 0 deletions docs/examples/data/basic-construction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// @title: Basic Data Construction
// @description: Learn how to create fundamental Data types using constructors.
import assert from "node:assert/strict"
import { Data } from "@evolution-sdk/evolution"

// #region main
// Create a simple constructor with no fields
const unit = new Data.Constr({ index: 0n, fields: [] })
console.log("Unit constructor:", unit)

// Create a constructor with primitive fields
const person = new Data.Constr({
index: 1n,
fields: ["416c696365", 30n] // 'Alice' as hex and age
})
console.log("Person constructor:", person)

// Create a constructor with mixed field types
const record = new Data.Constr({
index: 2n,
fields: [
"deadbeef", // bytes as hex string (ByteArray)
42n, // big integer (Int)
[1n, 2n, 3n], // array of big integers (List)
new Data.Constr({ index: 0n, fields: [] }) // nested constructor
]
})

// Verify the construction worked
assert.equal(person.index, 1n)
assert.equal(person.fields.length, 2)
assert.equal(person.fields[0], "416c696365") // 'Alice' in hex
assert.equal(person.fields[1], 30n)
// #endregion main
12 changes: 12 additions & 0 deletions docs/examples/data/bytes-validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// @title: Validate bytes
// @description: Quick check for hex-like bytes strings using Data.isBytes.
import assert from "node:assert/strict"
import { Data } from "@evolution-sdk/evolution"

// #region main
const hex = "deadbeef"
assert.equal(Data.isBytes(hex), true)

const invalid = "not-hex"
assert.equal(Data.isBytes(invalid), false)
// #endregion main
50 changes: 50 additions & 0 deletions docs/examples/data/cbor-encoding-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// @title: CBOR Encoding Options
// @description: Compare different CBOR encoding strategies for the same data.
import assert from "node:assert/strict"
import { CBOR, Data } from "@evolution-sdk/evolution"

// #region main
// Create complex data with unsorted elements (Maps should be standalone, not in constructor fields)
const unsortedMap = new Map<Data.Data, Data.Data>([
["7a65627261", 1n], // 'zebra' in hex
["6170706c65", 2n], // 'apple' in hex
["62616e616e61", 3n] // 'banana' in hex
])

// Create a constructor with only valid field types
const complexData = new Data.Constr({
index: 1n,
fields: [
// List with mixed order
[100n, 1n, 50n, 25n],
"deadbeef",
42n // additional data
]
})

// Standard encoding (preserves original order)
const standardHex = Data.toCBORHex(complexData)
console.log("Standard CBOR:", standardHex)

// Canonical encoding (sorted for deterministic output)
const canonicalHex = Data.toCBORHex(complexData, CBOR.CANONICAL_OPTIONS)
console.log("Canonical CBOR:", canonicalHex)

// Test with the standalone map
const mapStandardHex = Data.toCBORHex(unsortedMap)
const mapCanonicalHex = Data.toCBORHex(unsortedMap, CBOR.CANONICAL_OPTIONS)

// Both should decode to equivalent data
const fromStandard = Data.fromCBORHex(standardHex)
const fromCanonical = Data.fromCBORHex(canonicalHex)

assert.deepStrictEqual(fromStandard, complexData)
assert.deepStrictEqual(fromCanonical, complexData)
assert.deepStrictEqual(fromStandard, fromCanonical)

// Demonstrate that canonical encoding is deterministic
const secondCanonical = Data.toCBORHex(complexData, CBOR.CANONICAL_OPTIONS)
assert.equal(canonicalHex, secondCanonical)

console.log("Map encoding also works:", mapStandardHex.length > 0)
// #endregion main
65 changes: 65 additions & 0 deletions docs/examples/data/complex-nested-structures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// @title: Complex Nested Structures
// @description: Build sophisticated nested data structures with multiple levels and types.
import assert from "node:assert/strict"
import { Data } from "@evolution-sdk/evolution"

// #region main
// Create a complex user profile with nested data using only valid Data types
const userProfile = new Data.Constr({
index: 0n, // User constructor
fields: [
"616c696365", // username 'alice' in hex
new Data.Constr({
index: 1n, // Profile constructor
fields: [
25n, // age
"deadbeef", // some profile data as hex
// Nested preferences constructor
new Data.Constr({
index: 2n, // Preferences constructor
fields: [
1n, // notification setting (1 = enabled)
0n, // theme setting (0 = light, 1 = dark)
8n // timezone offset
]
})
]
})
]
})

// Create a transaction record with complex metadata
const transaction = new Data.Constr({
index: 10n, // Transaction constructor
fields: [
"deadbeef1234", // transaction hash
1000000n, // amount in microADA
new Data.Constr({
index: 11n, // Address constructor
fields: ["616464723174657374"] // address data in hex
}),
// Simple metadata as nested constructor
new Data.Constr({
index: 12n, // Metadata constructor
fields: [
1640995200n, // timestamp
"7061796d656e74", // 'payment' as hex string
1n // status code
]
})
]
})

// Test deep structure access
assert.equal(userProfile.index, 0n)
assert.equal(userProfile.fields[0], "616c696365") // alice in hex

// Verify nested constructor
const profileData = userProfile.fields[1] as Data.Constr
assert.equal(profileData.index, 1n)
assert.equal(profileData.fields[0], 25n)

console.log("Complex structures created successfully")
console.log("User profile index:", userProfile.index)
console.log("Transaction amount:", transaction.fields[1])
// #endregion main
71 changes: 71 additions & 0 deletions docs/examples/data/error-handling-patterns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// @title: Error Handling Patterns
// @description: Use Either patterns for safe data operations with proper error handling.
import assert from "node:assert/strict"
import { Either, pipe } from "effect"
import { Data } from "@evolution-sdk/evolution"

// #region main
// Use built-in Either-based functions for safe operations
const safeData = new Data.Constr({ index: 0n, fields: ["74657374", 42n] }) // 'test' as hex

// Safe encoding using Data.Either namespace
const encodingResult = Data.Either.toCBORHex(safeData)
assert.equal(Either.isRight(encodingResult), true)

// Extract values using Either.match for type safety
const encodedHex = Either.match(encodingResult, {
onLeft: (error: Data.DataError) => {
throw new Error(`Encoding failed: ${error.message}`)
},
onRight: (hex: string) => {
console.log("Encoded successfully:", hex)
return hex
}
})

// Safe decoding using the encoded hex
const decodingResult = Data.Either.fromCBORHex(encodedHex)
assert.equal(Either.isRight(decodingResult), true)

Either.match(decodingResult, {
onLeft: (error: Data.DataError) => {
throw new Error(`Decoding failed: ${error.message}`)
},
onRight: (decoded: Data.Data) => {
console.log("Decoded successfully")
assert.deepStrictEqual(decoded, safeData)
}
})

// Test error handling with invalid input
const invalidResult = Data.Either.fromCBORHex("invalid-hex-data")
assert.equal(Either.isLeft(invalidResult), true)

Either.match(invalidResult, {
onLeft: (error: Data.DataError) => {
console.log("Expected error:", error.message)
},
onRight: () => {
throw new Error("Should not succeed with invalid input")
}
})

// Compose operations using pipe and Either
const processDataSafely = (data: Data.Data) =>
pipe(
Data.Either.toCBORHex(data),
Either.flatMap((hex: string) => Data.Either.fromCBORHex(hex)),
Either.map((result: Data.Data) => `Roundtrip successful`)
)

const pipeResult = processDataSafely(safeData)
assert.equal(Either.isRight(pipeResult), true)

// Pattern matching for comprehensive error handling
const finalMessage = Either.match(pipeResult, {
onLeft: (error: Data.DataError) => `Operation failed: ${error.message}`,
onRight: (value: string) => `Operation succeeded: ${value}`
})

console.log("Final result:", finalMessage)
// #endregion main
28 changes: 28 additions & 0 deletions docs/examples/data/nested-canonical.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// @title: Canonical nested structure
// @description: Complex nested Data encoding with canonical CBOR options.
import assert from "node:assert/strict"
import { CBOR, Data } from "@evolution-sdk/evolution"

// #region main
const nestedUnsortedData = new Data.Constr({
index: 1n,
fields: [
new Data.Constr({
index: 0n,
fields: [new Data.Constr({ index: 2n, fields: [] })]
}),
new Map<Data.Data, Data.Data>([
["deadbeef01", new Data.Constr({ index: 0n, fields: [] })],
["beef", 19n],
["deadbeef03", new Data.Constr({ index: 1n, fields: [] })]
]),
[10n, 5n, 2n, 3n, 1n, 4n]
]
})

const cborHex = Data.toCBORHex(nestedUnsortedData)
const decoded = Data.fromCBORHex(cborHex)
const canonicalCborHex = Data.toCBORHex(nestedUnsortedData, CBOR.CANONICAL_OPTIONS)

assert.deepStrictEqual(decoded, nestedUnsortedData)
// #endregion main
11 changes: 11 additions & 0 deletions docs/examples/data/roundtrip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// @title: Roundtrip encode/decode
// @description: Encode a Data value to CBOR hex and decode back.
import assert from "node:assert/strict"
import { CBOR, Data } from "@evolution-sdk/evolution"

// #region main
const original = new Data.Constr({ index: 0n, fields: ["beef", 19n] })
const hexCbor = Data.toCBORHex(original, CBOR.CANONICAL_OPTIONS)
const back = Data.fromCBORHex(hexCbor)
assert.deepStrictEqual(back, original)
// #endregion main
Loading