@pathmx/core 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/LICENSE.md +172 -0
  2. package/README.md +111 -0
  3. package/actions/actions.ts +307 -0
  4. package/actions/draft.ts +105 -0
  5. package/actions/transaction.ts +164 -0
  6. package/assets.ts +149 -0
  7. package/authority/access.ts +820 -0
  8. package/authority/actors.ts +271 -0
  9. package/authority/agents.ts +95 -0
  10. package/authority/credentials.ts +144 -0
  11. package/authority/model.ts +71 -0
  12. package/authority/sharing.ts +89 -0
  13. package/browser-bundle.ts +61 -0
  14. package/canonical.ts +41 -0
  15. package/cli/dev.ts +134 -0
  16. package/cli/export.ts +74 -0
  17. package/cli/index.ts +52 -0
  18. package/cli/lint.ts +164 -0
  19. package/cli/mv.ts +30 -0
  20. package/cli/perms.ts +182 -0
  21. package/cli/plugin-packages.ts +159 -0
  22. package/cli/plugins.ts +95 -0
  23. package/cli/query.ts +225 -0
  24. package/cli/readme.md +95 -0
  25. package/cli/release.ts +75 -0
  26. package/cli/rm.ts +22 -0
  27. package/cli/serve.ts +100 -0
  28. package/cli/tree.ts +131 -0
  29. package/cli/update.ts +78 -0
  30. package/cli/utils.ts +53 -0
  31. package/core.ts +96 -0
  32. package/database.ts +189 -0
  33. package/dependencies.ts +60 -0
  34. package/dist/pathmx.js +1224 -0
  35. package/document.ts +194 -0
  36. package/environment.ts +110 -0
  37. package/environments/bun-plugins.ts +68 -0
  38. package/environments/bun-publish.ts +194 -0
  39. package/environments/bun.ts +223 -0
  40. package/globals.d.ts +14 -0
  41. package/graph.ts +153 -0
  42. package/host/compiler.ts +314 -0
  43. package/host/create.ts +66 -0
  44. package/host/engine.ts +630 -0
  45. package/host/plugin-host.ts +487 -0
  46. package/host/render.ts +102 -0
  47. package/host/response.ts +20 -0
  48. package/host/shell.html +15 -0
  49. package/host/source-sync.ts +254 -0
  50. package/html-attributes.ts +15 -0
  51. package/html.ts +48 -0
  52. package/icons/LICENSE +43 -0
  53. package/icons/lucide.ts +54 -0
  54. package/index.ts +75 -0
  55. package/invalidation.ts +85 -0
  56. package/log.ts +84 -0
  57. package/ops/href.ts +87 -0
  58. package/ops/index.ts +9 -0
  59. package/ops/move-source.ts +114 -0
  60. package/ops/plan.ts +47 -0
  61. package/ops/remove-source.ts +70 -0
  62. package/package.json +46 -0
  63. package/path.ts +75 -0
  64. package/pattern.ts +314 -0
  65. package/perf.ts +88 -0
  66. package/plugins/actor-path.ts +43 -0
  67. package/plugins/actor-profile.ts +55 -0
  68. package/plugins/agent-browsing.ts +183 -0
  69. package/plugins/app-component.ts +23 -0
  70. package/plugins/block-layout/index.ts +78 -0
  71. package/plugins/block-layout/theme.css +90 -0
  72. package/plugins/callout/index.ts +236 -0
  73. package/plugins/callout/theme.css +138 -0
  74. package/plugins/canonical-links.ts +144 -0
  75. package/plugins/code-highlight/client.ts +89 -0
  76. package/plugins/code-highlight/index.ts +147 -0
  77. package/plugins/code-highlight/theme.css +89 -0
  78. package/plugins/context.ts +131 -0
  79. package/plugins/datatype/Datatype[wdth,wght].woff2 +0 -0
  80. package/plugins/datatype/OFL.txt +96 -0
  81. package/plugins/datatype/index.ts +287 -0
  82. package/plugins/definition-list.ts +236 -0
  83. package/plugins/directive-definitions.ts +13 -0
  84. package/plugins/embedding/client.ts +88 -0
  85. package/plugins/embedding/index.ts +43 -0
  86. package/plugins/image/index.ts +68 -0
  87. package/plugins/image/theme.css +43 -0
  88. package/plugins/include.ts +119 -0
  89. package/plugins/index.ts +91 -0
  90. package/plugins/input/authoring.ts +236 -0
  91. package/plugins/input/config.ts +85 -0
  92. package/plugins/input/index.ts +359 -0
  93. package/plugins/input/model.ts +173 -0
  94. package/plugins/input/state.ts +272 -0
  95. package/plugins/layout.ts +313 -0
  96. package/plugins/literate/client.ts +208 -0
  97. package/plugins/literate/index.ts +742 -0
  98. package/plugins/math/index.ts +140 -0
  99. package/plugins/meta.ts +42 -0
  100. package/plugins/navigation/index.ts +158 -0
  101. package/plugins/navigation/model.ts +364 -0
  102. package/plugins/preset.ts +65 -0
  103. package/plugins/query/index.ts +322 -0
  104. package/plugins/rss/index.ts +46 -0
  105. package/plugins/runtime/actions.ts +62 -0
  106. package/plugins/runtime/client.ts +8 -0
  107. package/plugins/runtime/document.ts +506 -0
  108. package/plugins/runtime/error.ts +154 -0
  109. package/plugins/runtime/heading-links.ts +31 -0
  110. package/plugins/runtime/index.ts +104 -0
  111. package/plugins/runtime/live.ts +51 -0
  112. package/plugins/runtime/navigation.ts +113 -0
  113. package/plugins/runtime/pending.ts +53 -0
  114. package/plugins/runtime/publication.ts +19 -0
  115. package/plugins/runtime/start.ts +177 -0
  116. package/plugins/runtime/static-client.ts +6 -0
  117. package/plugins/runtime/static-live.ts +188 -0
  118. package/plugins/runtime/view-transition.ts +72 -0
  119. package/plugins/runtime/viewport.ts +110 -0
  120. package/plugins/schema.ts +24 -0
  121. package/plugins/scripts.ts +140 -0
  122. package/plugins/source-preview/client.ts +256 -0
  123. package/plugins/source-preview/index.ts +132 -0
  124. package/plugins/source-preview/model.ts +11 -0
  125. package/plugins/source-preview/preview.css +107 -0
  126. package/plugins/styles.ts +145 -0
  127. package/plugins/theme/components.ts +10 -0
  128. package/plugins/theme/foundation.css +358 -0
  129. package/plugins/theme/index.ts +333 -0
  130. package/plugins/theme/prose.css +284 -0
  131. package/plugins/theme/scheme.js +63 -0
  132. package/plugins/theme/toggle.css +44 -0
  133. package/plugins/theme/view-transition.css +68 -0
  134. package/plugins/toc/client.ts +146 -0
  135. package/plugins/toc/index.ts +232 -0
  136. package/plugins/toc/theme.css +172 -0
  137. package/plugins/types.ts +538 -0
  138. package/problem.ts +41 -0
  139. package/project.ts +6 -0
  140. package/publish/build.ts +402 -0
  141. package/publish/concurrent.ts +32 -0
  142. package/publish/identity.ts +63 -0
  143. package/publish/index.ts +11 -0
  144. package/publish/location.ts +167 -0
  145. package/publish/model.ts +58 -0
  146. package/publish/plan.ts +300 -0
  147. package/publish/validate.ts +150 -0
  148. package/query/candidate-index.ts +101 -0
  149. package/query/dependency-index.ts +99 -0
  150. package/query/fields.ts +216 -0
  151. package/query/invalidation.ts +48 -0
  152. package/query/kernel.ts +776 -0
  153. package/query/model.ts +79 -0
  154. package/repository.ts +374 -0
  155. package/runtime-profile.ts +34 -0
  156. package/schema/model.ts +92 -0
  157. package/schema/registry.ts +642 -0
  158. package/schema/standard.ts +226 -0
  159. package/server/context.ts +94 -0
  160. package/server/css-imports.ts +66 -0
  161. package/server/http.ts +333 -0
  162. package/server/page.ts +21 -0
  163. package/server/protocols.ts +12 -0
  164. package/server/representations.ts +66 -0
  165. package/server/router.ts +131 -0
  166. package/server/routes.ts +202 -0
  167. package/server/serve.ts +5 -0
  168. package/server/watch.ts +120 -0
  169. package/source/blocks.ts +71 -0
  170. package/source/format.ts +164 -0
  171. package/source/index.ts +67 -0
  172. package/source/interpolate.ts +63 -0
  173. package/source/markdown/blocks.ts +46 -0
  174. package/source/markdown/comments.ts +32 -0
  175. package/source/markdown/fences.ts +67 -0
  176. package/source/markdown/headings.ts +88 -0
  177. package/source/markdown/index.ts +34 -0
  178. package/source/markdown/inline-code.ts +6 -0
  179. package/source/markdown/links.ts +326 -0
  180. package/source/markdown/lists.ts +223 -0
  181. package/source/markdown/prose.ts +74 -0
  182. package/source/markdown/scan.ts +79 -0
  183. package/source/markdown/text.ts +82 -0
  184. package/source/meta.ts +87 -0
  185. package/source/source.ts +121 -0
  186. package/source/topmatter.ts +57 -0
  187. package/source/utils.ts +21 -0
  188. package/source-diagnostic.ts +63 -0
  189. package/text-file.ts +26 -0
  190. package/util.ts +35 -0
  191. package/view/components.ts +499 -0
  192. package/view/model.ts +91 -0
  193. package/view/projection.ts +162 -0
  194. package/view/session.ts +146 -0
  195. package/view/syntax.ts +372 -0
