doxum 0.1.1

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +218 -0
  3. package/dist/chunk-pbuEa-1d.js +13 -0
  4. package/dist/contract-DwNiKioc.d.ts +480 -0
  5. package/dist/contract-Otb5W6cQ.d.cts +480 -0
  6. package/dist/dependency-BdEMyquf.js +735 -0
  7. package/dist/dependency-BdEMyquf.js.map +1 -0
  8. package/dist/dependency-DLcCvNKq.cjs +1015 -0
  9. package/dist/dependency-DLcCvNKq.cjs.map +1 -0
  10. package/dist/index.cjs +2718 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +89 -0
  13. package/dist/index.d.ts +87 -0
  14. package/dist/index.js +2689 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/integration.cjs +15 -0
  17. package/dist/integration.cjs.map +1 -0
  18. package/dist/integration.d.cts +11 -0
  19. package/dist/integration.d.ts +11 -0
  20. package/dist/integration.js +14 -0
  21. package/dist/integration.js.map +1 -0
  22. package/dist/react.cjs +99 -0
  23. package/dist/react.cjs.map +1 -0
  24. package/dist/react.d.cts +16 -0
  25. package/dist/react.d.ts +16 -0
  26. package/dist/react.js +96 -0
  27. package/dist/react.js.map +1 -0
  28. package/package.json +89 -0
  29. package/skills/doxum-runtime/SKILL.md +51 -0
  30. package/skills/doxum-runtime/agents/openai.yaml +4 -0
  31. package/skills/doxum-runtime/references/guide.en.md +295 -0
  32. package/skills/doxum-runtime/references/guide.zh-CN.md +240 -0
  33. package/skills/doxum-runtime/references/invariants.en.md +147 -0
  34. package/skills/doxum-runtime/references/invariants.zh-CN.md +97 -0
  35. package/skills/doxum-runtime/references/patterns.en.md +287 -0
  36. package/skills/doxum-runtime/references/patterns.zh-CN.md +240 -0
