📄 src/models/adapters/vue.ts
D-OPEN SOVEREIGN
Documentation & Insights
**Composes** the Vue 3 reactivity system into the models_v2 record tracker
(coexists with other frameworks — see `addReactivitySystem`). Each tracked
ORM record maps to a `shallowRef` in a `WeakMap`; a read inside a reactive
effect subscribes and a mutation bumps the ref. Idempotent; returns an
unregister function.Persistent models_v2 session for Vue — full front-end boot + Vue reactivity,
retained across URL navigation (SPA / Astro `<ClientRouter />`). Thin wrapper
over the shared `bootstrapSession()` glue with Vue's reactivity installer.Returns a Vue computed ref that updates whenever the given user's level changes.
Automatically unsubscribes when the calling component is unmounted.
@example
const { level, progress } = useLevel('mine').value;Reactive view over the global trash store (models/trash.ts) for one object
type, merged across `usernames` (empty = every known username). Population
and live updates are entirely automatic (boot scan + reactivity-system hook
inside trash.ts) — nothing to register, nothing to feed it.
@example
const { count, getIds } = useTrash(Tag.type, ['mine']);Creates a reactive draft for a models_v2 record in Vue.
Returns the draft proxy, and reactive helpers.1/*
2 * Copyright (c) 2026 DataPond D-Library Pty Ltd. ("The Sanctuary")
3 * Non-Profit Public Library — The World Library
4 *
5 * D-SAFE Certification issued by POND Enterprise.
6 * Published under the D-Open Code Sovereign Licence v1.0 framework
7 * DataPond D-Library All exclusive Right reserved on modifiying the code - CC Attribution to data pond, Non modifiable, Non Commercial.
8 * https://registry.world.bibliotech.com/licence
9 * Source code donated to DataPond D-Library by it's author: data pond.
10 *
11 * Technical Guardian ("The Shield"): Pond Enterprise Pty Ltd. (ACN 694 747 987)
12 * All liability claims about D-SAFE certification issues coming from the published D-Safe direction must be addressed with Pond Enterprise Pty Ltd.
13 * Code Modification automatically voids the certified liability protection provided by Pond Enterprise.
14 */
15import { computed, onUnmounted, shallowRef } from 'vue';
16import { getLevel, subscribeLevel } from '../level-state.ts';
17import { trashStore } from '../trash.ts';
18import { addReactivitySystem, type ReactivitySystem } from '../db.ts';
19import { bootstrapSession, type SessionBootstrapOptions, resetModelsV2Session } from '../session.ts';
20export { resetModelsV2Session };
21
22let _vueUnregister: (() => void) | null = null;
23
24/**
25 * **Composes** the Vue 3 reactivity system into the models_v2 record tracker
26 * (coexists with other frameworks — see `addReactivitySystem`). Each tracked
27 * ORM record maps to a `shallowRef` in a `WeakMap`; a read inside a reactive
28 * effect subscribes and a mutation bumps the ref. Idempotent; returns an
29 * unregister function.
30 */
31export const installVueReactivity = (): (() => void) => {
32 if (_vueUnregister) return _vueUnregister;
33 const refs = new WeakMap<object, { value: number }>();
34 const system: ReactivitySystem = {
35 track(o: object) {
36 let r = refs.get(o);
37 if (!r) { r = shallowRef(0); refs.set(o, r); }
38 void r.value;
39 },
40 trigger(o: object) {
41 const r = refs.get(o);
42 if (r) r.value++;
43 },
44 };
45 _vueUnregister = addReactivitySystem(system);
46 return _vueUnregister;
47};
48
49/**
50 * Persistent models_v2 session for Vue — full front-end boot + Vue reactivity,
51 * retained across URL navigation (SPA / Astro `<ClientRouter />`). Thin wrapper
52 * over the shared `bootstrapSession()` glue with Vue's reactivity installer.
53 */
54export const bootstrapModelsV2 = (opts: SessionBootstrapOptions): Promise<void> =>
55 bootstrapSession(opts, installVueReactivity);
56
57/**
58 * Returns a Vue computed ref that updates whenever the given user's level changes.
59 * Automatically unsubscribes when the calling component is unmounted.
60 *
61 * @example
62 * const { level, progress } = useLevel('mine').value;
63 */
64export const useLevel = (username: string) => {
65 const tick = shallowRef(0);
66 const unsub = subscribeLevel(u => { if (u === username) tick.value++; });
67 onUnmounted(unsub);
68 return computed(() => (tick.value, getLevel(username)));
69};
70
71/**
72 * Reactive view over the global trash store (models/trash.ts) for one object
73 * type, merged across `usernames` (empty = every known username). Population
74 * and live updates are entirely automatic (boot scan + reactivity-system hook
75 * inside trash.ts) — nothing to register, nothing to feed it.
76 *
77 * @example
78 * const { count, getIds } = useTrash(Tag.type, ['mine']);
79 */
80export const useTrash = (objectType: number, usernames: string[] = []) => {
81 const tick = shallowRef(0);
82 const unsub = trashStore.subscribe(objectType, () => { tick.value++; });
83 onUnmounted(unsub);
84 return {
85 count: computed(() => (tick.value, trashStore.count(objectType, usernames))),
86 getIds: () => trashStore.list(objectType, usernames),
87 };
88};
89
90/**
91 * Creates a reactive draft for a models_v2 record in Vue.
92 * Returns the draft proxy, and reactive helpers.
93 */
94import { createDraft, isDraftDirty, commitDraft, rollbackDraft } from '../draft.ts';
95import type { Orm } from '../orm.ts';
96import { type Ref } from 'vue';
97
98export const useDraft = <T extends Orm>(model: Ref<T> | (() => T)) => {
99 const tick = shallowRef(0);
100 // recreate draft when underlying model changes, but keep it stable otherwise
101 const draft = computed(() => {
102 const m = typeof model === 'function' ? model() : model.value;
103 return createDraft(m, () => { tick.value++; });
104 });
105
106 return {
107 draft,
108 isDirty: computed(() => {
109 void tick.value; // depend on edits
110 return isDraftDirty(draft.value);
111 }),
112 commit: () => {
113 commitDraft(draft.value);
114 tick.value++;
115 },
116 rollback: () => {
117 rollbackDraft(draft.value);
118 tick.value++;
119 }
120 };
121};
122