package/view/model.ts ADDED
@@ -0,0 +1,91 @@
1
+ import type { ActionAffordance } from "../actions/actions.ts"
2
+ import type { Actor, Principal, UserActor } from "../authority/model.ts"
3
+ import type { ViewQuery } from "../query/model.ts"
4
+ import type { BlockType, SourceType } from "../schema/model.ts"
5
+ import type { MarkdownList, MarkdownTask } from "../source/index.ts"
6
+
7
+ export type ViewIdentity =
8
+ | Readonly<{ type: "anonymous" }>
9
+ | Readonly<{ type: "authenticated"; subject: UserActor }>
10
+ | Readonly<{ type: "inspection"; subject: Actor }>
11
+
12
+ type SourceViewMeta = Readonly<{
13
+ title: string
14
+ description?: string
15
+ image?: string
16
+ }>
17
+
18
+ type BlockViewMeta = Readonly<{
19
+ title?: string
20
+ description?: string
21
+ image?: string
22
+ }>
23
+
24
+ export type SourceView = Readonly<{
25
+ id: string
26
+ type: string
27
+ href: string
28
+ sourceType: SourceType
29
+ qualifiers: readonly string[]
30
+ data: Readonly<Record<string, unknown>>
31
+ body: string
32
+ blocks: readonly BlockView[]
33
+ meta: SourceViewMeta
34
+ }>
35
+
36
+ export type BlockView = Readonly<{
37
+ id: string
38
+ type: string
39
+ href: string
40
+ blockType: BlockType
41
+ data: Readonly<Record<string, unknown>>
42
+ body: string
43
+ lists: readonly MarkdownList[]
44
+ tasks: readonly MarkdownTask[]
45
+ meta: BlockViewMeta
46
+ }>
47
+
48
+ export type SourceSummary = Readonly<{
49
+ id: string
50
+ type: string
51
+ href: string
52
+ sourceType: SourceType
53
+ qualifiers: readonly string[]
54
+ data: Readonly<Record<string, unknown>>
55
+ meta: SourceView["meta"]
56
+ }>
57
+
58
+ export type BlockSummary = BlockView &
59
+ Readonly<{
60
+ source: SourceSummary
61
+ }>
62
+
63
+ export type SourceRelation = Readonly<{
64
+ rel: string
65
+ qualifiers: readonly string[]
66
+ type:
67
+ | "source"
68
+ | "asset"
69
+ | "external"
70
+ | "fragment"
71
+ | "actor-relative"
72
+ | "unresolved"
73
+ label?: string
74
+ target?: Readonly<{ type: "source"; id: string }>
75
+ href: string
76
+ fragment?: string
77
+ }>
78
+
79
+ export type SourceDescription = Readonly<{
80
+ source: SourceView
81
+ relations: readonly SourceRelation[]
82
+ actions: readonly ActionAffordance[]
83
+ }>
84
+
85
+ export type View = Readonly<{
86
+ identity: ViewIdentity
87
+ principal: Principal
88
+ query: ViewQuery
89
+ readSource(id: string): SourceView | undefined
90
+ describeSource(id: string): Promise<SourceDescription | undefined>
91
+ }>
@@ -0,0 +1,162 @@
1
+ import { publicPath } from "../server/router.ts"
2
+ import {
3
+ deriveBlockMeta,
4
+ deriveSourceMeta,
5
+ type Source,
6
+ type SourceBlock,
7
+ } from "../source/index.ts"
8
+ import type { ApplicationSchema, SourceType } from "../schema/model.ts"
9
+ import type {
10
+ BlockSummary,
11
+ BlockView,
12
+ SourceSummary,
13
+ SourceView,
14
+ } from "./model.ts"
15
+
16
+ const sourceViews = new WeakMap<Source, WeakMap<SourceType, SourceView>>()
17
+ const sourceSummaries = new WeakMap<
18
+ Source,
19
+ WeakMap<SourceType, SourceSummary>
20
+ >()
21
+
22
+ function immutableValue(
23
+ value: unknown,
24
+ seen = new WeakMap<object, unknown>(),
25
+ ): unknown {
26
+ if (Array.isArray(value)) {
27
+ const existing = seen.get(value)
28
+ if (existing) return existing
29
+ const projected: unknown[] = []
30
+ seen.set(value, projected)
31
+ for (const item of value) projected.push(immutableValue(item, seen))
32
+ return Object.freeze(projected)
33
+ }
34
+ if (value == null || typeof value !== "object") return value
35
+
36
+ const existing = seen.get(value)
37
+ if (existing) return existing
38
+ const projected = Object.create(null) as Record<string, unknown>
39
+ seen.set(value, projected)
40
+ for (const [key, item] of Object.entries(value)) {
41
+ projected[key] = immutableValue(item, seen)
42
+ }
43
+ return Object.freeze(projected)
44
+ }
45
+
46
+ function projectionCache<T>(
47
+ cache: WeakMap<Source, WeakMap<SourceType, T>>,
48
+ source: Source,
49
+ ) {
50
+ let projections = cache.get(source)
51
+ if (!projections) {
52
+ projections = new WeakMap()
53
+ cache.set(source, projections)
54
+ }
55
+ return projections
56
+ }
57
+
58
+ function projectMeta(derived: {
59
+ title: string
60
+ description: string
61
+ image: string
62
+ }): SourceView["meta"] {
63
+ return Object.freeze({
64
+ title: derived.title,
65
+ ...(derived.description ? { description: derived.description } : {}),
66
+ ...(derived.image ? { image: derived.image } : {}),
67
+ })
68
+ }
69
+
70
+ function projectBlockMeta(derived: {
71
+ title: string
72
+ description: string
73
+ image: string
74
+ }): BlockView["meta"] {
75
+ return Object.freeze({
76
+ ...(derived.title ? { title: derived.title } : {}),
77
+ ...(derived.description ? { description: derived.description } : {}),
78
+ ...(derived.image ? { image: derived.image } : {}),
79
+ })
80
+ }
81
+
82
+ function projectBlock(
83
+ source: Source,
84
+ block: SourceBlock,
85
+ schema: ApplicationSchema,
86
+ ): BlockView {
87
+ let meta: BlockView["meta"] | undefined
88
+ return Object.freeze({
89
+ id: block.id,
90
+ type: block.type,
91
+ href: `${publicPath(source)}#${encodeURIComponent(block.id)}`,
92
+ blockType: schema.blockType(block),
93
+ data: immutableValue(block.data) as Readonly<Record<string, unknown>>,
94
+ body: block.body,
95
+ /** Preserve lazy indexing while exposing only immutable list data. */
96
+ get lists() {
97
+ return block.lists
98
+ },
99
+ /** Tasks and lists share the canonical Block's lazy structural parse. */
100
+ get tasks() {
101
+ return block.tasks
102
+ },
103
+ /** Derive Block metadata only for consumers that request it. */
104
+ get meta() {
105
+ return (meta ??= projectBlockMeta(deriveBlockMeta(block, source)))
106
+ },
107
+ })
108
+ }
109
+
110
+ /** @internal Project one canonical Source for query and View consumers. */
111
+ export function projectSourceSummary(
112
+ source: Source,
113
+ schema: ApplicationSchema,
114
+ ) {
115
+ const sourceType = schema.sourceType(source)
116
+ const cache = projectionCache(sourceSummaries, source)
117
+ const cached = cache.get(sourceType)
118
+ if (cached) return cached
119
+ const summary: SourceSummary = Object.freeze({
120
+ id: source.id,
121
+ type: source.type,
122
+ href: publicPath(source),
123
+ sourceType,
124
+ qualifiers: Object.freeze([...source.qualifiers]),
125
+ data: immutableValue(source.data) as Readonly<Record<string, unknown>>,
126
+ meta: projectMeta(deriveSourceMeta(source)),
127
+ })
128
+ cache.set(sourceType, summary)
129
+ return summary
130
+ }
131
+
132
+ /** @internal Project one canonical Block with its containing Source context. */
133
+ export function projectBlockSummary(
134
+ source: Source,
135
+ block: SourceBlock,
136
+ schema: ApplicationSchema,
137
+ ): BlockSummary {
138
+ return Object.freeze({
139
+ ...projectBlock(source, block, schema),
140
+ source: projectSourceSummary(source, schema),
141
+ })
142
+ }
143
+
144
+ /** @internal Project one complete canonical Source for a View. */
145
+ export function projectSource(source: Source, schema: ApplicationSchema) {
146
+ const sourceType = schema.sourceType(source)
147
+ const cache = projectionCache(sourceViews, source)
148
+ const cached = cache.get(sourceType)
149
+ if (cached) return cached
150
+
151
+ const summary = projectSourceSummary(source, schema)
152
+ const projected: SourceView = Object.freeze({
153
+ ...summary,
154
+ data: immutableValue(source.data) as Readonly<Record<string, unknown>>,
155
+ body: source.body,
156
+ blocks: Object.freeze(
157
+ source.blocks.map((block) => projectBlock(source, block, schema)),
158
+ ),
159
+ })
160
+ cache.set(sourceType, projected)
161
+ return projected
162
+ }
@@ -0,0 +1,146 @@
1
+ import type { Engine } from "../host/engine.ts"
2
+ import { canonicalPath } from "../canonical.ts"
3
+ import type { Source } from "../source/index.ts"
4
+ import type { Actor, CredentialSession, Principal } from "../authority/model.ts"
5
+ import { principalFor } from "../authority/model.ts"
6
+ import type { View, ViewIdentity } from "./model.ts"
7
+ import type { ViewQuery } from "../query/model.ts"
8
+ import { projectSource } from "./projection.ts"
9
+
10
+ function identityFor(session: CredentialSession): ViewIdentity {
11
+ return session.type === "authenticated"
12
+ ? Object.freeze({ type: "authenticated", subject: session.actor })
13
+ : Object.freeze({ type: "anonymous" })
14
+ }
15
+
16
+ function within(id: string, root: string) {
17
+ return root === "/" || id === root || id.startsWith(`${root}/`)
18
+ }
19
+
20
+ function actorRelativeSource(
21
+ engine: Engine,
22
+ principal: Principal,
23
+ href: string,
24
+ ) {
25
+ if (principal.type !== "actor" || !href.startsWith("~/")) return
26
+ const pathname = href.slice(2).split(/[?#]/, 1)[0]
27
+ if (!pathname) return
28
+ const candidate = engine.environment.path.join(principal.actor.home, pathname)
29
+ try {
30
+ canonicalPath(candidate)
31
+ } catch {
32
+ return
33
+ }
34
+ if (!within(candidate, principal.actor.home)) return
35
+ return (
36
+ engine.repo.get(candidate) ??
37
+ engine.repo.atPath(candidate) ??
38
+ engine.resolve(candidate)
39
+ )
40
+ }
41
+
42
+ class EngineView implements View {
43
+ readonly #engine: Engine
44
+ readonly identity: ViewIdentity
45
+ readonly principal: Principal
46
+ readonly query: ViewQuery
47
+
48
+ constructor(engine: Engine, identity: ViewIdentity, principal: Principal) {
49
+ this.#engine = engine
50
+ this.identity = identity
51
+ this.principal = principal
52
+ this.query = engine.queries.viewQuery(this)
53
+ Object.freeze(this)
54
+ }
55
+
56
+ readSource(id: string) {
57
+ const source = this.readableSource(id)
58
+ if (!source) return
59
+ return projectSource(source, this.#engine.schema)
60
+ }
61
+
62
+ async describeSource(id: string) {
63
+ const source = this.readableSource(id)
64
+ if (!source) return
65
+ const actions = await this.#engine.actionAffordances(this.principal, source)
66
+ return Object.freeze({
67
+ source: projectSource(source, this.#engine.schema),
68
+ relations: Object.freeze(this.relationsFrom(source)),
69
+ actions,
70
+ })
71
+ }
72
+
73
+ private readableSource(id: string) {
74
+ const source = this.#engine.repo.get(id)
75
+ return source &&
76
+ this.#engine.readAccess(this.principal, source) !== "denied"
77
+ ? source
78
+ : undefined
79
+ }
80
+
81
+ private relationsFrom(source: Source) {
82
+ return this.#engine.graph.linksFrom(source.path).map((edge) => {
83
+ const common = {
84
+ rel: edge.directive?.name ?? "link",
85
+ qualifiers: Object.freeze([...(edge.directive?.qualifiers ?? [])]),
86
+ href: edge.href,
87
+ ...(edge.label ? { label: edge.label } : {}),
88
+ ...(edge.fragment ? { fragment: edge.fragment } : {}),
89
+ }
90
+ if (edge.type === "source" && edge.to) {
91
+ const target = this.#engine.repo.atPath(edge.to)
92
+ if (
93
+ target &&
94
+ this.#engine.readAccess(this.principal, target) !== "denied"
95
+ ) {
96
+ return Object.freeze({
97
+ ...common,
98
+ type: "source" as const,
99
+ target: Object.freeze({ type: "source" as const, id: target.id }),
100
+ })
101
+ }
102
+ return Object.freeze({
103
+ ...common,
104
+ type: "unresolved" as const,
105
+ })
106
+ }
107
+ if (edge.type === "actor-relative") {
108
+ const target = actorRelativeSource(
109
+ this.#engine,
110
+ this.principal,
111
+ edge.href,
112
+ )
113
+ if (
114
+ target &&
115
+ this.#engine.readAccess(this.principal, target) !== "denied"
116
+ ) {
117
+ return Object.freeze({
118
+ ...common,
119
+ type: "source" as const,
120
+ target: Object.freeze({ type: "source" as const, id: target.id }),
121
+ })
122
+ }
123
+ }
124
+ return Object.freeze({
125
+ ...common,
126
+ type: edge.type,
127
+ })
128
+ })
129
+ }
130
+ }
131
+
132
+ /** @internal Construct only from a CredentialSession admitted by a host. */
133
+ export function createView(engine: Engine, session: CredentialSession): View {
134
+ return new EngineView(engine, identityFor(session), principalFor(session))
135
+ }
136
+
137
+ /** @internal Create a trusted local inspection View without a credential session. */
138
+ export function createInspectionView(engine: Engine, actor?: Actor): View {
139
+ return new EngineView(
140
+ engine,
141
+ actor
142
+ ? Object.freeze({ type: "inspection", subject: actor })
143
+ : Object.freeze({ type: "anonymous" }),
144
+ actor ? Object.freeze({ type: "actor", actor }) : { type: "anonymous" },
145
+ )
146
+ }