@xyo-network/payload-builder 3.5.2 → 3.6.0-rc.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/payload-builder",
3
- "version": "3.5.2",
3
+ "version": "3.6.0-rc.10",
4
4
  "description": "Primary SDK for using XYO Protocol 2.0",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -29,22 +29,23 @@
29
29
  "module": "dist/neutral/index.mjs",
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "dependencies": {
32
- "@xylabs/assert": "^4.4.9",
33
- "@xylabs/hex": "^4.4.9",
34
- "@xylabs/logger": "^4.4.9",
35
- "@xylabs/object": "^4.4.9",
36
- "@xylabs/promise": "^4.4.9",
37
- "@xyo-network/hash": "^3.5.2",
38
- "@xyo-network/payload-model": "^3.5.2"
32
+ "@xylabs/assert": "^4.4.21",
33
+ "@xylabs/hex": "^4.4.21",
34
+ "@xylabs/logger": "^4.4.21",
35
+ "@xylabs/object": "^4.4.21",
36
+ "@xylabs/promise": "^4.4.21",
37
+ "@xyo-network/hash": "^3.6.0-rc.10",
38
+ "@xyo-network/payload-model": "^3.6.0-rc.10"
39
39
  },
40
40
  "devDependencies": {
41
- "@xylabs/ts-scripts-yarn3": "^4.2.4",
42
- "@xylabs/tsconfig": "^4.2.4",
43
- "@xylabs/vitest-extended": "^4.4.9",
41
+ "@xylabs/ts-scripts-yarn3": "^4.2.6",
42
+ "@xylabs/tsconfig": "^4.2.6",
43
+ "@xylabs/vitest-extended": "^4.4.21",
44
44
  "typescript": "^5.7.2",
45
- "vitest": "^2.1.5"
45
+ "vitest": "^2.1.8"
46
46
  },
47
47
  "publishConfig": {
48
48
  "access": "public"
49
- }
49
+ },
50
+ "stableVersion": "3.5.2"
50
51
  }
package/src/Builder.ts CHANGED
@@ -1,96 +1,93 @@
1
- import { assertEx } from '@xylabs/assert'
2
1
  import type { Hash } from '@xylabs/hex'
