@wovin/core 0.2.2 → 0.3.2
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/applog-utils.d.ts +25 -1
- package/dist/applog/applog-utils.d.ts.map +1 -1
- package/dist/applog/datom-types.d.ts.map +1 -1
- package/dist/applog.js +5 -3
- package/dist/blockstore.js +2 -0
- package/dist/blockstore.js.map +1 -1
- package/dist/{chunk-SHUHRHOT.js → chunk-4MKPGQIM.js} +17 -18
- package/dist/chunk-4MKPGQIM.js.map +1 -0
- package/dist/chunk-64EJIJAJ.js +17 -0
- package/dist/chunk-64EJIJAJ.js.map +1 -0
- package/dist/{chunk-HUIQ54TT.js → chunk-6CSJTSQP.js} +3 -3
- package/dist/chunk-7QEGHKR4.js +17 -0
- package/dist/chunk-7QEGHKR4.js.map +1 -0
- package/dist/{chunk-BLF5MAWU.js → chunk-BIYQEX3N.js} +2 -2
- package/dist/{chunk-6ALNRM3J.js → chunk-H3JNNTVP.js} +21 -8
- package/dist/chunk-H3JNNTVP.js.map +1 -0
- package/dist/{chunk-OC6Z6CQW.js → chunk-H4YVJKB7.js} +2 -2
- package/dist/chunk-ICBK7NC4.js +27 -0
- package/dist/chunk-ICBK7NC4.js.map +1 -0
- package/dist/chunk-N5QPZNKD.js +288 -0
- package/dist/chunk-N5QPZNKD.js.map +1 -0
- package/dist/{chunk-3SUFNJEZ.js → chunk-N7SEGHU4.js} +7 -2
- package/dist/{chunk-3SUFNJEZ.js.map → chunk-N7SEGHU4.js.map} +1 -1
- package/dist/chunk-XF4DWOAE.js +25 -0
- package/dist/chunk-XF4DWOAE.js.map +1 -0
- package/dist/index.js +20 -10
- 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 +46 -7
- package/dist/ipns/ipns-record.d.ts.map +1 -1
- package/dist/ipns/ipns-w3name.d.ts +45 -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 +591 -14
- 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/epoch-snapshot.d.ts +205 -0
- package/dist/query/epoch-snapshot.d.ts.map +1 -0
- package/dist/query.d.ts +1 -0
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +12 -4
- 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/applog-utils.test.ts +43 -1
- package/src/applog/applog-utils.ts +38 -21
- package/src/applog/datom-types.ts +2 -2
- package/src/applog/object-values.test.ts +9 -9
- package/src/ipfs/car.ts +14 -2
- package/src/ipns/gateway-resolver.ts +63 -0
- package/src/ipns/ipns-record.ts +158 -29
- package/src/ipns/ipns-w3name.ts +207 -0
- package/src/ipns/ipns-watcher.ts +608 -0
- package/src/ipns.ts +3 -0
- package/src/pubsub/snap-push.ts +6 -5
- package/src/query/epoch-snapshot.test.ts +594 -0
- package/src/query/epoch-snapshot.ts +392 -0
- package/src/query.ts +1 -0
- 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-22WDFLXO.js +0 -138
- package/dist/chunk-22WDFLXO.js.map +0 -1
- package/dist/chunk-6ALNRM3J.js.map +0 -1
- package/dist/chunk-SHUHRHOT.js.map +0 -1
- /package/dist/{chunk-HUIQ54TT.js.map → chunk-6CSJTSQP.js.map} +0 -0
- /package/dist/{chunk-BLF5MAWU.js.map → chunk-BIYQEX3N.js.map} +0 -0
- /package/dist/{chunk-OC6Z6CQW.js.map → chunk-H4YVJKB7.js.map} +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ApplogValue } from '../../applog/datom-types.ts';
|
|
2
|
+
import type { ISchemaAdapter, VMAttributeDef } from '../types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Pattern for creating a schema adapter from a Typia-generated schema.
|
|
5
|
+
*
|
|
6
|
+
* Typia is NOT a runtime dependency of @wovin/core, so this adapter
|
|
7
|
+
* works by accepting the Typia type object directly along with the
|
|
8
|
+
* attribute definitions (which must be provided separately since
|
|
9
|
+
* Typia doesn't expose runtime property introspection by default).
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```ts
|
|
13
|
+
* import typia from 'typia'
|
|
14
|
+
* import { createTypiaAdapter } from '@wovin/core/viewmodel/adapters/typia'
|
|
15
|
+
*
|
|
16
|
+
* interface MyEntity { name: string; age?: number }
|
|
17
|
+
*
|
|
18
|
+
* const adapter = createTypiaAdapter<MyEntity>(
|
|
19
|
+
* typia.createValidate<MyEntity>(),
|
|
20
|
+
* 'myEntity',
|
|
21
|
+
* {
|
|
22
|
+
* attributes: [
|
|
23
|
+
* { name: 'name', atPath: 'myEntity/name', optional: false },
|
|
24
|
+
* { name: 'age', atPath: 'myEntity/age', optional: true },
|
|
25
|
+
* ],
|
|
26
|
+
* },
|
|
27
|
+
* )
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function createTypiaAdapter<T extends Record<string, ApplogValue>>(_typiaValidator: (input: unknown) => {
|
|
31
|
+
success: boolean;
|
|
32
|
+
data: T | null;
|
|
33
|
+
errors?: any[];
|
|
34
|
+
}, entityPrefix: string, options: {
|
|
35
|
+
/** Attribute definitions (required for Typia since property introspection is compile-time) */
|
|
36
|
+
attributes: VMAttributeDef[];
|
|
37
|
+
/** Default values */
|
|
38
|
+
defaults?: Partial<T>;
|
|
39
|
+
}): ISchemaAdapter<T>;
|
|
40
|
+
//# sourceMappingURL=typia.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typia.d.ts","sourceRoot":"","sources":["../../../src/viewmodel/adapters/typia.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACvE,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,EACzF,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE;IACR,8FAA8F;IAC9F,UAAU,EAAE,cAAc,EAAE,CAAA;IAC5B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CACrB,GACC,cAAc,CAAC,CAAC,CAAC,CAUnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ApplogValue } from '../../applog/datom-types.ts';
|
|
2
|
+
import type { ISchemaAdapter } from '../types.ts';
|
|
3
|
+
import type { ZodObject, ZodTypeAny } from 'zod';
|
|
4
|
+
/**
|
|
5
|
+
* Create a schema adapter from a Zod object schema.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { z } from 'zod'
|
|
10
|
+
* import { createZodAdapter } from '@wovin/core/viewmodel/adapters/zod'
|
|
11
|
+
*
|
|
12
|
+
* const MySchema = z.object({
|
|
13
|
+
* name: z.string(),
|
|
14
|
+
* age: z.number().optional(),
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* const adapter = createZodAdapter(MySchema, 'myEntity')
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* The type parameter `T` is the inferred type of the schema.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createZodAdapter<T extends Record<string, ApplogValue> = Record<string, ApplogValue>>(zodSchema: ZodObject<Record<string, ZodTypeAny>>, entityPrefix: string, options?: {
|
|
23
|
+
/** Override at-paths for specific attributes */
|
|
24
|
+
atOverrides?: Record<string, string>;
|
|
25
|
+
/** Default values */
|
|
26
|
+
defaults?: Partial<T>;
|
|
27
|
+
/** Property name to at-path mapping function */
|
|
28
|
+
toAtPath?: (entityPrefix: string, attrName: string) => string;
|
|
29
|
+
}): ISchemaAdapter<T>;
|
|
30
|
+
//# sourceMappingURL=zod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.d.ts","sourceRoot":"","sources":["../../../src/viewmodel/adapters/zod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,aAAa,CAAA;AACjE,OAAO,KAAK,EAAE,SAAS,EAAW,UAAU,EAAE,MAAM,KAAK,CAAA;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnG,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAChD,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IACT,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACrB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAA;CAC7D,GACC,cAAc,CAAC,CAAC,CAAC,CAqBnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ApplogForInsertOptionalAgent, ApplogValue, EntityID } from '../applog/datom-types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Generic ObjectBuilder for type-safe entity creation and updates.
|
|
4
|
+
*
|
|
5
|
+
* Provides a fluent API to build a set of applogs for an entity.
|
|
6
|
+
* Modeled after the note3 builder pattern.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* ObjectBuilder.create({ name: 'foo' })
|
|
11
|
+
* .update({ type: 'bar' })
|
|
12
|
+
* .build(thread)
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class ObjectBuilder<TARGET extends Record<string, ApplogValue> = Record<string, ApplogValue>> {
|
|
16
|
+
private _data;
|
|
17
|
+
en: EntityID | null;
|
|
18
|
+
private _atPrefix;
|
|
19
|
+
private _atOverrides;
|
|
20
|
+
constructor(_data: Partial<TARGET>, en?: EntityID | null, _atPrefix?: string | null, _atOverrides?: Partial<Record<keyof TARGET, string>>);
|
|
21
|
+
/**
|
|
22
|
+
* Create a new builder with initial data.
|
|
23
|
+
*/
|
|
24
|
+
static create<TARGET extends Record<string, ApplogValue>>(init?: Partial<TARGET>, en?: EntityID, atPrefix?: string, atOverrides?: Partial<Record<keyof TARGET, string>>): ObjectBuilder<TARGET>;
|
|
25
|
+
/**
|
|
26
|
+
* Update the data being built.
|
|
27
|
+
*/
|
|
28
|
+
update(updateObj: Partial<TARGET>): this;
|
|
29
|
+
/**
|
|
30
|
+
* Build the applogs for this entity, optionally resolving against a thread.
|
|
31
|
+
*/
|
|
32
|
+
build(thread?: {
|
|
33
|
+
insert(applogs: ApplogForInsertOptionalAgent[]): ApplogForInsertOptionalAgent[];
|
|
34
|
+
}): ApplogForInsertOptionalAgent[];
|
|
35
|
+
/**
|
|
36
|
+
* Get the raw data being built.
|
|
37
|
+
*/
|
|
38
|
+
get data(): Partial<TARGET>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/viewmodel/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAEnG;;;;;;;;;;;;GAYG;AACH,qBAAa,aAAa,CACzB,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;IAGvE,OAAO,CAAC,KAAK;IACN,EAAE,EAAE,QAAQ,GAAG,IAAI;IAC1B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,YAAY;gBAHZ,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,EACvB,EAAE,GAAE,QAAQ,GAAG,IAAW,EACzB,SAAS,GAAE,MAAM,GAAG,IAAW,EAC/B,YAAY,GAAE,OAAO,CAAC,MAAM,CAAC,MAAM,MAAM,EAAE,MAAM,CAAC,CAAM;IAGjE;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACvD,IAAI,GAAE,OAAO,CAAC,MAAM,CAAM,EAC1B,EAAE,CAAC,EAAE,QAAQ,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,MAAM,EAAE,MAAM,CAAC,CAAC,GACjD,aAAa,CAAC,MAAM,CAAC;IAIxB;;OAEG;IACH,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI;IAKxC;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE;QACd,MAAM,CAAC,OAAO,EAAE,4BAA4B,EAAE,GAAG,4BAA4B,EAAE,CAAA;KAC/E,GAAG,4BAA4B,EAAE;IAclC;;OAEG;IACH,IAAI,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1B;CACD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
export declare function typeBoxExample(): void;
|
|
22
|
+
export declare function zodExample(): void;
|
|
23
|
+
export declare function arkTypePattern(): void;
|
|
24
|
+
export declare function typiaPattern(): void;
|
|
25
|
+
export declare function minimalNoSchemaExample(): void;
|
|
26
|
+
//# sourceMappingURL=all-adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"all-adapters.d.ts","sourceRoot":"","sources":["../../../src/viewmodel/examples/all-adapters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA6BH,wBAAgB,cAAc,SA2B7B;AASD,wBAAgB,UAAU,SA2BzB;AASD,wBAAgB,cAAc,SAyB7B;AASD,wBAAgB,YAAY,SA0B3B;AAMD,wBAAgB,sBAAsB,SAmBrC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ApplogValue, EntityID } from '../applog/datom-types.ts';
|
|
2
|
+
import type { Thread } from '../thread/basic.ts';
|
|
3
|
+
import { ObjectBuilder } from './builder.ts';
|
|
4
|
+
import { type ISignalAdapter, type IVMInstance, type ViewModelFactoryOptions } from './types.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Default signal adapter — reads Subscribable values directly (snapshot).
|
|
7
|
+
* Subscribe-once to keep .value current. No framework reactivity.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DefaultSignalAdapter: ISignalAdapter;
|
|
10
|
+
/**
|
|
11
|
+
* Create a ViewModel factory for a given schema.
|
|
12
|
+
*
|
|
13
|
+
* Returns a base class that can be extended or used directly.
|
|
14
|
+
* The class provides:
|
|
15
|
+
* - Static `get(en, thread)` for singleton access
|
|
16
|
+
* - Static `buildNew(init, en)` for creating entities
|
|
17
|
+
* - Instance `buildUpdate(init)` for updating entities
|
|
18
|
+
* - Lazy reactive property accessors per attribute
|
|
19
|
+
* - `setDeleted()` for soft deletion
|
|
20
|
+
*
|
|
21
|
+
* Framework-specific reactivity (Solid, Vue, etc.) can be added by
|
|
22
|
+
* providing a custom `ISignalAdapter` in the options.
|
|
23
|
+
*
|
|
24
|
+
* @param options - Factory configuration
|
|
25
|
+
* @returns A VM class constructor with static methods
|
|
26
|
+
*/
|
|
27
|
+
export declare function createViewModelFactory<T extends Record<string, ApplogValue>>(options: ViewModelFactoryOptions<T>): {
|
|
28
|
+
new (en: EntityID, thread: Thread, skipInit?: boolean): IVMInstance<T> & T;
|
|
29
|
+
/** Get or create a VM instance for the given entity ID */
|
|
30
|
+
get(en: EntityID, thread: Thread): IVMInstance<T> & T;
|
|
31
|
+
/** Create a builder for a new entity */
|
|
32
|
+
buildNew(init?: Partial<T>, en?: EntityID): ObjectBuilder<T>;
|
|
33
|
+
/** The VM name (for debugging) */
|
|
34
|
+
readonly vmName: string;
|
|
35
|
+
/** The entity prefix used for at-paths */
|
|
36
|
+
readonly entityPrefix: string;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/viewmodel/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,WAAW,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAMnG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,uBAAuB,EAG5B,MAAM,YAAY,CAAA;AAMnB;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAUlC,CAAA;AAoCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3E,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GA4NN;IAC5B,KACC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,OAAO,GAChB,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAErB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAErD,wCAAwC;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;IAE5D,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IAEvB,0CAA0C;IAC1C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC7B,CACD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { ObjectBuilder } from './builder.ts';
|
|
2
|
+
export { createViewModelFactory, DefaultSignalAdapter } from './factory.ts';
|
|
3
|
+
export { createAdapterFromAttributes, buildAtPath } from './schema-adapter.ts';
|
|
4
|
+
export type { ISchemaAdapter, ISignalAdapter, IVMInstance, IVMClass, VMAttributeDef, ViewModelFactoryOptions, VMInstanceMap, } from './types.ts';
|
|
5
|
+
export { GlobalVMInstances, getInstancesForThread } from './types.ts';
|
|
6
|
+
export { createTypeBoxAdapter } from './adapters/typebox.ts';
|
|
7
|
+
export { createZodAdapter } from './adapters/zod.ts';
|
|
8
|
+
export { createArkTypeAdapter } from './adapters/arktype.ts';
|
|
9
|
+
export { createTypiaAdapter } from './adapters/typia.ts';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/viewmodel/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAC3E,OAAO,EAAE,2BAA2B,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9E,YAAY,EACX,cAAc,EACd,cAAc,EACd,WAAW,EACX,QAAQ,EACR,cAAc,EACd,uBAAuB,EACvB,aAAa,GACb,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAGrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createArkTypeAdapter
|
|
3
|
+
} from "../chunk-64EJIJAJ.js";
|
|
4
|
+
import {
|
|
5
|
+
createTypeBoxAdapter
|
|
6
|
+
} from "../chunk-ICBK7NC4.js";
|
|
7
|
+
import {
|
|
8
|
+
createTypiaAdapter
|
|
9
|
+
} from "../chunk-7QEGHKR4.js";
|
|
10
|
+
import {
|
|
11
|
+
createZodAdapter
|
|
12
|
+
} from "../chunk-XF4DWOAE.js";
|
|
13
|
+
import {
|
|
14
|
+
lastWriteWins,
|
|
15
|
+
liveEntityAt
|
|
16
|
+
} from "../chunk-N7SEGHU4.js";
|
|
17
|
+
import {
|
|
18
|
+
EntityID_LENGTH,
|
|
19
|
+
SubscribableImpl,
|
|
20
|
+
dateNowIso,
|
|
21
|
+
ensureTsPvAndFinalizeApplog,
|
|
22
|
+
isInitEvent,
|
|
23
|
+
mintNewEntity,
|
|
24
|
+
rollingFilter
|
|
25
|
+
} from "../chunk-4MKPGQIM.js";
|
|
26
|
+
import "../chunk-ZAADLBSB.js";
|
|
27
|
+
|
|
28
|
+
// src/viewmodel/builder.ts
|
|
29
|
+
var ObjectBuilder = class _ObjectBuilder {
|
|
30
|
+
constructor(_data, en = null, _atPrefix = null, _atOverrides = {}) {
|
|
31
|
+
this._data = _data;
|
|
32
|
+
this.en = en;
|
|
33
|
+
this._atPrefix = _atPrefix;
|
|
34
|
+
this._atOverrides = _atOverrides;
|
|
35
|
+
}
|
|
36
|
+
_data;
|
|
37
|
+
en;
|
|
38
|
+
_atPrefix;
|
|
39
|
+
_atOverrides;
|
|
40
|
+
/**
|
|
41
|
+
* Create a new builder with initial data.
|
|
42
|
+
*/
|
|
43
|
+
static create(init = {}, en, atPrefix, atOverrides) {
|
|
44
|
+
return new _ObjectBuilder(init, en, atPrefix, atOverrides);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Update the data being built.
|
|
48
|
+
*/
|
|
49
|
+
update(updateObj) {
|
|
50
|
+
Object.assign(this._data, updateObj);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the applogs for this entity, optionally resolving against a thread.
|
|
55
|
+
*/
|
|
56
|
+
build(thread) {
|
|
57
|
+
const atPrefix = this._atPrefix;
|
|
58
|
+
const applogs = [];
|
|
59
|
+
for (const [key, value] of Object.entries(this._data)) {
|
|
60
|
+
if (value === void 0) continue;
|
|
61
|
+
const atOverride = this._atOverrides[key];
|
|
62
|
+
const at = atOverride ?? (atPrefix ? `${atPrefix}/${String(key)}` : String(key));
|
|
63
|
+
applogs.push({ en: this.en, at, vl: value });
|
|
64
|
+
}
|
|
65
|
+
return applogs;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get the raw data being built.
|
|
69
|
+
*/
|
|
70
|
+
get data() {
|
|
71
|
+
return { ...this._data };
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/viewmodel/types.ts
|
|
76
|
+
var GlobalVMInstances = /* @__PURE__ */ new WeakMap();
|
|
77
|
+
function getInstancesForThread(thread) {
|
|
78
|
+
let threadMap = GlobalVMInstances.get(thread);
|
|
79
|
+
if (!threadMap) {
|
|
80
|
+
threadMap = /* @__PURE__ */ new Map();
|
|
81
|
+
GlobalVMInstances.set(thread, threadMap);
|
|
82
|
+
}
|
|
83
|
+
return threadMap;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/viewmodel/factory.ts
|
|
87
|
+
var DefaultSignalAdapter = {
|
|
88
|
+
createGetter(subscribable) {
|
|
89
|
+
subscribable.subscribe(() => {
|
|
90
|
+
});
|
|
91
|
+
return () => subscribable.value;
|
|
92
|
+
},
|
|
93
|
+
createWritable(initial) {
|
|
94
|
+
let current = initial;
|
|
95
|
+
return [() => current, (v) => {
|
|
96
|
+
current = v;
|
|
97
|
+
}];
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
function makeCurrent(thread, fn) {
|
|
101
|
+
if (fn) return fn(thread);
|
|
102
|
+
return lastWriteWins(thread, { tolerateAlreadyFiltered: true });
|
|
103
|
+
}
|
|
104
|
+
function defaultPersistApplogs(thread, applogs) {
|
|
105
|
+
const finalized = applogs.map((log) => ensureTsPvAndFinalizeApplog(log, thread));
|
|
106
|
+
const writable = thread;
|
|
107
|
+
if (typeof writable.insertRaw === "function") {
|
|
108
|
+
writable.insertRaw(finalized);
|
|
109
|
+
} else if (typeof writable.insert === "function") {
|
|
110
|
+
writable.insert(applogs);
|
|
111
|
+
} else {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function createViewModelFactory(options) {
|
|
115
|
+
const {
|
|
116
|
+
adapter,
|
|
117
|
+
entityPrefix = adapter.getEntityPrefix(),
|
|
118
|
+
entityIdLength = EntityID_LENGTH,
|
|
119
|
+
generateEntityId,
|
|
120
|
+
vmName = entityPrefix,
|
|
121
|
+
signalAdapter = DefaultSignalAdapter
|
|
122
|
+
} = options;
|
|
123
|
+
const attrDefs = adapter.getAttributeDefs();
|
|
124
|
+
const defaults = adapter.getDefaults();
|
|
125
|
+
const genId = generateEntityId ?? ((data) => mintNewEntity({ ...data, ts: data.ts ?? dateNowIso() }, entityIdLength));
|
|
126
|
+
const persistFn = (thread, applogs) => {
|
|
127
|
+
defaultPersistApplogs(thread, applogs);
|
|
128
|
+
};
|
|
129
|
+
class ViewModel {
|
|
130
|
+
constructor(en, thread, skipInit) {
|
|
131
|
+
this.en = en;
|
|
132
|
+
this.thread = thread;
|
|
133
|
+
if (skipInit) return;
|
|
134
|
+
const currentThread = makeCurrent(thread, options.makeCurrentThread);
|
|
135
|
+
for (const attr of attrDefs) {
|
|
136
|
+
if (attr.name === "en") continue;
|
|
137
|
+
const attrName = attr.name;
|
|
138
|
+
const atPath = attr.atPath;
|
|
139
|
+
const defaultValue = attr.defaultValue ?? defaults?.[attrName];
|
|
140
|
+
Object.defineProperty(this, attrName, {
|
|
141
|
+
get() {
|
|
142
|
+
let signal = this._signals.get(attrName);
|
|
143
|
+
if (!signal) {
|
|
144
|
+
const subscribable = liveEntityAt(currentThread, this.en, atPath);
|
|
145
|
+
signal = this._signalAdapter.createGetter(subscribable);
|
|
146
|
+
this._signals.set(attrName, signal);
|
|
147
|
+
}
|
|
148
|
+
const value = signal();
|
|
149
|
+
return value ?? defaultValue ?? value;
|
|
150
|
+
},
|
|
151
|
+
set(v) {
|
|
152
|
+
const applog = { en: this.en, at: atPath, vl: v };
|
|
153
|
+
persistFn(this.thread, [applog]);
|
|
154
|
+
},
|
|
155
|
+
enumerable: true,
|
|
156
|
+
configurable: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const targets = /* @__PURE__ */ new Map();
|
|
160
|
+
this._targetApplogs = rollingFilter(currentThread, { vl: this.en });
|
|
161
|
+
this._targetMap = new SubscribableImpl(
|
|
162
|
+
targets,
|
|
163
|
+
() => this._targetApplogs.subscribe((event) => {
|
|
164
|
+
if (isInitEvent(event)) {
|
|
165
|
+
targets.clear();
|
|
166
|
+
for (const log of event.init) {
|
|
167
|
+
let ats = targets.get(log.en);
|
|
168
|
+
if (!ats) {
|
|
169
|
+
ats = /* @__PURE__ */ new Set();
|
|
170
|
+
targets.set(log.en, ats);
|
|
171
|
+
}
|
|
172
|
+
ats.add(log.at);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
for (const log of event.added) {
|
|
176
|
+
let ats = targets.get(log.en);
|
|
177
|
+
if (!ats) {
|
|
178
|
+
ats = /* @__PURE__ */ new Set();
|
|
179
|
+
targets.set(log.en, ats);
|
|
180
|
+
}
|
|
181
|
+
ats.add(log.at);
|
|
182
|
+
}
|
|
183
|
+
if (event.removed) {
|
|
184
|
+
for (const log of event.removed) {
|
|
185
|
+
const ats = targets.get(log.en);
|
|
186
|
+
if (ats) {
|
|
187
|
+
ats.delete(log.at);
|
|
188
|
+
if (ats.size === 0) targets.delete(log.en);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
this._targetMap._set(targets);
|
|
194
|
+
}, "derived")
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
en;
|
|
198
|
+
thread;
|
|
199
|
+
/** Per-instance signal storage */
|
|
200
|
+
_signals = /* @__PURE__ */ new Map();
|
|
201
|
+
_signalAdapter = signalAdapter;
|
|
202
|
+
/** Reactive map for applog tracking: vl === this.en */
|
|
203
|
+
_targetMap;
|
|
204
|
+
/** Applogs in the current thread where vl === this.en */
|
|
205
|
+
_targetApplogs;
|
|
206
|
+
/** Thread scoped to this entity */
|
|
207
|
+
get entityThread() {
|
|
208
|
+
return rollingFilter(this.thread, { en: this.en });
|
|
209
|
+
}
|
|
210
|
+
/** Applogs in the current thread where vl === this.en */
|
|
211
|
+
get targetApplogs() {
|
|
212
|
+
return this._targetApplogs;
|
|
213
|
+
}
|
|
214
|
+
/** Set of entities that have an applog with this.en as the vl */
|
|
215
|
+
get targettedBy() {
|
|
216
|
+
return new Set(this._targetMap.value.keys());
|
|
217
|
+
}
|
|
218
|
+
/** Set of at strings from applogs where vl === this.en */
|
|
219
|
+
get targettedVia() {
|
|
220
|
+
const via = /* @__PURE__ */ new Set();
|
|
221
|
+
for (const ats of this._targetMap.value.values()) {
|
|
222
|
+
for (const at of ats) via.add(at);
|
|
223
|
+
}
|
|
224
|
+
return via;
|
|
225
|
+
}
|
|
226
|
+
/** Whether this entity is soft-deleted */
|
|
227
|
+
get isDeleted() {
|
|
228
|
+
let signal = this._signals.get("__isDeleted");
|
|
229
|
+
if (!signal) {
|
|
230
|
+
const currentThread = makeCurrent(this.thread, options.makeCurrentThread);
|
|
231
|
+
const subscribable = liveEntityAt(currentThread, this.en, "isDeleted");
|
|
232
|
+
signal = this._signalAdapter.createGetter(subscribable);
|
|
233
|
+
this._signals.set("__isDeleted", signal);
|
|
234
|
+
}
|
|
235
|
+
return !!signal();
|
|
236
|
+
}
|
|
237
|
+
/** Soft-delete this entity */
|
|
238
|
+
setDeleted(thread = this.thread) {
|
|
239
|
+
const applog = { en: this.en, at: "isDeleted", vl: true };
|
|
240
|
+
persistFn(thread, [applog]);
|
|
241
|
+
}
|
|
242
|
+
/** Get a builder for updating this entity */
|
|
243
|
+
buildUpdate(init = {}) {
|
|
244
|
+
return new ObjectBuilder(init, this.en, entityPrefix);
|
|
245
|
+
}
|
|
246
|
+
/** Description for debugging */
|
|
247
|
+
get description() {
|
|
248
|
+
return `${vmName}VM(en=${this.en})`;
|
|
249
|
+
}
|
|
250
|
+
/** Get the full entity state as a plain object */
|
|
251
|
+
toJSON() {
|
|
252
|
+
const result = {};
|
|
253
|
+
for (const attr of attrDefs) {
|
|
254
|
+
const value = this[attr.name];
|
|
255
|
+
if (value !== void 0 && value !== null) {
|
|
256
|
+
result[attr.name] = value;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function getVMClass(en, thread) {
|
|
263
|
+
if (!en || typeof en !== "string") throw new Error(`[${vmName}VM.get] invalid en: ${en}`);
|
|
264
|
+
if (!thread) throw new Error(`[${vmName}VM.get] no thread provided`);
|
|
265
|
+
const threadMap = getInstancesForThread(thread);
|
|
266
|
+
let entityMap = threadMap.get(vmName);
|
|
267
|
+
if (!entityMap) {
|
|
268
|
+
entityMap = /* @__PURE__ */ new Map();
|
|
269
|
+
threadMap.set(vmName, entityMap);
|
|
270
|
+
}
|
|
271
|
+
const existing = entityMap.get(en);
|
|
272
|
+
if (existing) return existing;
|
|
273
|
+
const vm = new ViewModel(en, thread, false);
|
|
274
|
+
entityMap.set(en, vm);
|
|
275
|
+
return vm;
|
|
276
|
+
}
|
|
277
|
+
function buildNewEntity(init = {}, en) {
|
|
278
|
+
const entityId = en ?? genId(init);
|
|
279
|
+
return ObjectBuilder.create(init, entityId, entityPrefix);
|
|
280
|
+
}
|
|
281
|
+
const VMClass = ViewModel;
|
|
282
|
+
VMClass.get = getVMClass;
|
|
283
|
+
VMClass.buildNew = buildNewEntity;
|
|
284
|
+
VMClass.vmName = vmName;
|
|
285
|
+
VMClass.entityPrefix = entityPrefix;
|
|
286
|
+
return VMClass;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// src/viewmodel/schema-adapter.ts
|
|
290
|
+
function createAdapterFromAttributes(config) {
|
|
291
|
+
return {
|
|
292
|
+
getAttributeDefs: () => config.attributes,
|
|
293
|
+
getDefaults: () => config.defaults ?? {},
|
|
294
|
+
getEntityPrefix: () => config.entityPrefix
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function buildAtPath(entityPrefix, attrName) {
|
|
298
|
+
return `${entityPrefix}/${attrName}`;
|
|
299
|
+
}
|
|
300
|
+
export {
|
|
301
|
+
DefaultSignalAdapter,
|
|
302
|
+
GlobalVMInstances,
|
|
303
|
+
ObjectBuilder,
|
|
304
|
+
buildAtPath,
|
|
305
|
+
createAdapterFromAttributes,
|
|
306
|
+
createArkTypeAdapter,
|
|
307
|
+
createTypeBoxAdapter,
|
|
308
|
+
createTypiaAdapter,
|
|
309
|
+
createViewModelFactory,
|
|
310
|
+
createZodAdapter,
|
|
311
|
+
getInstancesForThread
|
|
312
|
+
};
|
|
313
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/viewmodel/builder.ts","../../src/viewmodel/types.ts","../../src/viewmodel/factory.ts","../../src/viewmodel/schema-adapter.ts"],"sourcesContent":["import type { ApplogForInsertOptionalAgent, ApplogValue, EntityID } from '../applog/datom-types.ts'\n\n/**\n * Generic ObjectBuilder for type-safe entity creation and updates.\n *\n * Provides a fluent API to build a set of applogs for an entity.\n * Modeled after the note3 builder pattern.\n *\n * Usage:\n * ```ts\n * ObjectBuilder.create({ name: 'foo' })\n * .update({ type: 'bar' })\n * .build(thread)\n * ```\n */\nexport class ObjectBuilder<\n\tTARGET extends Record<string, ApplogValue> = Record<string, ApplogValue>,\n> {\n\tconstructor(\n\t\tprivate _data: Partial<TARGET>,\n\t\tpublic en: EntityID | null = null,\n\t\tprivate _atPrefix: string | null = null,\n\t\tprivate _atOverrides: Partial<Record<keyof TARGET, string>> = {},\n\t) {}\n\n\t/**\n\t * Create a new builder with initial data.\n\t */\n\tstatic create<TARGET extends Record<string, ApplogValue>>(\n\t\tinit: Partial<TARGET> = {},\n\t\ten?: EntityID,\n\t\tatPrefix?: string,\n\t\tatOverrides?: Partial<Record<keyof TARGET, string>>,\n\t): ObjectBuilder<TARGET> {\n\t\treturn new ObjectBuilder<TARGET>(init, en, atPrefix, atOverrides)\n\t}\n\n\t/**\n\t * Update the data being built.\n\t */\n\tupdate(updateObj: Partial<TARGET>): this {\n\t\tObject.assign(this._data, updateObj)\n\t\treturn this\n\t}\n\n\t/**\n\t * Build the applogs for this entity, optionally resolving against a thread.\n\t */\n\tbuild(thread?: {\n\t\tinsert(applogs: ApplogForInsertOptionalAgent[]): ApplogForInsertOptionalAgent[]\n\t}): ApplogForInsertOptionalAgent[] {\n\t\tconst atPrefix = this._atPrefix\n\t\tconst applogs: ApplogForInsertOptionalAgent[] = []\n\n\t\tfor (const [key, value] of Object.entries(this._data) as [keyof TARGET, ApplogValue][]) {\n\t\t\tif (value === undefined) continue\n\t\t\tconst atOverride = this._atOverrides[key]\n\t\t\tconst at = atOverride ?? (atPrefix ? `${atPrefix}/${String(key)}` : String(key))\n\t\t\tapplogs.push({ en: this.en!, at, vl: value })\n\t\t}\n\n\t\treturn applogs\n\t}\n\n\t/**\n\t * Get the raw data being built.\n\t */\n\tget data(): Partial<TARGET> {\n\t\treturn { ...this._data }\n\t}\n}\n","import type { ApplogValue, EntityID } from '../applog/datom-types.ts'\nimport type { Thread } from '../thread/basic.ts'\nimport type { ObjectBuilder } from './builder.ts'\n\n// ═══════════════════════════════════════════════════════════════\n// Attribute Definition\n// ═══════════════════════════════════════════════════════════════\n\nexport interface VMAttributeDef {\n\t/** Attribute name (short: e.g. 'name', 'content') */\n\tname: string\n\t/** The wovin at-path used in applogs (e.g. 'block/content', 'speaker/name') */\n\tatPath: string\n\t/** Whether the attribute is optional */\n\toptional: boolean\n\t/** Default value if not present in applogs */\n\tdefaultValue?: ApplogValue\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Schema Adapter Interface\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * A schema adapter converts a type-system schema (TypeBox, Zod, ArkType, Typia)\n * into a uniform representation that the VM factory can consume.\n */\nexport interface ISchemaAdapter<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {\n\t/** Get the attribute definitions for this schema */\n\tgetAttributeDefs(): VMAttributeDef[]\n\n\t/** Get default values for all attributes */\n\tgetDefaults(): Partial<T>\n\n\t/** Optional: runtime validator */\n\tcreateValidator?(): (value: unknown) => value is T\n\n\t/** The entity prefix used for wovin at-paths (e.g. 'block', 'speaker') */\n\tgetEntityPrefix(): string\n}\n\n// ═══════════════════════════════════════════════════════════════\n// ViewModel Factory Options\n// ═══════════════════════════════════════════════════════════════\n\nexport interface ViewModelFactoryOptions<T extends Record<string, ApplogValue>> {\n\t/** The schema adapter for this entity type */\n\tadapter: ISchemaAdapter<T>\n\n\t/** How to get the default thread context */\n\tgetDefaultThread?: () => Thread\n\n\t/** EntityID generation length (default: 7) */\n\tentityIdLength?: number\n\n\t/** Function to generate entity IDs */\n\tgenerateEntityId?: (data: Partial<T> & { ts?: string }) => EntityID\n\n\t/** Override the entity prefix for at-paths */\n\tentityPrefix?: string\n\n\t/** Optional function to make thread current-state (lastWriteWins) */\n\tmakeCurrentThread?: (thread: Thread) => Thread\n\n\t/** Name for the VM type (used in logging and debugging) */\n\tvmName?: string\n\n\t/**\n\t * Signal adapter for framework-specific reactivity.\n\t * Default: non-reactive (direct Subscribable reads).\n\t * For SolidJS, pass createSolidSignalAdapter() from @wovin/ui-solid/viewmodel.\n\t */\n\tsignalAdapter?: ISignalAdapter\n}\n\n// ═══════════════════════════════════════════════════════════════\n// ViewModel Instance Interface\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IVMInstance<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {\n\treadonly en: EntityID\n\treadonly thread: Thread\n\n\t/** Get a builder for updating this entity */\n\tbuildUpdate(init?: Partial<T>): ObjectBuilder<T>\n\n\t/** Soft-delete this entity */\n\tsetDeleted(thread?: Thread): void\n\n\t/** Whether this entity is deleted */\n\treadonly isDeleted: boolean\n\n\t/** The entity thread filtered to this entity */\n\treadonly entityThread: Thread\n}\n\n// ═══════════════════════════════════════════════════════════════\n// ViewModel Class Interface (what the factory returns)\n// ═══════════════════════════════════════════════════════════════\n\nexport interface IVMClass<T extends Record<string, ApplogValue> = Record<string, ApplogValue>> {\n\tnew(en: EntityID, thread: Thread, ...args: any[]): IVMInstance<T>\n\n\t/** Get or create a VM instance for the given entity ID and thread */\n\tget(en: EntityID, thread: Thread): IVMInstance<T>\n\n\t/** Create a new entity builder */\n\tbuildNew(init?: Partial<T>, en?: EntityID): ObjectBuilder<T>\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Signal Adapter Interface (framework-specific reactivity)\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * A signal adapter abstracts how the VM creates reactive signals for each attribute.\n * The core factory uses a default (non-reactive) implementation.\n * Framework-specific extensions (Solid, Vue, etc.) override this.\n */\nexport interface ISignalAdapter {\n\t/**\n\t * Create a reactive getter for a subscribable value.\n\t * Returns a function that returns the current value.\n\t * In the default implementation, this is just () => subscribable.value.\n\t */\n\tcreateGetter<T>(subscribable: { value: T; subscribe(cb: () => void): () => void }): () => T\n\n\t/**\n\t * Create a writable signal for an attribute.\n\t * Returns [get, set] pair.\n\t * Default implementation stores and returns value directly.\n\t */\n\tcreateWritable<T>(initial: T): [() => T, (v: T) => void]\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Shared state maps\n// ═══════════════════════════════════════════════════════════════\n\nexport type VMInstanceMap<T> = Map<EntityID, T>\n\n/** WeakMap from Thread → Map<VMName, Map<EntityID, VMInstance>> */\nexport const GlobalVMInstances = new WeakMap<Thread, Map<string, Map<EntityID, unknown>>>()\n\nexport function getInstancesForThread(thread: Thread): Map<string, Map<EntityID, unknown>> {\n\tlet threadMap = GlobalVMInstances.get(thread)\n\tif (!threadMap) {\n\t\tthreadMap = new Map()\n\t\tGlobalVMInstances.set(thread, threadMap)\n\t}\n\treturn threadMap\n}\n","import type { ApplogForInsertOptionalAgent, ApplogValue, EntityID } from '../applog/datom-types.ts'\nimport { EntityID_LENGTH } from '../applog/datom-types.ts'\nimport { dateNowIso, mintNewEntity } from '../applog/applog-utils.ts'\nimport { ensureTsPvAndFinalizeApplog } from '../applog/applog-helpers.ts'\nimport { lastWriteWins, liveEntityAt } from '../query/basic.ts'\nimport { SubscribableImpl } from '../query/subscribable.ts'\nimport type { Thread } from '../thread/basic.ts'\nimport { isInitEvent } from '../thread/basic.ts'\nimport { rollingFilter } from '../thread/filters.ts'\nimport { ObjectBuilder } from './builder.ts'\nimport {\n\ttype ISignalAdapter,\n\ttype IVMInstance,\n\ttype ViewModelFactoryOptions,\n\ttype VMInstanceMap,\n\tgetInstancesForThread,\n} from './types.ts'\n\n// ═══════════════════════════════════════════════════════════════\n// Default (non-reactive) Signal Adapter\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Default signal adapter — reads Subscribable values directly (snapshot).\n * Subscribe-once to keep .value current. No framework reactivity.\n */\nexport const DefaultSignalAdapter: ISignalAdapter = {\n\tcreateGetter<T>(subscribable: { value: T; subscribe(cb: () => void): () => void }): () => T {\n\t\t// Subscribe once to activate upstream (lazy activation)\n\t\tsubscribable.subscribe(() => {})\n\t\treturn () => subscribable.value\n\t},\n\tcreateWritable<T>(initial: T): [() => T, (v: T) => void] {\n\t\tlet current = initial\n\t\treturn [() => current, (v: T) => { current = v }]\n\t},\n}\n\n// ═══════════════════════════════════════════════════════════════\n// makeCurrentThread - convenience wrapper\n// ═══════════════════════════════════════════════════════════════\n\nfunction makeCurrent(thread: Thread, fn?: ViewModelFactoryOptions<any>['makeCurrentThread']): Thread {\n\tif (fn) return fn(thread)\n\treturn lastWriteWins(thread, { tolerateAlreadyFiltered: true })\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Default persist function\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Default applog persistence: finalize applogs and push into thread.\n * Works with WriteableThread (which has insertRaw).\n */\nfunction defaultPersistApplogs(thread: Thread, applogs: ApplogForInsertOptionalAgent[]): void {\n\tconst finalized = applogs.map(log => ensureTsPvAndFinalizeApplog(log as any, thread))\n\tconst writable = thread as any\n\tif (typeof writable.insertRaw === 'function') {\n\t\twritable.insertRaw(finalized)\n\t} else if (typeof writable.insert === 'function') {\n\t\twritable.insert(applogs)\n\t} else {\n\t\t// Read-only thread — just finalize but don't persist\n\t\t// This is fine for optimistic UI or read-only scenarios\n\t}\n}\n\n// ═══════════════════════════════════════════════════════════════\n// createViewModelFactory - THE MAIN FACTORY\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Create a ViewModel factory for a given schema.\n *\n * Returns a base class that can be extended or used directly.\n * The class provides:\n * - Static `get(en, thread)` for singleton access\n * - Static `buildNew(init, en)` for creating entities\n * - Instance `buildUpdate(init)` for updating entities\n * - Lazy reactive property accessors per attribute\n * - `setDeleted()` for soft deletion\n *\n * Framework-specific reactivity (Solid, Vue, etc.) can be added by\n * providing a custom `ISignalAdapter` in the options.\n *\n * @param options - Factory configuration\n * @returns A VM class constructor with static methods\n */\nexport function createViewModelFactory<T extends Record<string, ApplogValue>>(\n\toptions: ViewModelFactoryOptions<T>,\n) {\n\tconst {\n\t\tadapter,\n\t\tentityPrefix = adapter.getEntityPrefix(),\n\t\tentityIdLength = EntityID_LENGTH,\n\t\tgenerateEntityId,\n\t\tvmName = entityPrefix,\n\t\tsignalAdapter = DefaultSignalAdapter,\n\t} = options\n\n\tconst attrDefs = adapter.getAttributeDefs()\n\tconst defaults = adapter.getDefaults()\n\n\t// Entity ID generation\n\tconst genId = generateEntityId ?? ((data: Partial<T> & { ts?: string }) =>\n\t\tmintNewEntity({ ...data, ts: data.ts ?? dateNowIso() }, entityIdLength) as EntityID)\n\n\t// Persist function (can be overridden by extending class)\n\tconst persistFn = (thread: Thread, applogs: ApplogForInsertOptionalAgent[]) => {\n\t\tdefaultPersistApplogs(thread, applogs)\n\t}\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// The ViewModel Class\n\t// ═══════════════════════════════════════════════════════════════\n\tclass ViewModel {\n\t\t/** Per-instance signal storage */\n\t\t_signals = new Map<string, () => ApplogValue>()\n\t\t_signalAdapter: ISignalAdapter = signalAdapter\n\n\t\t/** Reactive map for applog tracking: vl === this.en */\n\t\t_targetMap: SubscribableImpl<Map<EntityID, Set<string>>>\n\n\t\t/** Applogs in the current thread where vl === this.en */\n\t\t_targetApplogs: Thread\n\n\t\tconstructor(\n\t\t\tpublic en: EntityID,\n\t\t\tpublic thread: Thread,\n\t\t\tskipInit?: boolean,\n\t\t) {\n\t\t\tif (skipInit) return\n\n\t\t\tconst currentThread = makeCurrent(thread, options.makeCurrentThread)\n\n\t\t\t// Define lazy getters/setters for each attribute\n\t\t\tfor (const attr of attrDefs) {\n\t\t\t\tif (attr.name === 'en') continue\n\n\t\t\t\tconst attrName = attr.name\n\t\t\t\tconst atPath = attr.atPath\n\t\t\t\tconst defaultValue = attr.defaultValue ?? defaults?.[attrName as keyof T]\n\n\t\t\t\tObject.defineProperty(this, attrName, {\n\t\t\t\t\tget(this: ViewModel) {\n\t\t\t\t\t\tlet signal = this._signals.get(attrName)\n\t\t\t\t\t\tif (!signal) {\n\t\t\t\t\t\t\tconst subscribable = liveEntityAt(currentThread, this.en, atPath)\n\t\t\t\t\t\t\tsignal = this._signalAdapter.createGetter(subscribable)\n\t\t\t\t\t\t\tthis._signals.set(attrName, signal)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst value = signal()\n\t\t\t\t\t\treturn value ?? (defaultValue as ApplogValue | undefined) ?? value\n\t\t\t\t\t},\n\t\t\t\t\tset(this: ViewModel, v: ApplogValue) {\n\t\t\t\t\t\tconst applog: ApplogForInsertOptionalAgent = { en: this.en, at: atPath, vl: v }\n\t\t\t\t\t\tpersistFn(this.thread, [applog])\n\t\t\t\t\t},\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// ── Applog tracking: applogs where vl === this.en ────────────\n\t\t\tconst targets = new Map<EntityID, Set<string>>()\n\n\t\t\tthis._targetApplogs = rollingFilter(currentThread, { vl: this.en })\n\t\t\tthis._targetMap = new SubscribableImpl(\n\t\t\t\ttargets,\n\t\t\t\t() => this._targetApplogs.subscribe((event) => {\n\t\t\t\t\tif (isInitEvent(event)) {\n\t\t\t\t\t\ttargets.clear()\n\t\t\t\t\t\tfor (const log of event.init) {\n\t\t\t\t\t\t\tlet ats = targets.get(log.en)\n\t\t\t\t\t\t\tif (!ats) {\n\t\t\t\t\t\t\t\tats = new Set()\n\t\t\t\t\t\t\t\ttargets.set(log.en, ats)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tats.add(log.at)\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor (const log of event.added) {\n\t\t\t\t\t\t\tlet ats = targets.get(log.en)\n\t\t\t\t\t\t\tif (!ats) {\n\t\t\t\t\t\t\t\tats = new Set()\n\t\t\t\t\t\t\t\ttargets.set(log.en, ats)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tats.add(log.at)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (event.removed) {\n\t\t\t\t\t\t\tfor (const log of event.removed) {\n\t\t\t\t\t\t\t\tconst ats = targets.get(log.en)\n\t\t\t\t\t\t\t\tif (ats) {\n\t\t\t\t\t\t\t\t\tats.delete(log.at)\n\t\t\t\t\t\t\t\t\tif (ats.size === 0) targets.delete(log.en)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._targetMap._set(targets)\n\t\t\t\t}, 'derived'),\n\t\t\t)\n\t\t}\n\n\t\t/** Thread scoped to this entity */\n\t\tget entityThread(): Thread {\n\t\t\treturn rollingFilter(this.thread, { en: this.en })\n\t\t}\n\n\t\t/** Applogs in the current thread where vl === this.en */\n\t\tget targetApplogs(): Thread {\n\t\t\treturn this._targetApplogs\n\t\t}\n\n\t\t/** Set of entities that have an applog with this.en as the vl */\n\t\tget targettedBy(): Set<EntityID> {\n\t\t\treturn new Set(this._targetMap.value.keys())\n\t\t}\n\n\t\t/** Set of at strings from applogs where vl === this.en */\n\t\tget targettedVia(): Set<string> {\n\t\t\tconst via = new Set<string>()\n\t\t\tfor (const ats of this._targetMap.value.values()) {\n\t\t\t\tfor (const at of ats) via.add(at)\n\t\t\t}\n\t\t\treturn via\n\t\t}\n\n\t\t/** Whether this entity is soft-deleted */\n\t\tget isDeleted(): boolean {\n\t\t\tlet signal = this._signals.get('__isDeleted')\n\t\t\tif (!signal) {\n\t\t\t\tconst currentThread = makeCurrent(this.thread, options.makeCurrentThread)\n\t\t\t\tconst subscribable = liveEntityAt(currentThread, this.en, 'isDeleted')\n\t\t\t\tsignal = this._signalAdapter.createGetter(subscribable)\n\t\t\t\tthis._signals.set('__isDeleted', signal)\n\t\t\t}\n\t\t\treturn !!signal()\n\t\t}\n\n\t\t/** Soft-delete this entity */\n\t\tsetDeleted(thread = this.thread): void {\n\t\t\tconst applog: ApplogForInsertOptionalAgent = { en: this.en, at: 'isDeleted', vl: true }\n\t\t\tpersistFn(thread, [applog])\n\t\t}\n\n\t\t/** Get a builder for updating this entity */\n\t\tbuildUpdate(init: Partial<T> = {}): ObjectBuilder<T> {\n\t\t\treturn new ObjectBuilder<T>(init, this.en, entityPrefix)\n\t\t}\n\n\t\t/** Description for debugging */\n\t\tget description(): string {\n\t\t\treturn `${vmName}VM(en=${this.en})`\n\t\t}\n\n\t\t/** Get the full entity state as a plain object */\n\t\ttoJSON(): Partial<T> {\n\t\t\tconst result: Record<string, ApplogValue> = {}\n\t\t\tfor (const attr of attrDefs) {\n\t\t\t\tconst value = (this as any)[attr.name]\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\tresult[attr.name] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result as Partial<T>\n\t\t}\n\t}\n\n\t// ── Static Methods ────────────────────────────────────────────\n\n\t/**\n\t * Get or create a VM instance for the given entity and thread.\n\t * Implements the singleton pattern — returns cached instance if one exists.\n\t */\n\tfunction getVMClass(en: EntityID, thread: Thread): InstanceType<typeof ViewModel> {\n\t\tif (!en || typeof en !== 'string') throw new Error(`[${vmName}VM.get] invalid en: ${en}`)\n\t\tif (!thread) throw new Error(`[${vmName}VM.get] no thread provided`)\n\n\t\tconst threadMap = getInstancesForThread(thread)\n\t\tlet entityMap = threadMap.get(vmName) as VMInstanceMap<InstanceType<typeof ViewModel>> | undefined\n\t\tif (!entityMap) {\n\t\t\tentityMap = new Map()\n\t\t\tthreadMap.set(vmName, entityMap)\n\t\t}\n\n\t\tconst existing = entityMap.get(en)\n\t\tif (existing) return existing\n\n\t\tconst vm = new ViewModel(en, thread, false) as InstanceType<typeof ViewModel>\n\t\tentityMap.set(en, vm)\n\t\treturn vm\n\t}\n\n\t/**\n\t * Create a builder for constructing a new entity.\n\t */\n\tfunction buildNewEntity(init: Partial<T> = {}, en?: EntityID): ObjectBuilder<T> {\n\t\tconst entityId = en ?? genId(init as any)\n\t\treturn ObjectBuilder.create<T>(init, entityId, entityPrefix)\n\t}\n\n\t// Attach static methods to the class\n\tconst VMClass: any = ViewModel\n\tVMClass.get = getVMClass\n\tVMClass.buildNew = buildNewEntity\n\tVMClass.vmName = vmName\n\tVMClass.entityPrefix = entityPrefix\n\n\treturn VMClass as unknown as {\n\t\tnew(\n\t\t\ten: EntityID,\n\t\t\tthread: Thread,\n\t\t\tskipInit?: boolean,\n\t\t): IVMInstance<T> & T\n\n\t\t/** Get or create a VM instance for the given entity ID */\n\t\tget(en: EntityID, thread: Thread): IVMInstance<T> & T\n\n\t\t/** Create a builder for a new entity */\n\t\tbuildNew(init?: Partial<T>, en?: EntityID): ObjectBuilder<T>\n\n\t\t/** The VM name (for debugging) */\n\t\treadonly vmName: string\n\n\t\t/** The entity prefix used for at-paths */\n\t\treadonly entityPrefix: string\n\t}\n}\n","import type { ApplogValue } from '../applog/datom-types.ts'\nimport type { ISchemaAdapter, VMAttributeDef } from './types.ts'\n\n/**\n * Helper to create a simple schema adapter from a plain attribute list.\n * Useful for quick VM definitions or when you don't have a formal schema library.\n */\nexport function createAdapterFromAttributes<T extends Record<string, ApplogValue>>(\n\tconfig: {\n\t\tattributes: VMAttributeDef[]\n\t\tentityPrefix: string\n\t\tdefaults?: Partial<T>\n\t},\n): ISchemaAdapter<T> {\n\treturn {\n\t\tgetAttributeDefs: () => config.attributes,\n\t\tgetDefaults: () => (config.defaults ?? {}) as Partial<T>,\n\t\tgetEntityPrefix: () => config.entityPrefix,\n\t}\n}\n\n/**\n * Helper to build at-paths from attribute names and an entity prefix.\n */\nexport function buildAtPath(entityPrefix: string, attrName: string): string {\n\treturn `${entityPrefix}/${attrName}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeO,IAAM,gBAAN,MAAM,eAEX;AAAA,EACD,YACS,OACD,KAAsB,MACrB,YAA2B,MAC3B,eAAsD,CAAC,GAC9D;AAJO;AACD;AACC;AACA;AAAA,EACN;AAAA,EAJM;AAAA,EACD;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAMT,OAAO,OACN,OAAwB,CAAC,GACzB,IACA,UACA,aACwB;AACxB,WAAO,IAAI,eAAsB,MAAM,IAAI,UAAU,WAAW;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAkC;AACxC,WAAO,OAAO,KAAK,OAAO,SAAS;AACnC,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAE6B;AAClC,UAAM,WAAW,KAAK;AACtB,UAAM,UAA0C,CAAC;AAEjD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAoC;AACvF,UAAI,UAAU,OAAW;AACzB,YAAM,aAAa,KAAK,aAAa,GAAG;AACxC,YAAM,KAAK,eAAe,WAAW,GAAG,QAAQ,IAAI,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG;AAC9E,cAAQ,KAAK,EAAE,IAAI,KAAK,IAAK,IAAI,IAAI,MAAM,CAAC;AAAA,IAC7C;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAwB;AAC3B,WAAO,EAAE,GAAG,KAAK,MAAM;AAAA,EACxB;AACD;;;ACwEO,IAAM,oBAAoB,oBAAI,QAAqD;AAEnF,SAAS,sBAAsB,QAAqD;AAC1F,MAAI,YAAY,kBAAkB,IAAI,MAAM;AAC5C,MAAI,CAAC,WAAW;AACf,gBAAY,oBAAI,IAAI;AACpB,sBAAkB,IAAI,QAAQ,SAAS;AAAA,EACxC;AACA,SAAO;AACR;;;AC7HO,IAAM,uBAAuC;AAAA,EACnD,aAAgB,cAA4E;AAE3F,iBAAa,UAAU,MAAM;AAAA,IAAC,CAAC;AAC/B,WAAO,MAAM,aAAa;AAAA,EAC3B;AAAA,EACA,eAAkB,SAAuC;AACxD,QAAI,UAAU;AACd,WAAO,CAAC,MAAM,SAAS,CAAC,MAAS;AAAE,gBAAU;AAAA,IAAE,CAAC;AAAA,EACjD;AACD;AAMA,SAAS,YAAY,QAAgB,IAAgE;AACpG,MAAI,GAAI,QAAO,GAAG,MAAM;AACxB,SAAO,cAAc,QAAQ,EAAE,yBAAyB,KAAK,CAAC;AAC/D;AAUA,SAAS,sBAAsB,QAAgB,SAA+C;AAC7F,QAAM,YAAY,QAAQ,IAAI,SAAO,4BAA4B,KAAY,MAAM,CAAC;AACpF,QAAM,WAAW;AACjB,MAAI,OAAO,SAAS,cAAc,YAAY;AAC7C,aAAS,UAAU,SAAS;AAAA,EAC7B,WAAW,OAAO,SAAS,WAAW,YAAY;AACjD,aAAS,OAAO,OAAO;AAAA,EACxB,OAAO;AAAA,EAGP;AACD;AAuBO,SAAS,uBACf,SACC;AACD,QAAM;AAAA,IACL;AAAA,IACA,eAAe,QAAQ,gBAAgB;AAAA,IACvC,iBAAiB;AAAA,IACjB;AAAA,IACA,SAAS;AAAA,IACT,gBAAgB;AAAA,EACjB,IAAI;AAEJ,QAAM,WAAW,QAAQ,iBAAiB;AAC1C,QAAM,WAAW,QAAQ,YAAY;AAGrC,QAAM,QAAQ,qBAAqB,CAAC,SACnC,cAAc,EAAE,GAAG,MAAM,IAAI,KAAK,MAAM,WAAW,EAAE,GAAG,cAAc;AAGvE,QAAM,YAAY,CAAC,QAAgB,YAA4C;AAC9E,0BAAsB,QAAQ,OAAO;AAAA,EACtC;AAAA,EAKA,MAAM,UAAU;AAAA,IAWf,YACQ,IACA,QACP,UACC;AAHM;AACA;AAGP,UAAI,SAAU;AAEd,YAAM,gBAAgB,YAAY,QAAQ,QAAQ,iBAAiB;AAGnE,iBAAW,QAAQ,UAAU;AAC5B,YAAI,KAAK,SAAS,KAAM;AAExB,cAAM,WAAW,KAAK;AACtB,cAAM,SAAS,KAAK;AACpB,cAAM,eAAe,KAAK,gBAAgB,WAAW,QAAmB;AAExE,eAAO,eAAe,MAAM,UAAU;AAAA,UACrC,MAAqB;AACpB,gBAAI,SAAS,KAAK,SAAS,IAAI,QAAQ;AACvC,gBAAI,CAAC,QAAQ;AACZ,oBAAM,eAAe,aAAa,eAAe,KAAK,IAAI,MAAM;AAChE,uBAAS,KAAK,eAAe,aAAa,YAAY;AACtD,mBAAK,SAAS,IAAI,UAAU,MAAM;AAAA,YACnC;AACA,kBAAM,QAAQ,OAAO;AACrB,mBAAO,SAAU,gBAA4C;AAAA,UAC9D;AAAA,UACA,IAAqB,GAAgB;AACpC,kBAAM,SAAuC,EAAE,IAAI,KAAK,IAAI,IAAI,QAAQ,IAAI,EAAE;AAC9E,sBAAU,KAAK,QAAQ,CAAC,MAAM,CAAC;AAAA,UAChC;AAAA,UACA,YAAY;AAAA,UACZ,cAAc;AAAA,QACf,CAAC;AAAA,MACF;AAGA,YAAM,UAAU,oBAAI,IAA2B;AAE/C,WAAK,iBAAiB,cAAc,eAAe,EAAE,IAAI,KAAK,GAAG,CAAC;AAClE,WAAK,aAAa,IAAI;AAAA,QACrB;AAAA,QACA,MAAM,KAAK,eAAe,UAAU,CAAC,UAAU;AAC9C,cAAI,YAAY,KAAK,GAAG;AACvB,oBAAQ,MAAM;AACd,uBAAW,OAAO,MAAM,MAAM;AAC7B,kBAAI,MAAM,QAAQ,IAAI,IAAI,EAAE;AAC5B,kBAAI,CAAC,KAAK;AACT,sBAAM,oBAAI,IAAI;AACd,wBAAQ,IAAI,IAAI,IAAI,GAAG;AAAA,cACxB;AACA,kBAAI,IAAI,IAAI,EAAE;AAAA,YACf;AAAA,UACD,OAAO;AACN,uBAAW,OAAO,MAAM,OAAO;AAC9B,kBAAI,MAAM,QAAQ,IAAI,IAAI,EAAE;AAC5B,kBAAI,CAAC,KAAK;AACT,sBAAM,oBAAI,IAAI;AACd,wBAAQ,IAAI,IAAI,IAAI,GAAG;AAAA,cACxB;AACA,kBAAI,IAAI,IAAI,EAAE;AAAA,YACf;AACA,gBAAI,MAAM,SAAS;AAClB,yBAAW,OAAO,MAAM,SAAS;AAChC,sBAAM,MAAM,QAAQ,IAAI,IAAI,EAAE;AAC9B,oBAAI,KAAK;AACR,sBAAI,OAAO,IAAI,EAAE;AACjB,sBAAI,IAAI,SAAS,EAAG,SAAQ,OAAO,IAAI,EAAE;AAAA,gBAC1C;AAAA,cACD;AAAA,YACD;AAAA,UACD;AACA,eAAK,WAAW,KAAK,OAAO;AAAA,QAC7B,GAAG,SAAS;AAAA,MACb;AAAA,IACD;AAAA,IA3EQ;AAAA,IACA;AAAA;AAAA,IAXR,WAAW,oBAAI,IAA+B;AAAA,IAC9C,iBAAiC;AAAA;AAAA,IAGjC;AAAA;AAAA,IAGA;AAAA;AAAA,IAiFA,IAAI,eAAuB;AAC1B,aAAO,cAAc,KAAK,QAAQ,EAAE,IAAI,KAAK,GAAG,CAAC;AAAA,IAClD;AAAA;AAAA,IAGA,IAAI,gBAAwB;AAC3B,aAAO,KAAK;AAAA,IACb;AAAA;AAAA,IAGA,IAAI,cAA6B;AAChC,aAAO,IAAI,IAAI,KAAK,WAAW,MAAM,KAAK,CAAC;AAAA,IAC5C;AAAA;AAAA,IAGA,IAAI,eAA4B;AAC/B,YAAM,MAAM,oBAAI,IAAY;AAC5B,iBAAW,OAAO,KAAK,WAAW,MAAM,OAAO,GAAG;AACjD,mBAAW,MAAM,IAAK,KAAI,IAAI,EAAE;AAAA,MACjC;AACA,aAAO;AAAA,IACR;AAAA;AAAA,IAGA,IAAI,YAAqB;AACxB,UAAI,SAAS,KAAK,SAAS,IAAI,aAAa;AAC5C,UAAI,CAAC,QAAQ;AACZ,cAAM,gBAAgB,YAAY,KAAK,QAAQ,QAAQ,iBAAiB;AACxE,cAAM,eAAe,aAAa,eAAe,KAAK,IAAI,WAAW;AACrE,iBAAS,KAAK,eAAe,aAAa,YAAY;AACtD,aAAK,SAAS,IAAI,eAAe,MAAM;AAAA,MACxC;AACA,aAAO,CAAC,CAAC,OAAO;AAAA,IACjB;AAAA;AAAA,IAGA,WAAW,SAAS,KAAK,QAAc;AACtC,YAAM,SAAuC,EAAE,IAAI,KAAK,IAAI,IAAI,aAAa,IAAI,KAAK;AACtF,gBAAU,QAAQ,CAAC,MAAM,CAAC;AAAA,IAC3B;AAAA;AAAA,IAGA,YAAY,OAAmB,CAAC,GAAqB;AACpD,aAAO,IAAI,cAAiB,MAAM,KAAK,IAAI,YAAY;AAAA,IACxD;AAAA;AAAA,IAGA,IAAI,cAAsB;AACzB,aAAO,GAAG,MAAM,SAAS,KAAK,EAAE;AAAA,IACjC;AAAA;AAAA,IAGA,SAAqB;AACpB,YAAM,SAAsC,CAAC;AAC7C,iBAAW,QAAQ,UAAU;AAC5B,cAAM,QAAS,KAAa,KAAK,IAAI;AACrC,YAAI,UAAU,UAAa,UAAU,MAAM;AAC1C,iBAAO,KAAK,IAAI,IAAI;AAAA,QACrB;AAAA,MACD;AACA,aAAO;AAAA,IACR;AAAA,EACD;AAQA,WAAS,WAAW,IAAc,QAAgD;AACjF,QAAI,CAAC,MAAM,OAAO,OAAO,SAAU,OAAM,IAAI,MAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AACxF,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,IAAI,MAAM,4BAA4B;AAEnE,UAAM,YAAY,sBAAsB,MAAM;AAC9C,QAAI,YAAY,UAAU,IAAI,MAAM;AACpC,QAAI,CAAC,WAAW;AACf,kBAAY,oBAAI,IAAI;AACpB,gBAAU,IAAI,QAAQ,SAAS;AAAA,IAChC;AAEA,UAAM,WAAW,UAAU,IAAI,EAAE;AACjC,QAAI,SAAU,QAAO;AAErB,UAAM,KAAK,IAAI,UAAU,IAAI,QAAQ,KAAK;AAC1C,cAAU,IAAI,IAAI,EAAE;AACpB,WAAO;AAAA,EACR;AAKA,WAAS,eAAe,OAAmB,CAAC,GAAG,IAAiC;AAC/E,UAAM,WAAW,MAAM,MAAM,IAAW;AACxC,WAAO,cAAc,OAAU,MAAM,UAAU,YAAY;AAAA,EAC5D;AAGA,QAAM,UAAe;AACrB,UAAQ,MAAM;AACd,UAAQ,WAAW;AACnB,UAAQ,SAAS;AACjB,UAAQ,eAAe;AAEvB,SAAO;AAmBR;;;AClUO,SAAS,4BACf,QAKoB;AACpB,SAAO;AAAA,IACN,kBAAkB,MAAM,OAAO;AAAA,IAC/B,aAAa,MAAO,OAAO,YAAY,CAAC;AAAA,IACxC,iBAAiB,MAAM,OAAO;AAAA,EAC/B;AACD;AAKO,SAAS,YAAY,cAAsB,UAA0B;AAC3E,SAAO,GAAG,YAAY,IAAI,QAAQ;AACnC;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ApplogValue } from '../applog/datom-types.ts';
|
|
2
|
+
import type { ISchemaAdapter, VMAttributeDef } from './types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Helper to create a simple schema adapter from a plain attribute list.
|
|
5
|
+
* Useful for quick VM definitions or when you don't have a formal schema library.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createAdapterFromAttributes<T extends Record<string, ApplogValue>>(config: {
|
|
8
|
+
attributes: VMAttributeDef[];
|
|
9
|
+
entityPrefix: string;
|
|
10
|
+
defaults?: Partial<T>;
|
|
11
|
+
}): ISchemaAdapter<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Helper to build at-paths from attribute names and an entity prefix.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildAtPath(entityPrefix: string, attrName: string): string;
|
|
16
|
+
//# sourceMappingURL=schema-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-adapter.d.ts","sourceRoot":"","sources":["../../src/viewmodel/schema-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhE;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAChF,MAAM,EAAE;IACP,UAAU,EAAE,cAAc,EAAE,CAAA;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CACrB,GACC,cAAc,CAAC,CAAC,CAAC,CAMnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1E"}
|