Skip to content

Commit

Permalink
PayloadBuilderBase merged into PayloadBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
arietrouw committed Dec 20, 2024
1 parent 46547f7 commit f3f6d1f
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 134 deletions.
12 changes: 5 additions & 7 deletions packages/core-payload-plugins/packages/schema/src/Payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export type SchemaPayload = Payload<{
*/
definition: {
[key: string]: unknown
$id?: string
}
/**
* The schema this schema extends (if any)
Expand All @@ -19,12 +18,11 @@ export type SchemaPayload = Payload<{

/** @deprecated use definition.$id instead */
name?: string

/**
* Identifies this payload as a Schema
*/
schema: SchemaSchema
}>
}, SchemaSchema> & {
definition: {
$id?: string
}
}

/**
* Identity function for determining if an object is an Schema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import {
ObjectHasher, removeEmptyFields, sortFields,
} from '@xyo-network/hash'
import type { PayloadBuilderOptions } from '@xyo-network/payload-builder'
import {
omitSchema, PayloadBuilder, PayloadBuilderBase,
} from '@xyo-network/payload-builder'
import { omitSchema, PayloadBuilder } from '@xyo-network/payload-builder'
import type {
ModuleError, Payload, Schema,
WithoutMeta,
Expand Down Expand Up @@ -43,8 +41,9 @@ const uniqueAccounts = (accounts: AccountInstance[], throwOnFalse = false) => {
export class BoundWitnessBuilder<
TBoundWitness extends UnsignedBoundWitness = UnsignedBoundWitness,
TPayload extends Payload = Payload>
extends PayloadBuilderBase<
TBoundWitness
extends PayloadBuilder<
TBoundWitness,
Promise<[Signed<TBoundWitness>, TPayload[], ModuleError[]]>
> {
private static readonly _buildMutex = new Mutex()

Expand Down Expand Up @@ -99,7 +98,7 @@ export class BoundWitnessBuilder<
): Promise<Pick<T, GeneratedBoundWitnessFields>> {
const addresses = accounts.map(account => hexFromArrayBuffer(account.addressBytes, { prefix: false }))
const previous_hashes = accounts.map(account => account.previousHash ?? null)
const payload_hashes = payloads ? await PayloadBuilder.dataHashes(payloads) : []
const payload_hashes = payloads ? await BoundWitnessBuilder.dataHashes(payloads) : []
const payload_schemas = payloads?.map(({ schema }) => schema) ?? []
return {
addresses, payload_hashes, payload_schemas, previous_hashes,
Expand All @@ -122,7 +121,7 @@ export class BoundWitnessBuilder<
assertEx(!fields.payload_schemas.some(schema => !schema), () => 'nulls found in schemas')
}

async build(): Promise<[Signed<TBoundWitness>, TPayload[], ModuleError[]]> {
override async build(): Promise<[Signed<TBoundWitness>, TPayload[], ModuleError[]]> {
return await BoundWitnessBuilder._buildMutex.runExclusive(async () => {
const dataHashableFields = (await this.dataHashableFields()) as TBoundWitness
const $signatures = await this.sign()
Expand Down Expand Up @@ -180,7 +179,7 @@ export class BoundWitnessBuilder<
}
// we need to do the cast here since ts seems to not like nested, yet same, generics
this._fields = omitSchema(
PayloadBuilderBase.omitMeta(
BoundWitnessBuilder.omitMeta(
removeEmptyFields(structuredClone(fields)),
),
) as unknown as WithoutMeta<WithoutSchema<TBoundWitness>>
Expand Down
121 changes: 108 additions & 13 deletions packages/protocol/packages/payload/packages/builder/src/Builder.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,47 @@
import { assertEx } from '@xylabs/assert'
import type { Hash } from '@xylabs/hex'
import type { AnyObject, Compare } from '@xylabs/object'
import { ObjectHasher } from '@xyo-network/hash'
import type {
AnyObject, Compare, EmptyObject,
} from '@xylabs/object'
import {
type Payload,
isJsonObject, omitByPrefix, pickByPrefix, toJson,
} from '@xylabs/object'
import type { Promisable } from '@xylabs/promise'
import { ObjectHasher, removeEmptyFields } from '@xyo-network/hash'
import {
type Payload, type Schema,
type Sequence,
SequenceComparer,
SequenceParser,
type WithHashMeta,
type WithOnlyClientMeta,
type WithOptionalSchema,
type WithoutClientMeta,
type WithoutMeta,
type WithoutPrivateStorageMeta,
type WithoutSchema,
type WithoutStorageMeta,
type WithStorageMeta,
} from '@xyo-network/payload-model'

import { PayloadBuilderBase } from './BuilderBase.ts'
import type { PayloadBuilderOptions } from './Options.ts'

export const omitSchema = <T extends WithOptionalSchema>(payload: T): WithoutSchema<T> => {
const result = structuredClone(payload)
delete result.schema
return result
}

export class PayloadBuilder<T extends Payload = Payload<AnyObject>, R = T> {
protected _fields?: WithoutMeta<WithoutSchema<T>>
protected _meta?: WithOnlyClientMeta<T>
protected _schema: Schema

constructor(readonly options: PayloadBuilderOptions) {
const { schema } = options
this._schema = schema
}

export class PayloadBuilder<
T extends Payload = Payload<AnyObject>,
> extends PayloadBuilderBase<T> {
static async addHashMeta<T extends Payload>(payload: T): Promise<WithHashMeta<T>>
static async addHashMeta<T extends Payload>(payloads: T[]): Promise<WithHashMeta<T>[]>
static async addHashMeta<T extends Payload>(payloads: T | T[]): Promise<WithHashMeta<T>[] | WithHashMeta<T>> {
Expand All @@ -26,8 +52,8 @@ export class PayloadBuilder<
}),
)
} else {
const _hash = await PayloadBuilder.hash(payloads)
const _dataHash = await PayloadBuilder.dataHash(payloads)
const _hash = await this.hash(payloads)
const _dataHash = await this.dataHash(payloads)
return {
...payloads,
_dataHash,
Expand Down Expand Up @@ -82,13 +108,26 @@ export class PayloadBuilder<
)
}

static dataHashableFields<T extends Payload>(
schema: Schema,
payload: WithoutSchema<T>,

): Promisable<WithoutMeta<T>> {
const cleanFields = removeEmptyFields({ ...payload, schema })
assertEx(
cleanFields === undefined || isJsonObject(cleanFields),
() => `Fields must be JsonObject: ${JSON.stringify(toJson(cleanFields), null, 2)}`,
)
return this.omitMeta(cleanFields) as WithoutMeta<T>
}

static async dataHashes(payloads: undefined): Promise<undefined>
static async dataHashes<T extends Payload>(payloads: T[]): Promise<Hash[]>
static async dataHashes<T extends Payload>(payloads?: T[]): Promise<Hash[] | undefined> {
return payloads
? await Promise.all(
payloads.map(async (payload) => {
return await PayloadBuilder.dataHash(payload)
return await this.dataHash(payload)
}),
)
: undefined
Expand Down Expand Up @@ -124,7 +163,7 @@ export class PayloadBuilder<
static async hashPairs<T extends Payload>(payloads: T[]): Promise<[T, Hash][]> {
return await Promise.all(
payloads.map<Promise<[T, Hash]>>(async (payload) => {
return [payload, await PayloadBuilder.hash(payload)]
return [payload, await this.hash(payload)]
}),
)
}
Expand All @@ -141,6 +180,38 @@ export class PayloadBuilder<
return await ObjectHasher.hashes(payloads)
}

static omitClientMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutClientMeta<T>
static omitClientMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutClientMeta<T>[]
static omitClientMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutClientMeta<T> | WithoutClientMeta<T>[] {
return Array.isArray(payloads)
? payloads.map(payload => this.omitClientMeta(payload, maxDepth))
: omitByPrefix(payloads, '$', maxDepth)
}

static omitMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutMeta<T>
static omitMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutMeta<T>[]
static omitMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutMeta<T> | WithoutMeta<T>[] {
return Array.isArray(payloads)
? payloads.map(payload => this.omitMeta(payload, maxDepth))
: this.omitStorageMeta(this.omitClientMeta(payloads, maxDepth), maxDepth) as unknown as WithoutMeta<T>
}

static omitPrivateStorageMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutPrivateStorageMeta<T>
static omitPrivateStorageMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutPrivateStorageMeta<T>[]
static omitPrivateStorageMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutPrivateStorageMeta<T> | WithoutPrivateStorageMeta<T>[] {
return Array.isArray(payloads)
? payloads.map(payload => this.omitPrivateStorageMeta(payload, maxDepth))
: omitByPrefix(payloads, '__', maxDepth)
}

static omitStorageMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutStorageMeta<T>
static omitStorageMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutStorageMeta<T>[]
static omitStorageMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutStorageMeta<T> | WithoutStorageMeta<T>[] {
return Array.isArray(payloads)
? payloads.map(payload => this.omitStorageMeta(payload, maxDepth))
: omitByPrefix(payloads, '_', maxDepth)
}

static sortByStorageMeta<T extends Payload>(
payloads: WithStorageMeta<T>[],
direction: -1 | 1 = 1,
Expand Down Expand Up @@ -180,11 +251,35 @@ export class PayloadBuilder<
return result
}

build(): T {
build(): R {
return {
schema: this._schema,
...this._fields,
...this._meta,
} as T
} as R
}

async dataHashableFields() {
return await PayloadBuilder.dataHashableFields(
assertEx(this._schema, () => 'Payload: Missing Schema'),
// TODO: Add verification that required fields are present
this._fields as WithoutSchema<T>,
)
}

fields(fields: WithoutMeta<WithoutSchema<T>>) {
// we need to do the cast here since ts seems to not like nested, yet same, generics
this._fields = omitSchema(PayloadBuilder.omitMeta(removeEmptyFields(structuredClone(fields)))) as unknown as WithoutMeta<WithoutSchema<T>>
return this
}

meta(meta: WithOnlyClientMeta<T>) {
// we need to do the cast here since ts seems to not like nested, yet same, generics
this._meta = pickByPrefix(meta, '$') as WithOnlyClientMeta<T>
return this
}

schema(value: Schema) {
this._schema = value
}
}
105 changes: 0 additions & 105 deletions packages/protocol/packages/payload/packages/builder/src/BuilderBase.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './Builder.ts'
export * from './BuilderBase.ts'
export * from './Builder.ts'
export * from './Options.ts'

0 comments on commit f3f6d1f

Please sign in to comment.