3
- import type {
4
- AnyObject, JsonArray, JsonObject,
5
- } from '@xylabs/object'
6
- import { isJsonObject, omitBy } from '@xylabs/object'
7
- import { PayloadHasher } from '@xyo-network/hash'
8
- import type {
9
- Payload, PayloadWithMeta, WithMeta,
2
+ import type { AnyObject } from '@xylabs/object'
3
+ import { ObjectHasher } from '@xyo-network/hash'
4
+ import {
5
+ type Payload,
6
+ SequenceParser,
7
+ type WithHashMeta,
8
+ type WithoutStorageMeta,
9
+ type WithStorageMeta,
10
10
  } from '@xyo-network/payload-model'
11
11
 
12
- import type { WithoutMeta, WithoutSchema } from './BuilderBase.ts'
13
- import { PayloadBuilderBase, removeMetaAndSchema } from './BuilderBase.ts'
14
- import type { PayloadBuilderOptions } from './Options.ts'
15
-
16
- export interface BuildOptions {
17
- stamp?: boolean
18
- validate?: boolean
19
- }
20
-
21
- const omitByPredicate = <T extends object>(prefix: string) => (_: T[keyof T], key: keyof T) => {
22
- assertEx(typeof key === 'string', () => `Invalid key type [${String(key)}, ${typeof key}]`)
23
- return (key as string).startsWith(prefix)
24
- }
12
+ import { PayloadBuilderBase } from './BuilderBase.ts'
25
13
 
26
14
  export class PayloadBuilder<
27
15
  T extends Payload = Payload<AnyObject>,
28
- O extends PayloadBuilderOptions<T> = PayloadBuilderOptions<T>,
29
- > extends PayloadBuilderBase<T, O> {
30
- static async build<T extends Payload = Payload<AnyObject>>(payload: T, options?: BuildOptions): Promise<WithMeta<T>>
31
- static async build<T extends Payload = Payload<AnyObject>>(payload: T[], options?: BuildOptions): Promise<WithMeta<T>[]>
32
- static async build<T extends Payload = Payload<AnyObject>>(payload: T | T[], options: BuildOptions = {}) {
33
- if (Array.isArray(payload)) {
34
- return await Promise.all(payload.map(payload => this.build(payload, options)))
16
+ > extends PayloadBuilderBase<T> {
17
+ static async addHashMeta<T extends Payload>(payload: T): Promise<WithHashMeta<T>>
18
+ static async addHashMeta<T extends Payload>(payloads: T[]): Promise<WithHashMeta<T>[]>
19
+ static async addHashMeta<T extends Payload>(payloads: T | T[]): Promise<WithHashMeta<T>[] | WithHashMeta<T>> {
20
+ if (Array.isArray(payloads)) {
21
+ return await Promise.all(
22
+ payloads.map(async (payload) => {
23
+ return await this.addHashMeta(payload)
24
+ }),
25
+ )
35
26
  } else {
36
- const { stamp = false, validate = true } = options
37
- const {
38
- schema, $hash: incomingDataHash, $meta: incomingMeta = {},
39
- } = payload as WithMeta<T>
40
-
41
- // check for legacy signatures
42
- const { _signatures } = payload as { _signatures?: JsonArray }
43
- if (_signatures && !incomingMeta.signatures) {
44
- incomingMeta.signatures = _signatures
27
+ const _hash = await PayloadBuilder.hash(payloads)
28
+ const _dataHash = await PayloadBuilder.dataHash(payloads)
29
+ return {
30
+ ...payloads,
31
+ _dataHash,
32
+ _hash,
45
33
  }
34
+ }
35
+ }
46
36
 
47
- const fields = removeMetaAndSchema(payload)
48
- const dataHashableFields = await PayloadBuilder.dataHashableFields(schema, fields)
49
- const $hash = validate || incomingDataHash === undefined ? await PayloadHasher.hash(dataHashableFields) : incomingDataHash
50
- const $meta: JsonObject = { ...incomingMeta }
51
- if ($meta.timestamp === undefined && stamp) {
52
- $meta.timestamp = Date.now()
53
- }
54
- const hashableFields: WithMeta<Payload> = {
55
- ...dataHashableFields, $hash, schema,
56
- }
37
+ static async addSequencedStorageMeta<T extends Payload = Payload>(payload: T): Promise<WithStorageMeta<T>> {
38
+ const withHashMeta = await this.addHashMeta(payload)
39
+ const _sequence = SequenceParser.from(Date.now(), withHashMeta._hash).localSequence
40
+ return {
41
+ ...withHashMeta,
42
+ _sequence,
43
+ }
44
+ }
57
45
 
58
- if (Object.keys($meta).length > 0) {
59
- hashableFields.$meta = $meta
60
- }
46
+ static async addStorageMeta<T extends Payload>(payload: T): Promise<WithStorageMeta<T>>
47
+ static async addStorageMeta<T extends Payload>(payloads: T[]): Promise<WithStorageMeta<T>[]>
48
+ static async addStorageMeta<T extends Payload>(payloads: T | T[]): Promise<WithStorageMeta<T>[] | WithStorageMeta<T>> {
49
+ return Array.isArray(payloads)
50
+ ? await (async () => {
51
+ return await Promise.all(payloads.map(async payload => await this.addSequencedStorageMeta(
52
+ payload,
53
+ )))
54
+ })()
55
+ : this.addSequencedStorageMeta(
56
+ payloads,
57
+ )
58
+ }
61
59
 
62
- return hashableFields as WithMeta<T>
63
- }
60
+ static compareStorageMeta(a: WithStorageMeta<Payload>, b: WithStorageMeta<Payload>) {
61
+ return a._sequence > b._sequence ? 1 : a._sequence < b._sequence ? -1 : 0
64
62
  }
65
63
 
66
- static async dataHash<T extends Payload>(payload: T, options?: BuildOptions): Promise<Hash> {
67
- return (await this.build(payload, options)).$hash
64
+ static async dataHash<T extends Payload>(payload: T): Promise<Hash> {
65
+ return await ObjectHasher.hash(this.omitMeta(payload))
68
66
  }
69
67
 
70
- static async dataHashPairs<T extends Payload>(payloads: T[], options?: BuildOptions): Promise<[WithMeta<T>, Hash][]> {
68
+ static async dataHashPairs<T extends Payload>(payloads: T[]): Promise<[T, Hash][]> {
71
69
  return await Promise.all(
72
70
  payloads.map(async (payload) => {
73
- const built = await PayloadBuilder.build(payload, options)
74
- return [built, built.$hash]
71
+ const dataHash = await this.dataHash(payload)
72
+ return [payload, dataHash]
75
73
  }),
76
74
  )
77
75
  }
78
76
 
79
- static async dataHashes(payloads: undefined, options?: BuildOptions): Promise<undefined>
80
- static async dataHashes<T extends Payload>(payloads: T[], options?: BuildOptions): Promise<Hash[]>
81
- static async dataHashes<T extends Payload>(payloads?: T[], options?: BuildOptions): Promise<Hash[] | undefined> {
77
+ static async dataHashes(payloads: undefined): Promise<undefined>
78
+ static async dataHashes<T extends Payload>(payloads: T[]): Promise<Hash[]>
79
+ static async dataHashes<T extends Payload>(payloads?: T[]): Promise<Hash[] | undefined> {
82
80
  return payloads
83
81
  ? await Promise.all(
84
82
  payloads.map(async (payload) => {
85
- const built = await PayloadBuilder.build(payload, options)
86
- return built.$hash
83
+ return await PayloadBuilder.dataHash(payload)
87
84
  }),
88
85
  )
89
86
  : undefined
90
87
  }
91
88
 
92
89
  static async filterExclude<T extends Payload>(payloads: T[] = [], hash: Hash[] | Hash): Promise<T[]> {
93
- return await PayloadHasher.filterExcludeByHash(await this.filterExcludeByDataHash(payloads, hash), hash)
90
+ return await ObjectHasher.filterExcludeByHash(await this.filterExcludeByDataHash(payloads, hash), hash)
94
91
  }
95
92
 
96
93
  static async filterExcludeByDataHash<T extends Payload>(payloads: T[] = [], hash: Hash[] | Hash): Promise<T[]> {
@@ -107,8 +104,8 @@ export class PayloadBuilder<
107
104
  return (await this.dataHashPairs(payloads)).find(([_, objHash]) => objHash === hash)?.[0]
108
105
  }
109
106
 
110
- static async hash<T extends Payload>(payload: T, options?: BuildOptions): Promise<Hash> {
111
- return await PayloadHasher.hash(await PayloadBuilder.build(payload, options))
107
+ static async hash<T extends Payload>(payload: T): Promise<Hash> {
108
+ return await ObjectHasher.hash(this.omitStorageMeta(payload))
112
109
  }
113
110
 
114
111
  /**
@@ -116,68 +113,47 @@ export class PayloadBuilder<
116
113
  * @param objs Any array of payloads
117
114
  * @returns An array of payload/hash tuples
118
115
  */
119
- static async hashPairs<T extends Payload>(payloads: T[], options?: BuildOptions): Promise<[WithMeta<T>, Hash][]> {
116
+ static async hashPairs<T extends Payload>(payloads: T[]): Promise<[T, Hash][]> {
120
117
  return await Promise.all(
121
- payloads.map<Promise<[WithMeta<T>, Hash]>>(async (payload) => {
122
- const built = await PayloadBuilder.build(payload, options)
123
- return [built, await PayloadBuilder.hash(built)]
118
+ payloads.map<Promise<[T, Hash]>>(async (payload) => {
119
+ return [payload, await PayloadBuilder.hash(payload)]
124
120
  }),
125
121
  )
126
122
  }
127
123
 
128
- static async hashableFields<T extends Payload = Payload<AnyObject>>(
129
- schema: string,
130
- fields?: WithoutSchema<WithoutMeta<T>>,
131
- $meta?: JsonObject,
132
- $hash?: Hash,
133
- timestamp?: number,
134
- stamp = false,
135
- ): Promise<WithMeta<T>> {
136
- const dataFields = await this.dataHashableFields<T>(schema, fields)
137
- assertEx($meta === undefined || isJsonObject($meta), () => '$meta must be JsonObject')
138
- const result: WithMeta<T> = omitBy(
139
- {
140
- ...dataFields,
141
- $hash: $hash ?? (await PayloadBuilder.dataHash(dataFields)),
142
- schema,
143
- } as WithMeta<T>,
144
- omitByPredicate('_'),
145
- ) as WithMeta<T>
146
-
147
- const clonedMeta = { ...$meta }
148
-
149
- if (timestamp) {
150
- clonedMeta.timestamp = timestamp
151
- }
152
-
153
- if (clonedMeta.timestamp === undefined && stamp) {
154
- clonedMeta.timestamp = Date.now()
155
- }
156
-
157
- if (Object.keys(clonedMeta).length > 0) {
158
- result.$meta = clonedMeta
159
- }
160
-
161
- return result
124
+ static hashableFields<T extends Payload>(
125
+ payload: T,
126
+ ): WithoutStorageMeta<T> {
127
+ return this.omitStorageMeta(payload)
162
128
  }
163
129
 
164
130
  static async hashes(payloads: undefined): Promise<undefined>
165
131
  static async hashes<T extends Payload>(payloads: T[]): Promise<Hash[]>
166
132
  static async hashes<T extends Payload>(payloads?: T[]): Promise<Hash[] | undefined> {
167
- return await PayloadHasher.hashes(payloads)
133
+ return await ObjectHasher.hashes(payloads)
168
134
  }
169
135
 
170
- static async toAllHashMap<T extends Payload>(objs: T[]): Promise<Record<Hash, WithMeta<T>>> {
171
- const result: Record<Hash, WithMeta<T>> = {}
172
- for (const pair of await this.hashPairs(objs)) {
136
+ static sortByStorageMeta<T extends Payload>(payloads: WithStorageMeta<T>[], direction: -1 | 1 = 1) {
137
+ return payloads.sort((a, b) =>
138
+ a._sequence < b._sequence
139
+ ? -direction
140
+ : a._sequence > b._sequence
141
+ ? direction
142
+ : 0)
143
+ }
144
+
145
+ static async toAllHashMap<T extends Payload>(payloads: T[]): Promise<Record<Hash, T>> {
146
+ const result: Record<Hash, T> = {}
147
+ for (const pair of await this.hashPairs(payloads)) {
148
+ const dataHash = await this.dataHash(pair[0])
173
149
  result[pair[1]] = pair[0]
174
- result[pair[0].$hash] = pair[0]
150
+ result[dataHash] = pair[0]
175
151
  }
176
152
  return result
177
153
  }
178
154
 
179
- static async toDataHashMap<T extends Payload>(objs: T[]): Promise<Record<Hash, WithMeta<T>>> {
180
- const result: Record<Hash, WithMeta<T>> = {}
155
+ static async toDataHashMap<T extends Payload>(objs: T[]): Promise<Record<Hash, T>> {
156
+ const result: Record<Hash, T> = {}
181
157
  for (const pair of await this.dataHashPairs(objs)) {
182
158
  result[pair[1]] = pair[0]
183
159
  }
@@ -189,41 +165,19 @@ export class PayloadBuilder<
189
165
  * @param objs Any array of payloads
190
166
  * @returns A map of hashes to payloads
191
167
  */
192
- static async toHashMap<T extends Payload>(objs: T[]): Promise<Record<Hash, WithMeta<T>>> {
193
- const result: Record<Hash, WithMeta<T>> = {}
168
+ static async toHashMap<T extends Payload>(objs: T[]): Promise<Record<Hash, T>> {
169
+ const result: Record<Hash, T> = {}
194
170
  for (const pair of await this.hashPairs(objs)) {
195
171
  result[pair[1]] = pair[0]
196
172
  }
197
173
  return result
198
174
  }
199
175
 
200
- static withoutMeta(payload: undefined): undefined
201
- static withoutMeta<T extends PayloadWithMeta>(payload: T): Omit<T, '$meta'>
202
- static withoutMeta<T extends PayloadWithMeta>(payloads: T[]): Omit<T, '$meta'>[]
203
- static withoutMeta<T extends PayloadWithMeta>(payloads: T | T[]) {
204
- if (Array.isArray(payloads)) {
205
- return payloads.map(payload => this.withoutMeta(payload))
206
- } else {
207
- if (payloads) {
208
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
209
- const { $meta, ...result } = payloads
210
- return result as Omit<T, '$meta'>
211
- }
212
- }
213
- }
214
-
215
- async build(options?: BuildOptions): Promise<WithMeta<T>> {
216
- const dataHashableFields = await this.dataHashableFields()
217
- return await PayloadBuilder.build<T>({
218
- ...dataHashableFields, $meta: this._$meta, schema: this._schema,
219
- } as Payload as T, options)
220
- }
221
-
222
- async hashableFields() {
223
- return await PayloadBuilder.hashableFields(
224
- assertEx(this._schema, () => 'Payload: Missing Schema'),
225
- this._fields,
226
- this._$meta,
227
- )
176
+ build(): T {
177
+ return {
178
+ schema: this._schema,
179
+ ...this._fields,
180
+ ...this._meta,
181
+ } as T
228
182
  }
229
183
  }
@@ -1,107 +1,105 @@
1
1
  import { assertEx } from '@xylabs/assert'
2
- import type { Hash } from '@xylabs/hex'
3
- import type { AnyObject, JsonObject } from '@xylabs/object'
2
+ import type { AnyObject, EmptyObject } from '@xylabs/object'
4
3
  import {
5
- isJsonObject, omitBy, toJson,
4
+ isJsonObject, omitByPrefix, pickByPrefix, toJson,
6
5
  } from '@xylabs/object'
7
6
  import type { Promisable } from '@xylabs/promise'
8
7
  import { removeEmptyFields } from '@xyo-network/hash'
9
8
  import type {
10
- Payload, Schema, WithMeta, WithOptionalMeta,
9
+ Payload, Schema,
10
+ WithOnlyClientMeta,
11
+ WithOptionalSchema,
12
+ WithoutClientMeta,
13
+ WithoutMeta,
14
+ WithoutPrivateStorageMeta,
15
+ WithoutSchema,
16
+ WithoutStorageMeta,
11
17
  } from '@xyo-network/payload-model'
12
18
 
13
19
  import type { PayloadBuilderOptions } from './Options.ts'
14
20
 
15
- export type WithOptionalSchema<T extends Payload> = Omit<T, 'schema'> & Partial<T>
16
-
17
- export type WithoutSchema<T extends WithOptionalSchema<Payload>> = Omit<T, 'schema'>
18
-
19
- export type WithoutMeta<T extends WithOptionalMeta<Payload>> = Omit<T, '$hash' | '$meta'>
20
-
21
- export const removeMetaAndSchema = <T extends Payload>(payload: WithOptionalSchema<WithOptionalMeta<T>>): WithoutSchema<WithoutMeta<T>> => {
22
- const { ...result } = payload
23
- delete result.$hash
24
- delete result.$meta
21
+ export const omitSchema = <T extends WithOptionalSchema>(payload: T): WithoutSchema<T> => {
22
+ const result = structuredClone(payload)
25
23
  delete result.schema
26
- return result as Omit<T, 'schema'>
24
+ return result
27
25
  }
28
26
 
29
- const omitByPredicate = (prefix: string) => (_: unknown, key: string) => {
30
- assertEx(typeof key === 'string', () => `Invalid key type [${key}, ${typeof key}]`)
31
- return key.startsWith(prefix)
32
- }
33
-
34
- export class PayloadBuilderBase<T extends Payload = Payload<AnyObject>, O extends PayloadBuilderOptions<T> = PayloadBuilderOptions<T>> {
35
- protected _$meta?: JsonObject
36
- protected _fields?: WithoutSchema<WithoutMeta<T>>
27
+ export class PayloadBuilderBase<T extends Payload = Payload<AnyObject>> {
28
+ protected _fields?: WithoutMeta<WithoutSchema<T>>
29
+ protected _meta?: WithOnlyClientMeta<T>
37
30
  protected _schema: Schema
38
31
 
39
- constructor(readonly options: O) {
40
- const {
41
- schema, fields, meta,
42
- } = options
32
+ constructor(readonly options: PayloadBuilderOptions) {
33
+ const { schema } = options
43
34
  this._schema = schema
44
- this._fields = removeEmptyFields(fields ?? {}) as WithoutSchema<WithoutMeta<T>>
45
- this._$meta = meta
46
35
  }
47
36
 
48
- static dataHashableFields<T extends Payload = Payload<AnyObject>>(
49
- schema: string,
50
- fields?: WithoutSchema<WithoutMeta<T>>,
51
- ): Promisable<Omit<T, '$hash' | '$meta'>> {
52
- const cleanFields = fields ? removeEmptyFields(fields) : undefined
37
+ static dataHashableFields<T extends Payload>(
38
+ schema: Schema,
39
+ payload: WithoutSchema<T>,
40
+
41
+ ): Promisable<WithoutMeta<T>> {
42
+ const cleanFields = removeEmptyFields({ ...payload, schema })
53
43
  assertEx(
54
44
  cleanFields === undefined || isJsonObject(cleanFields),
55
45
  () => `Fields must be JsonObject: ${JSON.stringify(toJson(cleanFields), null, 2)}`,
56
46
  )
57
- return omitBy(omitBy({ schema, ...cleanFields }, omitByPredicate('$')), omitByPredicate('_')) as unknown as T
47
+ return this.omitMeta(cleanFields) as WithoutMeta<T>
58
48
  }
59
49
 
60
- protected static metaFields(dataHash: Hash, otherMeta?: JsonObject, stamp = true): Promisable<JsonObject> {
61
- const meta: JsonObject = { ...otherMeta }
50
+ static omitClientMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutClientMeta<T>
51
+ static omitClientMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutClientMeta<T>[]
52
+ static omitClientMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutClientMeta<T> | WithoutClientMeta<T>[] {
53
+ return Array.isArray(payloads)
54
+ ? payloads.map(payload => this.omitClientMeta(payload, maxDepth))
55
+ : omitByPrefix(payloads, '$', maxDepth)
56
+ }
62
57
 
63
- if (!meta.timestamp && stamp) {
64
- meta.timestamp = meta.timestamp ?? Date.now()
65
- }
58
+ static omitMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutMeta<T>
59
+ static omitMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutMeta<T>[]
60
+ static omitMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutMeta<T> | WithoutMeta<T>[] {
61
+ return Array.isArray(payloads)
62
+ ? payloads.map(payload => this.omitMeta(payload, maxDepth))
63
+ : this.omitStorageMeta(this.omitClientMeta(payloads, maxDepth), maxDepth) as unknown as WithoutMeta<T>
64
+ }
66
65
 
67
- return meta
66
+ static omitPrivateStorageMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutPrivateStorageMeta<T>
67
+ static omitPrivateStorageMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutPrivateStorageMeta<T>[]
68
+ static omitPrivateStorageMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutPrivateStorageMeta<T> | WithoutPrivateStorageMeta<T>[] {
69
+ return Array.isArray(payloads)
70
+ ? payloads.map(payload => this.omitPrivateStorageMeta(payload, maxDepth))
71
+ : omitByPrefix(payloads, '__', maxDepth)
68
72
  }
69
73
 
70
- $meta(meta?: JsonObject) {
71
- this._$meta = meta ?? (this._fields as WithMeta<T>).$meta
72
- return this
74
+ static omitStorageMeta<T extends EmptyObject>(payload: T, maxDepth?: number): WithoutStorageMeta<T>
75
+ static omitStorageMeta<T extends EmptyObject>(payloads: T[], maxDepth?: number): WithoutStorageMeta<T>[]
76
+ static omitStorageMeta<T extends EmptyObject>(payloads: T | T[], maxDepth = 100): WithoutStorageMeta<T> | WithoutStorageMeta<T>[] {
77
+ return Array.isArray(payloads)
78
+ ? payloads.map(payload => this.omitStorageMeta(payload, maxDepth))
79
+ : omitByPrefix(payloads, '_', maxDepth)
73
80
  }
74
81
 
75
82
  async dataHashableFields() {
76
83
  return await PayloadBuilderBase.dataHashableFields(
77
84
  assertEx(this._schema, () => 'Payload: Missing Schema'),
78
- this._fields,
85
+ // TODO: Add verification that required fields are present
86
+ this._fields as WithoutSchema<T>,
79
87
  )
80
88
  }
81
89
 
82
- // we do not require sending in $hash since it will be generated anyway
83
- fields(fields: WithOptionalSchema<WithOptionalMeta<T>>) {
84
- if (fields) {
85
- const {
86
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
87
- $meta, $hash, schema, ...fieldsOnly
88
- } = fields
89
- if ($meta) {
90
- this.$meta($meta)
91
- }
92
- if (schema) {
93
- this.schema(schema)
94
- }
95
- this._fields = removeMetaAndSchema<T>(fields)
96
- }
90
+ fields(fields: WithoutMeta<WithoutSchema<T>>) {
91
+ // we need to do the cast here since ts seems to not like nested, yet same, generics
92
+ this._fields = omitSchema(PayloadBuilderBase.omitMeta(removeEmptyFields(structuredClone(fields)))) as unknown as WithoutMeta<WithoutSchema<T>>
97
93
  return this
98
94
  }
99
95
 
100
- schema(value: Schema) {
101
- this._schema = value
96
+ meta(meta: WithOnlyClientMeta<T>) {
97
+ // we need to do the cast here since ts seems to not like nested, yet same, generics
98
+ this._meta = pickByPrefix(meta, '$') as WithOnlyClientMeta<T>
99
+ return this
102
100
  }
103
101
 
104
- protected async metaFields(dataHash: Hash, stamp = true): Promise<JsonObject> {
105
- return await PayloadBuilderBase.metaFields(dataHash, this._$meta, stamp)
102
+ schema(value: Schema) {
103
+ this._schema = value
106
104
  }
107
105
  }
package/src/Options.ts CHANGED
@@ -1,10 +1,7 @@
1
1
  import type { Logger } from '@xylabs/logger'
2
- import type { JsonObject } from '@xylabs/object'
3
2
  import type { Schema } from '@xyo-network/payload-model'
4
3
 
5
- export interface PayloadBuilderOptions<T> {
6
- readonly fields?: Omit<T, 'schema' | '$hash' | '$meta'>
4
+ export interface PayloadBuilderOptions {
7
5
  readonly logger?: Logger
8
- readonly meta?: JsonObject
9
6
  readonly schema: Schema
10
7
  }