@wovin/core 0.2.2 → 0.3.0
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/dist/applog/datom-types.d.ts.map +1 -1
- package/dist/applog.js +1 -1
- package/dist/blockstore.js +2 -0
- package/dist/blockstore.js.map +1 -1
- package/dist/{chunk-SHUHRHOT.js → chunk-2OXLPZQI.js} +10 -3
- package/dist/chunk-2OXLPZQI.js.map +1 -0
- package/dist/{chunk-3SUFNJEZ.js → chunk-2PJFLZRC.js} +7 -2
- package/dist/{chunk-3SUFNJEZ.js.map → chunk-2PJFLZRC.js.map} +1 -1
- package/dist/chunk-64EJIJAJ.js +17 -0
- package/dist/chunk-64EJIJAJ.js.map +1 -0
- package/dist/chunk-7QEGHKR4.js +17 -0
- package/dist/chunk-7QEGHKR4.js.map +1 -0
- package/dist/{chunk-OC6Z6CQW.js → chunk-EHO2BFFY.js} +2 -2
- package/dist/chunk-ICBK7NC4.js +27 -0
- package/dist/chunk-ICBK7NC4.js.map +1 -0
- package/dist/{chunk-22WDFLXO.js → chunk-OKXRRWNS.js} +3 -3
- package/dist/{chunk-6ALNRM3J.js → chunk-Q4EMPWA3.js} +15 -8
- package/dist/chunk-Q4EMPWA3.js.map +1 -0
- package/dist/{chunk-HUIQ54TT.js → chunk-VGIACGWX.js} +3 -3
- package/dist/{chunk-BLF5MAWU.js → chunk-WVW4YXB5.js} +2 -2
- package/dist/chunk-XF4DWOAE.js +25 -0
- package/dist/chunk-XF4DWOAE.js.map +1 -0
- package/dist/index.js +7 -7
- package/dist/ipfs/car.d.ts.map +1 -1
- package/dist/ipfs.js +4 -4
- package/dist/ipns/gateway-resolver.d.ts +21 -0
- package/dist/ipns/gateway-resolver.d.ts.map +1 -0
- package/dist/ipns/ipns-record.d.ts +28 -7
- package/dist/ipns/ipns-record.d.ts.map +1 -1
- package/dist/ipns/ipns-w3name.d.ts +15 -0
- package/dist/ipns/ipns-w3name.d.ts.map +1 -0
- package/dist/ipns/ipns-watcher.d.ts +190 -0
- package/dist/ipns/ipns-watcher.d.ts.map +1 -0
- package/dist/ipns.d.ts +3 -0
- package/dist/ipns.d.ts.map +1 -1
- package/dist/ipns.js +488 -8
- package/dist/ipns.js.map +1 -1
- package/dist/pubsub/snap-push.d.ts +2 -2
- package/dist/pubsub/snap-push.d.ts.map +1 -1
- package/dist/pubsub.js +4 -4
- package/dist/query.js +3 -3
- package/dist/retrieve.js +4 -4
- package/dist/thread.js +1 -1
- package/dist/viewmodel/adapters/arktype.d.ts +33 -0
- package/dist/viewmodel/adapters/arktype.d.ts.map +1 -0
- package/dist/viewmodel/adapters/arktype.js +7 -0
- package/dist/viewmodel/adapters/arktype.js.map +1 -0
- package/dist/viewmodel/adapters/typebox.d.ts +35 -0
- package/dist/viewmodel/adapters/typebox.d.ts.map +1 -0
- package/dist/viewmodel/adapters/typebox.js +7 -0
- package/dist/viewmodel/adapters/typebox.js.map +1 -0
- package/dist/viewmodel/adapters/typia.d.ts +40 -0
- package/dist/viewmodel/adapters/typia.d.ts.map +1 -0
- package/dist/viewmodel/adapters/typia.js +7 -0
- package/dist/viewmodel/adapters/typia.js.map +1 -0
- package/dist/viewmodel/adapters/zod.d.ts +30 -0
- package/dist/viewmodel/adapters/zod.d.ts.map +1 -0
- package/dist/viewmodel/adapters/zod.js +7 -0
- package/dist/viewmodel/adapters/zod.js.map +1 -0
- package/dist/viewmodel/builder.d.ts +40 -0
- package/dist/viewmodel/builder.d.ts.map +1 -0
- package/dist/viewmodel/examples/all-adapters.d.ts +26 -0
- package/dist/viewmodel/examples/all-adapters.d.ts.map +1 -0
- package/dist/viewmodel/factory.d.ts +38 -0
- package/dist/viewmodel/factory.d.ts.map +1 -0
- package/dist/viewmodel/index.d.ts +10 -0
- package/dist/viewmodel/index.d.ts.map +1 -0
- package/dist/viewmodel/index.js +313 -0
- package/dist/viewmodel/index.js.map +1 -0
- package/dist/viewmodel/schema-adapter.d.ts +16 -0
- package/dist/viewmodel/schema-adapter.d.ts.map +1 -0
- package/dist/viewmodel/types.d.ts +97 -0
- package/dist/viewmodel/types.d.ts.map +1 -0
- package/package.json +29 -3
- package/src/applog/datom-types.ts +2 -2
- package/src/ipfs/car.ts +8 -2
- package/src/ipns/gateway-resolver.ts +63 -0
- package/src/ipns/ipns-record.ts +68 -17
- package/src/ipns/ipns-w3name.ts +103 -0
- package/src/ipns/ipns-watcher.ts +607 -0
- package/src/ipns.ts +3 -0
- package/src/pubsub/snap-push.ts +6 -5
- package/src/viewmodel/adapters/arktype.ts +44 -0
- package/src/viewmodel/adapters/typebox.ts +59 -0
- package/src/viewmodel/adapters/typia.ts +50 -0
- package/src/viewmodel/adapters/zod.ts +55 -0
- package/src/viewmodel/builder.ts +71 -0
- package/src/viewmodel/examples/all-adapters.ts +206 -0
- package/src/viewmodel/factory.ts +330 -0
- package/src/viewmodel/index.ts +22 -0
- package/src/viewmodel/schema-adapter.ts +27 -0
- package/src/viewmodel/types.ts +152 -0
- package/dist/chunk-6ALNRM3J.js.map +0 -1
- package/dist/chunk-SHUHRHOT.js.map +0 -1
- /package/dist/{chunk-OC6Z6CQW.js.map → chunk-EHO2BFFY.js.map} +0 -0
- /package/dist/{chunk-22WDFLXO.js.map → chunk-OKXRRWNS.js.map} +0 -0
- /package/dist/{chunk-HUIQ54TT.js.map → chunk-VGIACGWX.js.map} +0 -0
- /package/dist/{chunk-BLF5MAWU.js.map → chunk-WVW4YXB5.js.map} +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ApplogValue } from '../../applog/datom-types.ts'
|
|
2
|
+
import type { ISchemaAdapter, VMAttributeDef } from '../types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a schema adapter from a TypeBox object schema.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { Type } from '@sinclair/typebox'
|
|
10
|
+
* import { createTypeBoxAdapter } from '@wovin/core/viewmodel/adapters/typebox'
|
|
11
|
+
*
|
|
12
|
+
* const MySchema = Type.Object({
|
|
13
|
+
* name: Type.String(),
|
|
14
|
+
* age: Type.Optional(Type.Number()),
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* const adapter = createTypeBoxAdapter(MySchema, 'myEntity')
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* The type parameter `T` is the inferred static type of the schema.
|
|
21
|
+
* Can pass a compiled validator separately if runtime validation is needed.
|
|
22
|
+
*/
|
|
23
|
+
export function createTypeBoxAdapter<T extends Record<string, ApplogValue>>(
|
|
24
|
+
typeBoxSchema: { properties: Record<string, any>; type?: string },
|
|
25
|
+
entityPrefix: string,
|
|
26
|
+
options?: {
|
|
27
|
+
/** Override at-paths for specific attributes */
|
|
28
|
+
atOverrides?: Record<string, string>
|
|
29
|
+
/** Default values */
|
|
30
|
+
defaults?: Partial<T>
|
|
31
|
+
/** Property name to at-path mapping function */
|
|
32
|
+
toAtPath?: (entityPrefix: string, attrName: string) => string
|
|
33
|
+
/** A pre-compiled validator function (e.g. from TypeCompiler.Compile) */
|
|
34
|
+
validator?: (value: unknown) => value is T
|
|
35
|
+
},
|
|
36
|
+
): ISchemaAdapter<T> {
|
|
37
|
+
const properties = typeBoxSchema.properties as Record<string, any>
|
|
38
|
+
const toAtPath = options?.toAtPath ?? ((prefix, name) => `${prefix}/${name}`)
|
|
39
|
+
|
|
40
|
+
const attributeDefs: VMAttributeDef[] = Object.entries(properties).map(([name, propSchema]: [string, any]) => {
|
|
41
|
+
const isOptional = propSchema.optional ?? false
|
|
42
|
+
const wovinAtName = propSchema.wovinAtName
|
|
43
|
+
const atPath = options?.atOverrides?.[name] ?? wovinAtName ?? toAtPath(entityPrefix, name)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
name,
|
|
47
|
+
atPath,
|
|
48
|
+
optional: isOptional,
|
|
49
|
+
defaultValue: propSchema.default,
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
getAttributeDefs: () => attributeDefs,
|
|
55
|
+
getDefaults: () => (options?.defaults ?? {}) as Partial<T>,
|
|
56
|
+
getEntityPrefix: () => entityPrefix,
|
|
57
|
+
createValidator: options?.validator ? () => options.validator! : undefined,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ApplogValue } from '../../applog/datom-types.ts'
|
|
2
|
+
import type { ISchemaAdapter, VMAttributeDef } from '../types.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pattern for creating a schema adapter from a Typia-generated schema.
|
|
6
|
+
*
|
|
7
|
+
* Typia is NOT a runtime dependency of @wovin/core, so this adapter
|
|
8
|
+
* works by accepting the Typia type object directly along with the
|
|
9
|
+
* attribute definitions (which must be provided separately since
|
|
10
|
+
* Typia doesn't expose runtime property introspection by default).
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```ts
|
|
14
|
+
* import typia from 'typia'
|
|
15
|
+
* import { createTypiaAdapter } from '@wovin/core/viewmodel/adapters/typia'
|
|
16
|
+
*
|
|
17
|
+
* interface MyEntity { name: string; age?: number }
|
|
18
|
+
*
|
|
19
|
+
* const adapter = createTypiaAdapter<MyEntity>(
|
|
20
|
+
* typia.createValidate<MyEntity>(),
|
|
21
|
+
* 'myEntity',
|
|
22
|
+
* {
|
|
23
|
+
* attributes: [
|
|
24
|
+
* { name: 'name', atPath: 'myEntity/name', optional: false },
|
|
25
|
+
* { name: 'age', atPath: 'myEntity/age', optional: true },
|
|
26
|
+
* ],
|
|
27
|
+
* },
|
|
28
|
+
* )
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function createTypiaAdapter<T extends Record<string, ApplogValue>>(
|
|
32
|
+
_typiaValidator: (input: unknown) => { success: boolean; data: T | null; errors?: any[] },
|
|
33
|
+
entityPrefix: string,
|
|
34
|
+
options: {
|
|
35
|
+
/** Attribute definitions (required for Typia since property introspection is compile-time) */
|
|
36
|
+
attributes: VMAttributeDef[]
|
|
37
|
+
/** Default values */
|
|
38
|
+
defaults?: Partial<T>
|
|
39
|
+
},
|
|
40
|
+
): ISchemaAdapter<T> {
|
|
41
|
+
return {
|
|
42
|
+
getAttributeDefs: () => options.attributes,
|
|
43
|
+
getDefaults: () => (options?.defaults ?? {}) as Partial<T>,
|
|
44
|
+
getEntityPrefix: () => entityPrefix,
|
|
45
|
+
createValidator: () => (value: unknown): value is T => {
|
|
46
|
+
const result = _typiaValidator(value)
|
|
47
|
+
return result.success
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ApplogValue } from '../../applog/datom-types.ts'
|
|
2
|
+
import type { ISchemaAdapter, VMAttributeDef } from '../types.ts'
|
|
3
|
+
import type { ZodObject, ZodType, ZodTypeAny } from 'zod'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create a schema adapter from a Zod object schema.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { z } from 'zod'
|
|
11
|
+
* import { createZodAdapter } from '@wovin/core/viewmodel/adapters/zod'
|
|
12
|
+
*
|
|
13
|
+
* const MySchema = z.object({
|
|
14
|
+
* name: z.string(),
|
|
15
|
+
* age: z.number().optional(),
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* const adapter = createZodAdapter(MySchema, 'myEntity')
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The type parameter `T` is the inferred type of the schema.
|
|
22
|
+
*/
|
|
23
|
+
export function createZodAdapter<T extends Record<string, ApplogValue> = Record<string, ApplogValue>>(
|
|
24
|
+
zodSchema: ZodObject<Record<string, ZodTypeAny>>,
|
|
25
|
+
entityPrefix: string,
|
|
26
|
+
options?: {
|
|
27
|
+
/** Override at-paths for specific attributes */
|
|
28
|
+
atOverrides?: Record<string, string>
|
|
29
|
+
/** Default values */
|
|
30
|
+
defaults?: Partial<T>
|
|
31
|
+
/** Property name to at-path mapping function */
|
|
32
|
+
toAtPath?: (entityPrefix: string, attrName: string) => string
|
|
33
|
+
},
|
|
34
|
+
): ISchemaAdapter<T> {
|
|
35
|
+
const shape = zodSchema.shape as Record<string, ZodTypeAny>
|
|
36
|
+
const toAtPath = options?.toAtPath ?? ((prefix, name) => `${prefix}/${name}`)
|
|
37
|
+
|
|
38
|
+
const attributeDefs: VMAttributeDef[] = Object.entries(shape).map(([name, fieldSchema]: [string, ZodTypeAny]) => {
|
|
39
|
+
const isOptional = fieldSchema.isOptional() || fieldSchema.isNullable()
|
|
40
|
+
const atPath = options?.atOverrides?.[name] ?? toAtPath(entityPrefix, name)
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
name,
|
|
44
|
+
atPath,
|
|
45
|
+
optional: isOptional,
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
getAttributeDefs: () => attributeDefs,
|
|
51
|
+
getDefaults: () => (options?.defaults ?? {}) as Partial<T>,
|
|
52
|
+
getEntityPrefix: () => entityPrefix,
|
|
53
|
+
createValidator: () => (value: unknown): value is T => zodSchema.safeParse(value).success,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ApplogForInsertOptionalAgent, ApplogValue, EntityID } from '../applog/datom-types.ts'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic ObjectBuilder for type-safe entity creation and updates.
|
|
5
|
+
*
|
|
6
|
+
* Provides a fluent API to build a set of applogs for an entity.
|
|
7
|
+
* Modeled after the note3 builder pattern.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* ```ts
|
|
11
|
+
* ObjectBuilder.create({ name: 'foo' })
|
|
12
|
+
* .update({ type: 'bar' })
|
|
13
|
+
* .build(thread)
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export class ObjectBuilder<
|
|
17
|
+
TARGET extends Record<string, ApplogValue> = Record<string, ApplogValue>,
|
|
18
|
+
> {
|
|
19
|
+
constructor(
|
|
20
|
+
private _data: Partial<TARGET>,
|
|
21
|
+
public en: EntityID | null = null,
|
|
22
|
+
private _atPrefix: string | null = null,
|
|
23
|
+
private _atOverrides: Partial<Record<keyof TARGET, string>> = {},
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create a new builder with initial data.
|
|
28
|
+
*/
|
|
29
|
+
static create<TARGET extends Record<string, ApplogValue>>(
|
|
30
|
+
init: Partial<TARGET> = {},
|
|
31
|
+
en?: EntityID,
|
|
32
|
+
atPrefix?: string,
|
|
33
|
+
atOverrides?: Partial<Record<keyof TARGET, string>>,
|
|
34
|
+
): ObjectBuilder<TARGET> {
|
|
35
|
+
return new ObjectBuilder<TARGET>(init, en, atPrefix, atOverrides)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Update the data being built.
|
|
40
|
+
*/
|
|
41
|
+
update(updateObj: Partial<TARGET>): this {
|
|
42
|
+
Object.assign(this._data, updateObj)
|
|
43
|
+
return this
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Build the applogs for this entity, optionally resolving against a thread.
|
|
48
|
+
*/
|
|
49
|
+
build(thread?: {
|
|
50
|
+
insert(applogs: ApplogForInsertOptionalAgent[]): ApplogForInsertOptionalAgent[]
|
|
51
|
+
}): ApplogForInsertOptionalAgent[] {
|
|
52
|
+
const atPrefix = this._atPrefix
|
|
53
|
+
const applogs: ApplogForInsertOptionalAgent[] = []
|
|
54
|
+
|
|
55
|
+
for (const [key, value] of Object.entries(this._data) as [keyof TARGET, ApplogValue][]) {
|
|
56
|
+
if (value === undefined) continue
|
|
57
|
+
const atOverride = this._atOverrides[key]
|
|
58
|
+
const at = atOverride ?? (atPrefix ? `${atPrefix}/${String(key)}` : String(key))
|
|
59
|
+
applogs.push({ en: this.en!, at, vl: value })
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return applogs
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get the raw data being built.
|
|
67
|
+
*/
|
|
68
|
+
get data(): Partial<TARGET> {
|
|
69
|
+
return { ...this._data }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════════
|
|
3
|
+
* Schema Adapter Examples
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════
|
|
5
|
+
*
|
|
6
|
+
* This file demonstrates how to use each schema adapter with the
|
|
7
|
+
* generic ViewModel factory. Uncomment the adapter you want to use.
|
|
8
|
+
*
|
|
9
|
+
* Each section is self-contained and shows:
|
|
10
|
+
* 1. Schema definition
|
|
11
|
+
* 2. Adapter creation
|
|
12
|
+
* 3. ViewModel factory usage
|
|
13
|
+
* 4. Basic VM usage
|
|
14
|
+
*
|
|
15
|
+
* Note: Not all schema libraries are installed as dependencies.
|
|
16
|
+
* ✓ TypeBox — peer dependency of @wovin/core (available)
|
|
17
|
+
* ✓ Zod — dependency of @wovin/core (available)
|
|
18
|
+
* ✗ ArkType — NOT installed (example shown for pattern reference)
|
|
19
|
+
* ✗ Typia — NOT installed (example shown for pattern reference)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { createViewModelFactory, ObjectBuilder, type ISchemaAdapter, type VMAttributeDef } from '../index.ts'
|
|
23
|
+
import type { Thread } from '../../thread/basic.ts'
|
|
24
|
+
import type { ApplogValue, EntityID } from '../../applog/datom-types.ts'
|
|
25
|
+
|
|
26
|
+
// ═══════════════════════════════════════════════════════════════
|
|
27
|
+
// Shared helpers for examples
|
|
28
|
+
// ═══════════════════════════════════════════════════════════════
|
|
29
|
+
|
|
30
|
+
/** Dummy thread for examples */
|
|
31
|
+
function createMockThread(): Thread {
|
|
32
|
+
return { name: 'mock', applogs: [], filters: [], subscribe: () => () => {} } as unknown as Thread
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface Note extends Record<string, ApplogValue> {
|
|
36
|
+
title: string
|
|
37
|
+
body: string
|
|
38
|
+
tags?: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════
|
|
42
|
+
// 1. TypeBox Adapter Example
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════
|
|
44
|
+
|
|
45
|
+
// import { Type } from '@sinclair/typebox'
|
|
46
|
+
// import { Static } from '@sinclair/typebox'
|
|
47
|
+
// import { createTypeBoxAdapter } from '../adapters/typebox.ts'
|
|
48
|
+
|
|
49
|
+
export function typeBoxExample() {
|
|
50
|
+
/*
|
|
51
|
+
|
|
52
|
+
const NoteSchema = Type.Object({
|
|
53
|
+
title: Type.String(),
|
|
54
|
+
body: Type.String(),
|
|
55
|
+
tags: Type.Optional(Type.String()),
|
|
56
|
+
})
|
|
57
|
+
type Note = Static<typeof NoteSchema>
|
|
58
|
+
|
|
59
|
+
const NoteVM = createViewModelFactory<Note>({
|
|
60
|
+
adapter: createTypeBoxAdapter(NoteSchema, 'note', {
|
|
61
|
+
atOverrides: {
|
|
62
|
+
title: 'note/title',
|
|
63
|
+
body: 'note/body',
|
|
64
|
+
tags: 'note/tags',
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
vmName: 'Note',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const thread = createMockThread()
|
|
71
|
+
const note = NoteVM.get('abc123' as EntityID, thread)
|
|
72
|
+
console.log(note.title) // reactive read
|
|
73
|
+
note.title = 'Hello' // writes to thread via applog
|
|
74
|
+
|
|
75
|
+
*/
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ═══════════════════════════════════════════════════════════════
|
|
79
|
+
// 2. Zod Adapter Example
|
|
80
|
+
// ═══════════════════════════════════════════════════════════════
|
|
81
|
+
|
|
82
|
+
// import { z } from 'zod'
|
|
83
|
+
// import { createZodAdapter } from '../adapters/zod.ts'
|
|
84
|
+
|
|
85
|
+
export function zodExample() {
|
|
86
|
+
/*
|
|
87
|
+
|
|
88
|
+
const NoteSchema = z.object({
|
|
89
|
+
title: z.string(),
|
|
90
|
+
body: z.string(),
|
|
91
|
+
tags: z.string().optional(),
|
|
92
|
+
})
|
|
93
|
+
type Note = z.infer<typeof NoteSchema>
|
|
94
|
+
|
|
95
|
+
const NoteVM = createViewModelFactory<Note>({
|
|
96
|
+
adapter: createZodAdapter(NoteSchema, 'note', {
|
|
97
|
+
atOverrides: {
|
|
98
|
+
title: 'note/title',
|
|
99
|
+
body: 'note/body',
|
|
100
|
+
tags: 'note/tags',
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
vmName: 'Note',
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const thread = createMockThread()
|
|
107
|
+
const note = NoteVM.get('abc123' as EntityID, thread)
|
|
108
|
+
console.log(note.title)
|
|
109
|
+
note.title = 'Hello'
|
|
110
|
+
|
|
111
|
+
*/
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ═══════════════════════════════════════════════════════════════
|
|
115
|
+
// 3. ArkType Adapter Pattern
|
|
116
|
+
// ═══════════════════════════════════════════════════════════════
|
|
117
|
+
// ArkType is NOT a dependency. This shows the pattern if you install it.
|
|
118
|
+
|
|
119
|
+
// import { createArkTypeAdapter } from '../adapters/arktype.ts'
|
|
120
|
+
|
|
121
|
+
export function arkTypePattern() {
|
|
122
|
+
/*
|
|
123
|
+
|
|
124
|
+
// First, define attributes manually (ArkType doesn't expose runtime props)
|
|
125
|
+
const attrs: VMAttributeDef[] = [
|
|
126
|
+
{ name: 'title', atPath: 'note/title', optional: false },
|
|
127
|
+
{ name: 'body', atPath: 'note/body', optional: false },
|
|
128
|
+
{ name: 'tags', atPath: 'note/tags', optional: true },
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
// Then create the adapter with a validator
|
|
132
|
+
// import { type } from 'arktype'
|
|
133
|
+
// const NoteSchema = type({ title: 'string', body: 'string', 'tags?': 'string' })
|
|
134
|
+
|
|
135
|
+
const NoteVM = createViewModelFactory<Note>({
|
|
136
|
+
adapter: createArkTypeAdapter(
|
|
137
|
+
// NoteSchema, // your arktype validator
|
|
138
|
+
{} as any, // placeholder
|
|
139
|
+
'note',
|
|
140
|
+
{ attributes: attrs },
|
|
141
|
+
),
|
|
142
|
+
vmName: 'Note',
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
*/
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ═══════════════════════════════════════════════════════════════
|
|
149
|
+
// 4. Typia Adapter Pattern
|
|
150
|
+
// ═══════════════════════════════════════════════════════════════
|
|
151
|
+
// Typia is NOT a dependency. This shows the pattern if you install it.
|
|
152
|
+
|
|
153
|
+
// import { createTypiaAdapter } from '../adapters/typia.ts'
|
|
154
|
+
|
|
155
|
+
export function typiaPattern() {
|
|
156
|
+
/*
|
|
157
|
+
|
|
158
|
+
// Define attributes manually (Typia strips types at compile time)
|
|
159
|
+
const attrs: VMAttributeDef[] = [
|
|
160
|
+
{ name: 'title', atPath: 'note/title', optional: false },
|
|
161
|
+
{ name: 'body', atPath: 'note/body', optional: false },
|
|
162
|
+
{ name: 'tags', atPath: 'note/tags', optional: true },
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
// Then create the adapter with a typia validator
|
|
166
|
+
// import typia from 'typia'
|
|
167
|
+
// interface Note { title: string; body: string; tags?: string }
|
|
168
|
+
// const validate = typia.createValidate<Note>()
|
|
169
|
+
|
|
170
|
+
const NoteVM = createViewModelFactory<Note>({
|
|
171
|
+
adapter: createTypiaAdapter(
|
|
172
|
+
// validate, // your typia validator
|
|
173
|
+
{} as any, // placeholder
|
|
174
|
+
'note',
|
|
175
|
+
{ attributes: attrs },
|
|
176
|
+
),
|
|
177
|
+
vmName: 'Note',
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
*/
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ═══════════════════════════════════════════════════════════════
|
|
184
|
+
// 5. Minimal adapter (no schema library)
|
|
185
|
+
// ═══════════════════════════════════════════════════════════════
|
|
186
|
+
|
|
187
|
+
export function minimalNoSchemaExample() {
|
|
188
|
+
// You don't need a schema library at all — use createAdapterFromAttributes
|
|
189
|
+
|
|
190
|
+
const adapter: ISchemaAdapter<Note> = {
|
|
191
|
+
getAttributeDefs: (): VMAttributeDef[] => [
|
|
192
|
+
{ name: 'title', atPath: 'note/title', optional: false },
|
|
193
|
+
{ name: 'body', atPath: 'note/body', optional: false },
|
|
194
|
+
{ name: 'tags', atPath: 'note/tags', optional: true },
|
|
195
|
+
],
|
|
196
|
+
getDefaults: () => ({ title: '', body: '' }),
|
|
197
|
+
getEntityPrefix: () => 'note',
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const NoteVM = createViewModelFactory<Note>({
|
|
201
|
+
adapter,
|
|
202
|
+
vmName: 'Note',
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
console.log('Minimal NoteVM created:', NoteVM.vmName)
|
|
206
|
+
}
|