@@ -0,0 +1,14 @@
1
+ import { i as readWith, t as createDependencyTracker } from "./dependency-BdEMyquf.js";
2
+ //#region core/src/integration.ts
3
+ const track = (runtime, selector) => {
4
+ const dependencies = createDependencyTracker();
5
+ const value = readWith(runtime, selector, dependencies);
6
+ return Object.freeze({
7
+ value,
8
+ targets: dependencies.snapshot()
9
+ });
10
+ };
11
+ //#endregion
12
+ export { track };
13
+
14
+ //# sourceMappingURL=integration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.js","names":[],"sources":["../core/src/integration.ts"],"sourcesContent":["import type { DocumentSchema, ImpactTarget } from './schema';\nimport type { DocumentReader } from './access/reader';\nimport type { DocumentRuntime } from './runtime/contract';\nimport { createDependencyTracker } from './access/dependency';\nimport { readWith } from './runtime/access';\n\nexport type TrackedSelection<TValue> = {\n readonly value: TValue;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\n// Framework adapters receive one immutable result instead of coordinating a\n// mutable collector with the reader's scoped lifetime themselves.\nexport const track = <TSchema extends DocumentSchema, TValue>(\n runtime: DocumentRuntime<TSchema>,\n selector: (read: DocumentReader<TSchema>) => TValue\n): TrackedSelection<TValue> => {\n const dependencies = createDependencyTracker();\n const value = readWith(runtime, selector, dependencies);\n return Object.freeze({ value, targets: dependencies.snapshot() });\n};\n"],"mappings":";;AAaA,MAAa,SACX,SACA,aAC6B;CAC7B,MAAM,eAAe,yBAAyB;CAC9C,MAAM,QAAQ,SAAS,SAAS,UAAU,aAAa;AACvD,QAAO,OAAO,OAAO;EAAE;EAAO,SAAS,aAAa,UAAU;EAAE,CAAC"}
package/dist/react.cjs ADDED
@@ -0,0 +1,99 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_integration = require("./integration.cjs");
3
+ let doxum = require("doxum");
4
+ let react = require("react");
5
+ //#region react/src/hooks.ts
6
+ const objectIs = (previous, next) => Object.is(previous, next);
7
+ const sameTargets = (left, right) => {
8
+ if (left.length !== right.length) return false;
9
+ for (let index = 0; index < left.length; index += 1) if (!doxum.target.same(left[index], right[index])) return false;
10
+ return true;
11
+ };
12
+ function useDocumentSelector(runtime, selector, options) {
13
+ const equality = options?.isEqual ?? objectIs;
14
+ const cache = (0, react.useRef)(void 0);
15
+ const serverCache = (0, react.useRef)(void 0);
16
+ const read = (0, react.useCallback)(() => {
17
+ const selection = require_integration.track(runtime, selector);
18
+ const next = selection.value;
19
+ const previous = cache.current;
20
+ const targets = selection.targets;
21
+ if (previous && previous.runtime === runtime && equality(previous.value, next)) {
22
+ cache.current = {
23
+ runtime,
24
+ value: previous.value,
25
+ targets
26
+ };
27
+ return previous.value;
28
+ }
29
+ cache.current = {
30
+ runtime,
31
+ value: next,
32
+ targets
33
+ };
34
+ return next;
35
+ }, [
36
+ equality,
37
+ runtime,
38
+ selector
39
+ ]);
40
+ const subscribe = (0, react.useCallback)((listener) => {
41
+ let targets = cache.current?.targets ?? [];
42
+ let unsubscribe = () => void 0;
43
+ const install = () => {
44
+ if (targets.length === 0) return () => void 0;
45
+ return runtime.subscribe(targets.length === 1 ? targets[0] : targets, onCommit);
46
+ };
47
+ const onCommit = () => {
48
+ const previous = cache.current;
49
+ const next = read();
50
+ const nextTargets = cache.current?.targets ?? [];
51
+ if (!sameTargets(targets, nextTargets)) {
52
+ unsubscribe();
53
+ targets = nextTargets;
54
+ unsubscribe = install();
55
+ }
56
+ if (previous && previous.value !== next) listener();
57
+ };
58
+ unsubscribe = install();
59
+ return () => unsubscribe();
60
+ }, [read, runtime]);
61
+ const server = options?.server;
62
+ return (0, react.useSyncExternalStore)(subscribe, read, (0, react.useCallback)(() => {
63
+ const previous = serverCache.current;
64
+ if (previous && previous.source === server) return previous.value;
65
+ const value = server ? server() : read();
66
+ serverCache.current = {
67
+ source: server,
68
+ value
69
+ };
70
+ return value;
71
+ }, [read, server]));
72
+ }
73
+ function useReadable(readable) {
74
+ const subscribe = (0, react.useCallback)((listener) => readable.subscribe(listener), [readable]);
75
+ const read = (0, react.useCallback)(() => readable.current(), [readable]);
76
+ return (0, react.useSyncExternalStore)(subscribe, read, read);
77
+ }
78
+ function useHistory(history) {
79
+ const subscribe = (0, react.useCallback)((listener) => history.subscribe(listener), [history]);
80
+ const read = (0, react.useCallback)(() => history.current(), [history]);
81
+ const state = (0, react.useSyncExternalStore)(subscribe, read, read);
82
+ const undo = (0, react.useCallback)(() => history.undo(), [history]);
83
+ const redo = (0, react.useCallback)(() => history.redo(), [history]);
84
+ return (0, react.useMemo)(() => ({
85
+ ...state,
86
+ undo,
87
+ redo
88
+ }), [
89
+ redo,
90
+ state,
91
+ undo
92
+ ]);
93
+ }
94
+ //#endregion
95
+ exports.useDocumentSelector = useDocumentSelector;
96
+ exports.useHistory = useHistory;
97
+ exports.useReadable = useReadable;
98
+
99
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.cjs","names":["target","track"],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentRuntime,\n DocumentSchema,\n DocumentSelector,\n HistoryState,\n ImpactTarget,\n LocalHistory,\n OperationResult,\n Readable,\n} from 'doxum';\nimport { target } from 'doxum';\nimport { track } from 'doxum/integration';\nimport { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends DocumentSchema, TResult> = {\n readonly runtime: DocumentRuntime<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!target.same(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends DocumentSchema, TResult>(\n runtime: DocumentRuntime<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n { readonly source: (() => TResult) | undefined; readonly value: TResult } | undefined\n >(undefined);\n\n const read = useCallback((): TResult => {\n const selection = track(runtime, selector);\n const next = selection.value;\n const previous = cache.current;\n\n // Keep the prior reference for semantic equality on the same runtime. This\n // is what makes inline selectors safe with useSyncExternalStore.\n const targets = selection.targets;\n if (previous && previous.runtime === runtime && equality(previous.value, next)) {\n cache.current = { runtime, value: previous.value, targets };\n return previous.value;\n }\n\n cache.current = { runtime, value: next, targets };\n return next;\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return runtime.subscribe(\n targets.length === 1\n ? targets[0]\n : (targets as [ImpactTarget<unknown>, ...ImpactTarget<unknown>[]]),\n onCommit\n );\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && previous.value !== next) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (previous && previous.source === server) return previous.value;\n const value = server ? server() : read();\n serverCache.current = { source: server, value };\n return value;\n }, [read, server]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { DocumentRuntime, DocumentSchema, DocumentSelector, HistoryState, LocalHistory, OperationResult, Readable } from "doxum";
2
+
3
+ //#region react/src/hooks.d.ts
4
+ type DocumentSelectorOptions<TResult> = {
5
+ readonly isEqual?: (previous: TResult, next: TResult) => boolean;
6
+ readonly server?: () => TResult;
7
+ };
8
+ declare function useDocumentSelector<TSchema extends DocumentSchema, TResult>(runtime: DocumentRuntime<TSchema>, selector: DocumentSelector<TSchema, TResult>, options?: DocumentSelectorOptions<TResult>): TResult;
9
+ declare function useReadable<T>(readable: Readable<T>): T;
10
+ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {
11
+ undo(): OperationResult<TCommit>;
12
+ redo(): OperationResult<TCommit>;
13
+ };
14
+ //#endregion
15
+ export { type DocumentSelectorOptions, useDocumentSelector, useHistory, useReadable };
16
+ //# sourceMappingURL=react.d.cts.map
@@ -0,0 +1,16 @@
1
+ import { DocumentRuntime, DocumentSchema, DocumentSelector, HistoryState, LocalHistory, OperationResult, Readable } from "doxum";
2
+
3
+ //#region react/src/hooks.d.ts
4
+ type DocumentSelectorOptions<TResult> = {
5
+ readonly isEqual?: (previous: TResult, next: TResult) => boolean;
6
+ readonly server?: () => TResult;
7
+ };
8
+ declare function useDocumentSelector<TSchema extends DocumentSchema, TResult>(runtime: DocumentRuntime<TSchema>, selector: DocumentSelector<TSchema, TResult>, options?: DocumentSelectorOptions<TResult>): TResult;
9
+ declare function useReadable<T>(readable: Readable<T>): T;
10
+ declare function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {
11
+ undo(): OperationResult<TCommit>;
12
+ redo(): OperationResult<TCommit>;
13
+ };
14
+ //#endregion
15
+ export { type DocumentSelectorOptions, useDocumentSelector, useHistory, useReadable };
16
+ //# sourceMappingURL=react.d.ts.map
package/dist/react.js ADDED
@@ -0,0 +1,96 @@
1
+ import { track } from "./integration.js";
2
+ import { target } from "doxum";
3
+ import { useCallback, useMemo, useRef, useSyncExternalStore } from "react";
4
+ //#region react/src/hooks.ts
5
+ const objectIs = (previous, next) => Object.is(previous, next);
6
+ const sameTargets = (left, right) => {
7
+ if (left.length !== right.length) return false;
8
+ for (let index = 0; index < left.length; index += 1) if (!target.same(left[index], right[index])) return false;
9
+ return true;
10
+ };
11
+ function useDocumentSelector(runtime, selector, options) {
12
+ const equality = options?.isEqual ?? objectIs;
13
+ const cache = useRef(void 0);
14
+ const serverCache = useRef(void 0);
15
+ const read = useCallback(() => {
16
+ const selection = track(runtime, selector);
17
+ const next = selection.value;
18
+ const previous = cache.current;
19
+ const targets = selection.targets;
20
+ if (previous && previous.runtime === runtime && equality(previous.value, next)) {
21
+ cache.current = {
22
+ runtime,
23
+ value: previous.value,
24
+ targets
25
+ };
26
+ return previous.value;
27
+ }
28
+ cache.current = {
29
+ runtime,
30
+ value: next,
31
+ targets
32
+ };
33
+ return next;
34
+ }, [
35
+ equality,
36
+ runtime,
37
+ selector
38
+ ]);
39
+ const subscribe = useCallback((listener) => {
40
+ let targets = cache.current?.targets ?? [];
41
+ let unsubscribe = () => void 0;
42
+ const install = () => {
43
+ if (targets.length === 0) return () => void 0;
44
+ return runtime.subscribe(targets.length === 1 ? targets[0] : targets, onCommit);
45
+ };
46
+ const onCommit = () => {
47
+ const previous = cache.current;
48
+ const next = read();
49
+ const nextTargets = cache.current?.targets ?? [];
50
+ if (!sameTargets(targets, nextTargets)) {
51
+ unsubscribe();
52
+ targets = nextTargets;
53
+ unsubscribe = install();
54
+ }
55
+ if (previous && previous.value !== next) listener();
56
+ };
57
+ unsubscribe = install();
58
+ return () => unsubscribe();
59
+ }, [read, runtime]);
60
+ const server = options?.server;
61
+ return useSyncExternalStore(subscribe, read, useCallback(() => {
62
+ const previous = serverCache.current;
63
+ if (previous && previous.source === server) return previous.value;
64
+ const value = server ? server() : read();
65
+ serverCache.current = {
66
+ source: server,
67
+ value
68
+ };
69
+ return value;
70
+ }, [read, server]));
71
+ }
72
+ function useReadable(readable) {
73
+ const subscribe = useCallback((listener) => readable.subscribe(listener), [readable]);
74
+ const read = useCallback(() => readable.current(), [readable]);
75
+ return useSyncExternalStore(subscribe, read, read);
76
+ }
77
+ function useHistory(history) {
78
+ const subscribe = useCallback((listener) => history.subscribe(listener), [history]);
79
+ const read = useCallback(() => history.current(), [history]);
80
+ const state = useSyncExternalStore(subscribe, read, read);
81
+ const undo = useCallback(() => history.undo(), [history]);
82
+ const redo = useCallback(() => history.redo(), [history]);
83
+ return useMemo(() => ({
84
+ ...state,
85
+ undo,
86
+ redo
87
+ }), [
88
+ redo,
89
+ state,
90
+ undo
91
+ ]);
92
+ }
93
+ //#endregion
94
+ export { useDocumentSelector, useHistory, useReadable };
95
+
96
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","names":[],"sources":["../react/src/hooks.ts"],"sourcesContent":["import type {\n DocumentRuntime,\n DocumentSchema,\n DocumentSelector,\n HistoryState,\n ImpactTarget,\n LocalHistory,\n OperationResult,\n Readable,\n} from 'doxum';\nimport { target } from 'doxum';\nimport { track } from 'doxum/integration';\nimport { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';\n\nexport type DocumentSelectorOptions<TResult> = {\n readonly isEqual?: (previous: TResult, next: TResult) => boolean;\n readonly server?: () => TResult;\n};\n\ntype SelectorCache<TSchema extends DocumentSchema, TResult> = {\n readonly runtime: DocumentRuntime<TSchema>;\n readonly value: TResult;\n readonly targets: readonly ImpactTarget<unknown>[];\n};\n\nconst objectIs = <T>(previous: T, next: T): boolean => Object.is(previous, next);\nconst sameTargets = (\n left: readonly ImpactTarget<unknown>[],\n right: readonly ImpactTarget<unknown>[]\n): boolean => {\n if (left.length !== right.length) return false;\n for (let index = 0; index < left.length; index += 1)\n if (!target.same(left[index], right[index])) return false;\n return true;\n};\n\nexport function useDocumentSelector<TSchema extends DocumentSchema, TResult>(\n runtime: DocumentRuntime<TSchema>,\n selector: DocumentSelector<TSchema, TResult>,\n options?: DocumentSelectorOptions<TResult>\n): TResult {\n const equality = options?.isEqual ?? objectIs;\n const cache = useRef<SelectorCache<TSchema, TResult> | undefined>(undefined);\n const serverCache = useRef<\n { readonly source: (() => TResult) | undefined; readonly value: TResult } | undefined\n >(undefined);\n\n const read = useCallback((): TResult => {\n const selection = track(runtime, selector);\n const next = selection.value;\n const previous = cache.current;\n\n // Keep the prior reference for semantic equality on the same runtime. This\n // is what makes inline selectors safe with useSyncExternalStore.\n const targets = selection.targets;\n if (previous && previous.runtime === runtime && equality(previous.value, next)) {\n cache.current = { runtime, value: previous.value, targets };\n return previous.value;\n }\n\n cache.current = { runtime, value: next, targets };\n return next;\n }, [equality, runtime, selector]);\n\n const subscribe = useCallback(\n (listener: () => void) => {\n let targets = cache.current?.targets ?? [];\n let unsubscribe: () => void = () => undefined;\n const install = () => {\n if (targets.length === 0) return () => undefined;\n return runtime.subscribe(\n targets.length === 1\n ? targets[0]\n : (targets as [ImpactTarget<unknown>, ...ImpactTarget<unknown>[]]),\n onCommit\n );\n };\n const onCommit = () => {\n const previous = cache.current;\n const next = read();\n const nextTargets = cache.current?.targets ?? [];\n if (!sameTargets(targets, nextTargets)) {\n unsubscribe();\n targets = nextTargets;\n unsubscribe = install();\n }\n if (previous && previous.value !== next) listener();\n };\n unsubscribe = install();\n return () => unsubscribe();\n },\n [read, runtime]\n );\n\n const server = options?.server;\n const readServer = useCallback((): TResult => {\n const previous = serverCache.current;\n if (previous && previous.source === server) return previous.value;\n const value = server ? server() : read();\n serverCache.current = { source: server, value };\n return value;\n }, [read, server]);\n\n return useSyncExternalStore(subscribe, read, readServer);\n}\n\nexport function useReadable<T>(readable: Readable<T>): T {\n const subscribe = useCallback((listener: () => void) => readable.subscribe(listener), [readable]);\n const read = useCallback(() => readable.current(), [readable]);\n return useSyncExternalStore(subscribe, read, read);\n}\n\nexport function useHistory<TCommit>(history: LocalHistory<TCommit>): HistoryState & {\n undo(): OperationResult<TCommit>;\n redo(): OperationResult<TCommit>;\n} {\n const subscribe = useCallback((listener: () => void) => history.subscribe(listener), [history]);\n const read = useCallback(() => history.current(), [history]);\n const state = useSyncExternalStore(subscribe, read, read);\n const undo = useCallback(() => history.undo(), [history]);\n const redo = useCallback(() => history.redo(), [history]);\n\n return useMemo(() => ({ ...state, undo, redo }), [redo, state, undo]);\n}\n"],"mappings":";;;;AAyBA,MAAM,YAAe,UAAa,SAAqB,OAAO,GAAG,UAAU,KAAK;AAChF,MAAM,eACJ,MACA,UACY;AACZ,KAAI,KAAK,WAAW,MAAM,OAAQ,QAAO;AACzC,MAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,EAChD,KAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,MAAM,OAAO,CAAE,QAAO;AACtD,QAAO;;AAGT,SAAgB,oBACd,SACA,UACA,SACS;CACT,MAAM,WAAW,SAAS,WAAW;CACrC,MAAM,QAAQ,OAAoD,KAAA,EAAU;CAC5E,MAAM,cAAc,OAElB,KAAA,EAAU;CAEZ,MAAM,OAAO,kBAA2B;EACtC,MAAM,YAAY,MAAM,SAAS,SAAS;EAC1C,MAAM,OAAO,UAAU;EACvB,MAAM,WAAW,MAAM;EAIvB,MAAM,UAAU,UAAU;AAC1B,MAAI,YAAY,SAAS,YAAY,WAAW,SAAS,SAAS,OAAO,KAAK,EAAE;AAC9E,SAAM,UAAU;IAAE;IAAS,OAAO,SAAS;IAAO;IAAS;AAC3D,UAAO,SAAS;;AAGlB,QAAM,UAAU;GAAE;GAAS,OAAO;GAAM;GAAS;AACjD,SAAO;IACN;EAAC;EAAU;EAAS;EAAS,CAAC;CAEjC,MAAM,YAAY,aACf,aAAyB;EACxB,IAAI,UAAU,MAAM,SAAS,WAAW,EAAE;EAC1C,IAAI,oBAAgC,KAAA;EACpC,MAAM,gBAAgB;AACpB,OAAI,QAAQ,WAAW,EAAG,cAAa,KAAA;AACvC,UAAO,QAAQ,UACb,QAAQ,WAAW,IACf,QAAQ,KACP,SACL,SACD;;EAEH,MAAM,iBAAiB;GACrB,MAAM,WAAW,MAAM;GACvB,MAAM,OAAO,MAAM;GACnB,MAAM,cAAc,MAAM,SAAS,WAAW,EAAE;AAChD,OAAI,CAAC,YAAY,SAAS,YAAY,EAAE;AACtC,iBAAa;AACb,cAAU;AACV,kBAAc,SAAS;;AAEzB,OAAI,YAAY,SAAS,UAAU,KAAM,WAAU;;AAErD,gBAAc,SAAS;AACvB,eAAa,aAAa;IAE5B,CAAC,MAAM,QAAQ,CAChB;CAED,MAAM,SAAS,SAAS;AASxB,QAAO,qBAAqB,WAAW,MARpB,kBAA2B;EAC5C,MAAM,WAAW,YAAY;AAC7B,MAAI,YAAY,SAAS,WAAW,OAAQ,QAAO,SAAS;EAC5D,MAAM,QAAQ,SAAS,QAAQ,GAAG,MAAM;AACxC,cAAY,UAAU;GAAE,QAAQ;GAAQ;GAAO;AAC/C,SAAO;IACN,CAAC,MAAM,OAAO,CAEsC,CAAC;;AAG1D,SAAgB,YAAe,UAA0B;CACvD,MAAM,YAAY,aAAa,aAAyB,SAAS,UAAU,SAAS,EAAE,CAAC,SAAS,CAAC;CACjG,MAAM,OAAO,kBAAkB,SAAS,SAAS,EAAE,CAAC,SAAS,CAAC;AAC9D,QAAO,qBAAqB,WAAW,MAAM,KAAK;;AAGpD,SAAgB,WAAoB,SAGlC;CACA,MAAM,YAAY,aAAa,aAAyB,QAAQ,UAAU,SAAS,EAAE,CAAC,QAAQ,CAAC;CAC/F,MAAM,OAAO,kBAAkB,QAAQ,SAAS,EAAE,CAAC,QAAQ,CAAC;CAC5D,MAAM,QAAQ,qBAAqB,WAAW,MAAM,KAAK;CACzD,MAAM,OAAO,kBAAkB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC;CACzD,MAAM,OAAO,kBAAkB,QAAQ,MAAM,EAAE,CAAC,QAAQ,CAAC;AAEzD,QAAO,eAAe;EAAE,GAAG;EAAO;EAAM;EAAM,GAAG;EAAC;EAAM;EAAO;EAAK,CAAC"}
package/package.json ADDED
@@ -0,0 +1,89 @@
1
+ {
2
+ "name": "doxum",
3
+ "version": "0.1.1",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "description": "Doxum is a typed runtime for complex mutable documents.",
7
+ "type": "module",
8
+ "keywords": [
9
+ "document",
10
+ "state",
11
+ "runtime",
12
+ "typescript"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Isrowan/doxum.git"
17
+ },
18
+ "homepage": "https://github.com/Isrowan/doxum#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/Isrowan/doxum/issues"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "main": "./dist/index.cjs",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "require": "./dist/index.cjs"
33
+ },
34
+ "./integration": {
35
+ "types": "./dist/integration.d.ts",
36
+ "import": "./dist/integration.js",
37
+ "require": "./dist/integration.cjs"
38
+ },
39
+ "./react": {
40
+ "types": "./dist/react.d.ts",
41
+ "import": "./dist/react.js",
42
+ "require": "./dist/react.cjs"
43
+ }
44
+ },
45
+ "peerDependencies": {
46
+ "react": ">=18"
47
+ },
48
+ "peerDependenciesMeta": {
49
+ "react": {
50
+ "optional": true
51
+ }
52
+ },
53
+ "files": [
54
+ "dist",
55
+ "skills"
56
+ ],
57
+ "sideEffects": false,
58
+ "devDependencies": {
59
+ "@eslint/js": "^9.35.0",
60
+ "eslint": "^9.35.0",
61
+ "prettier": "^3.6.2",
62
+ "rimraf": "^6.1.3",
63
+ "tsdown": "^0.21.1",
64
+ "tsx": "^4.21.0",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.43.0",
67
+ "vitest": "^4.0.16",
68
+ "@types/react": "^19.2.5",
69
+ "@types/react-dom": "^19.2.3",
70
+ "@types/react-test-renderer": "^19.1.0",
71
+ "react": "19.2.4",
72
+ "react-dom": "19.2.4",
73
+ "react-test-renderer": "19.2.4"
74
+ },
75
+ "scripts": {
76
+ "build": "tsdown --config tsdown.config.ts",
77
+ "typecheck": "tsc -p tsconfig.json --noEmit",
78
+ "test": "vitest run --config vitest.config.ts",
79
+ "check": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run test",
80
+ "bench": "vitest bench --config vitest.bench.config.ts",
81
+ "profile": "node --expose-gc --import tsx core/bench/profile.ts",
82
+ "format": "prettier --write --ignore-unknown .",
83
+ "format:check": "prettier --check --ignore-unknown .",
84
+ "lint": "eslint .",
85
+ "clean": "pnpm -r exec rimraf dist",
86
+ "release": "node scripts/release.mjs",
87
+ "release:resume": "node scripts/release.mjs --resume"
88
+ }
89
+ }
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: doxum-runtime
3
+ description: 'Use doxum and doxum/react to design, build, or review Doxum document runtime code. Apply for schemas, mutations, operations, views, subscriptions, and React integration.'
4
+ ---
5
+
6
+ # Doxum Runtime
7
+
8
+ Use this skill when a task creates, modifies, reviews, or explains Doxum code.
9
+ It applies to `doxum`, `doxum/react`, and application code that uses
10
+ Doxum's schema, runtime, transaction, operation, impact, projection, or React
11
+ APIs. Do not apply it to unrelated TypeScript or React work merely because the
12
+ application happens to contain a Doxum runtime.
13
+
14
+ ## Read the right reference
15
+
16
+ - Start with [the English guide](references/guide.en.md) for English requests
17
+ or [中文指南](references/guide.zh-CN.md) for Chinese requests. They are
18
+ equivalent task-oriented introductions.
19
+ - Read [the English patterns](references/patterns.en.md) or
20
+ [中文模式参考](references/patterns.zh-CN.md) when implementing schema models,
21
+ transactions, replay, selectors, views, or React code.
22
+ - Read [the English invariants](references/invariants.en.md) or
23
+ [中文不变量](references/invariants.zh-CN.md) before changing mutation,
24
+ addressing, impact, notification, history, tree, or derived-view behavior.
25
+
26
+ ## Required Doxum decisions
27
+
28
+ - Treat `createDocument` as the only write authority for canonical document
29
+ state. Application writes use `runtime.update`; replayed external operations
30
+ use `runtime.apply`.
31
+ - A transaction is synchronous and atomic. Do not retain a transaction reader
32
+ or writer after its callback returns, and do not introduce another writable
33
+ state cache.
34
+ - Use the runtime's schema selectors, anchors, addresses, and `target` APIs.
35
+ Do not add local path parsers, duplicate impact-target helpers, or manually
36
+ synchronize derived data.
37
+ - Handle expected mutation failure from the returned `rejected` result and its
38
+ `MutationIssue` values. Use `tx.report` or `tx.reject` with
39
+ `DocumentDiagnostic` for application validation. A thrown callback error
40
+ rolls back and is rethrown.
41
+ - A committed result with `observerErrors` is still committed. Do not retry its
42
+ write as if canonical state had been rolled back.
43
+ - Keep `core` framework-neutral. React code belongs behind `doxum/react` and
44
+ must not make `core` import UI concepts.
45
+ - Doxum does not define persistence, synchronization, authorization, or
46
+ conflict resolution. Keep those policies in the application boundary before
47
+ `apply` or `replace`.
48
+
49
+ When public behavior or lifecycle semantics change, update the README and
50
+ architecture guide and add focused tests for rollback, inverse history, impact
51
+ or subscription behavior, and performance-sensitive collection or tree paths.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: 'Doxum Runtime'
3
+ short_description: 'Build, modify, and review Doxum runtime code safely.'
4
+ default_prompt: 'Use $doxum-runtime to implement this Doxum feature while preserving its runtime invariants.'