@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
@@ -0,0 +1,226 @@
1
+ /** The Standard Schema interface. */
2
+ export interface StandardSchemaV1<Input = unknown, Output = Input> {
3
+ /** The Standard Schema properties. */
4
+ readonly "~standard": StandardSchemaV1.Props<Input, Output>
5
+ }
6
+
7
+ export function isStandardSchema(value: unknown): value is StandardSchemaV1 {
8
+ if (
9
+ value == null ||
10
+ (typeof value !== "object" && typeof value !== "function")
11
+ ) {
12
+ return false
13
+ }
14
+ const standard = (value as { ["~standard"]?: unknown })["~standard"]
15
+ if (standard == null || typeof standard !== "object") return false
16
+ const props = standard as { version?: unknown; validate?: unknown }
17
+ return props.version === 1 && typeof props.validate === "function"
18
+ }
19
+
20
+ /** The orthogonal Standard JSON Schema v1 discovery interface. */
21
+ export interface StandardJSONSchemaV1<Input = unknown, Output = Input> {
22
+ readonly "~standard": StandardJSONSchemaV1.Props<Input, Output>
23
+ }
24
+
25
+ export declare namespace StandardJSONSchemaV1 {
26
+ export interface Props<Input = unknown, Output = Input> {
27
+ readonly version: 1
28
+ readonly vendor: string
29
+ readonly types?: Types<Input, Output> | undefined
30
+ readonly jsonSchema: Converter
31
+ }
32
+
33
+ export interface Converter {
34
+ readonly input: (options: Options) => Readonly<Record<string, unknown>>
35
+ readonly output: (options: Options) => Readonly<Record<string, unknown>>
36
+ }
37
+
38
+ export type Target =
39
+ "draft-2020-12" | "draft-07" | "openapi-3.0" | ({} & string)
40
+
41
+ export interface Options {
42
+ readonly target: Target
43
+ readonly libraryOptions?: Record<string, unknown> | undefined
44
+ }
45
+
46
+ export interface Types<Input = unknown, Output = Input> {
47
+ readonly input: Input
48
+ readonly output: Output
49
+ }
50
+
51
+ export type InferInput<Schema extends StandardJSONSchemaV1> = NonNullable<
52
+ Schema["~standard"]["types"]
53
+ >["input"]
54
+
55
+ export type InferOutput<Schema extends StandardJSONSchemaV1> = NonNullable<
56
+ Schema["~standard"]["types"]
57
+ >["output"]
58
+ }
59
+
60
+ /** PathMX data combines validation and transport-safe structural discovery. */
61
+ export type PathMXDataSchema<
62
+ Input = unknown,
63
+ Output = Input,
64
+ > = StandardSchemaV1<Input, Output> & StandardJSONSchemaV1<Input, Output>
65
+
66
+ export function isStandardJsonSchema(
67
+ value: unknown,
68
+ ): value is StandardJSONSchemaV1 {
69
+ if (
70
+ value == null ||
71
+ (typeof value !== "object" && typeof value !== "function")
72
+ ) {
73
+ return false
74
+ }
75
+ const jsonSchema = (value as Partial<StandardJSONSchemaV1>)["~standard"]
76
+ ?.jsonSchema
77
+ return (
78
+ jsonSchema != null &&
79
+ typeof jsonSchema.input === "function" &&
80
+ typeof jsonSchema.output === "function"
81
+ )
82
+ }
83
+
84
+ function isJsonSchemaObject(
85
+ value: unknown,
86
+ ): value is Readonly<Record<string, unknown>> {
87
+ return value != null && typeof value === "object" && !Array.isArray(value)
88
+ }
89
+
90
+ const requiredJsonSchemas = new WeakMap<
91
+ object,
92
+ Partial<Record<"input" | "output", Readonly<Record<string, unknown>>>>
93
+ >()
94
+
95
+ /** Convert an installed PathMX data schema or fail registration with context. */
96
+ export function requireStandardJsonSchema(
97
+ schema: unknown,
98
+ direction: "input" | "output",
99
+ subject: string,
100
+ ) {
101
+ if (!isStandardSchema(schema) || !isStandardJsonSchema(schema)) {
102
+ throw new Error(
103
+ `${subject} must implement Standard Schema and Standard JSON Schema v1.`,
104
+ )
105
+ }
106
+ const cached = requiredJsonSchemas.get(schema)?.[direction]
107
+ if (cached) return cached
108
+ let converted: unknown
109
+ try {
110
+ converted = schema["~standard"].jsonSchema[direction]({
111
+ target: "draft-2020-12",
112
+ })
113
+ } catch (error) {
114
+ const detail = error instanceof Error ? error.message : String(error)
115
+ throw new Error(`${subject} ${direction} JSON Schema failed: ${detail}`)
116
+ }
117
+ if (!isJsonSchemaObject(converted)) {
118
+ throw new Error(`${subject} ${direction} JSON Schema must be an object.`)
119
+ }
120
+ const frozen = Object.freeze(converted)
121
+ const directions = requiredJsonSchemas.get(schema) ?? {}
122
+ directions[direction] = frozen
123
+ requiredJsonSchemas.set(schema, directions)
124
+ return frozen
125
+ }
126
+
127
+ export function standardJsonSchema(
128
+ schema: StandardSchemaV1 | undefined,
129
+ direction: "input" | "output",
130
+ ) {
131
+ const converter = (schema as Partial<StandardJSONSchemaV1> | undefined)?.[
132
+ "~standard"
133
+ ]?.jsonSchema?.[direction]
134
+ if (!converter) return
135
+ try {
136
+ return Object.freeze(converter({ target: "draft-2020-12" }))
137
+ } catch {
138
+ return
139
+ }
140
+ }
141
+
142
+ export function formatSchemaIssues(
143
+ issues: ReadonlyArray<StandardSchemaV1.Issue>,
144
+ ) {
145
+ return issues
146
+ .map((issue) => {
147
+ const path = issue.path
148
+ ?.map((segment) =>
149
+ String(typeof segment === "object" ? segment.key : segment),
150
+ )
151
+ .join(".")
152
+ return path ? `${path}: ${issue.message}` : issue.message
153
+ })
154
+ .join("; ")
155
+ }
156
+
157
+ export declare namespace StandardSchemaV1 {
158
+ /** The Standard Schema properties interface. */
159
+ export interface Props<Input = unknown, Output = Input> {
160
+ /** The version number of the standard. */
161
+ readonly version: 1
162
+ /** The vendor name of the schema library. */
163
+ readonly vendor: string
164
+ /** Validates unknown input values. */
165
+ readonly validate: (
166
+ value: unknown,
167
+ options?: StandardSchemaV1.Options | undefined,
168
+ ) => Result<Output> | Promise<Result<Output>>
169
+ /** Inferred types associated with the schema. */
170
+ readonly types?: Types<Input, Output> | undefined
171
+ }
172
+
173
+ /** The result interface of the validate function. */
174
+ export type Result<Output> = SuccessResult<Output> | FailureResult
175
+
176
+ /** The result interface if validation succeeds. */
177
+ export interface SuccessResult<Output> {
178
+ /** The typed output value. */
179
+ readonly value: Output
180
+ /** A falsy value for `issues` indicates success. */
181
+ readonly issues?: undefined
182
+ }
183
+
184
+ export interface Options {
185
+ /** Explicit support for additional vendor-specific parameters, if needed. */
186
+ readonly libraryOptions?: Record<string, unknown> | undefined
187
+ }
188
+
189
+ /** The result interface if validation fails. */
190
+ export interface FailureResult {
191
+ /** The issues of failed validation. */
192
+ readonly issues: ReadonlyArray<Issue>
193
+ }
194
+
195
+ /** The issue interface of the failure output. */
196
+ export interface Issue {
197
+ /** The error message of the issue. */
198
+ readonly message: string
199
+ /** The path of the issue, if any. */
200
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined
201
+ }
202
+
203
+ /** The path segment interface of the issue. */
204
+ export interface PathSegment {
205
+ /** The key representing a path segment. */
206
+ readonly key: PropertyKey
207
+ }
208
+
209
+ /** The Standard Schema types interface. */
210
+ export interface Types<Input = unknown, Output = Input> {
211
+ /** The input type of the schema. */
212
+ readonly input: Input
213
+ /** The output type of the schema. */
214
+ readonly output: Output
215
+ }
216
+
217
+ /** Infers the input type of a Standard Schema. */
218
+ export type InferInput<Schema extends StandardSchemaV1> = NonNullable<
219
+ Schema["~standard"]["types"]
220
+ >["input"]
221
+
222
+ /** Infers the output type of a Standard Schema. */
223
+ export type InferOutput<Schema extends StandardSchemaV1> = NonNullable<
224
+ Schema["~standard"]["types"]
225
+ >["output"]
226
+ }
@@ -0,0 +1,94 @@
1
+ import { AccessDeniedError } from "../authority/access.ts"
2
+ import { createTransaction } from "../actions/transaction.ts"
3
+ import type { Engine } from "../host/engine.ts"
4
+ import type { ServerContext, ServerRenderOptions } from "../plugins/types.ts"
5
+ import type { Source } from "../source/index.ts"
6
+ import { principalFor, type CredentialSession } from "../authority/model.ts"
7
+ import type { View } from "../view/model.ts"
8
+ import { renderPage } from "../host/render.ts"
9
+ import { pageNotFound, requestScheme } from "./page.ts"
10
+
11
+ /** @internal Bind one portable handler to its owning plugin and Engine. */
12
+ export function createServerContext(
13
+ app: Engine,
14
+ plugin: string,
15
+ path: string,
16
+ request: Request,
17
+ url: URL,
18
+ ): ServerContext {
19
+ let resolvedSession: Promise<CredentialSession> | undefined
20
+ let resolvedView: Promise<View> | undefined
21
+ const session = () => (resolvedSession ??= app.resolveCredentials(request))
22
+ const view = () =>
23
+ (resolvedView ??= session().then((value) => app.view(value)))
24
+ const appContext = app.appContext(plugin)
25
+ const resolveSource = (input: Source | string) =>
26
+ typeof input === "string" ? appContext.sources.get(input) : input
27
+
28
+ return Object.freeze({
29
+ request,
30
+ url,
31
+ path,
32
+ plugin,
33
+ log: appContext.log,
34
+ runtime: appContext.runtime,
35
+ database: appContext.database,
36
+ graph: appContext.graph,
37
+ source(idOrPath) {
38
+ return appContext.sources.get(idOrPath)
39
+ },
40
+ sources() {
41
+ return appContext.sources.all()
42
+ },
43
+ resolve(pathname) {
44
+ return appContext.sources.resolve(pathname)
45
+ },
46
+ isPublic(target) {
47
+ return appContext.access.read({ type: "anonymous" }, target) === "public"
48
+ },
49
+ session,
50
+ view,
51
+ async readAccess(target) {
52
+ const credentials = await session()
53
+ return appContext.access.read(principalFor(credentials), target)
54
+ },
55
+ onSync(listener) {
56
+ return app.onSync(listener)
57
+ },
58
+ async render(input, options: ServerRenderOptions = {}) {
59
+ const source = resolveSource(input)
60
+ if (!source) return pageNotFound()
61
+ const credentials = await session()
62
+ return renderPage(app, credentials, principalFor(credentials), source, {
63
+ ...options,
64
+ scheme: requestScheme(request),
65
+ })
66
+ },
67
+ async mutate(run) {
68
+ const credentials = await session()
69
+ if (credentials.type !== "authenticated") {
70
+ throw new AccessDeniedError("authentication-required")
71
+ }
72
+ const result = await app.commitPrepared(async () => {
73
+ const transaction = createTransaction(app, credentials.actor)
74
+ await run(transaction)
75
+ return transaction.changeSet()
76
+ })
77
+ if (result.applied.length) {
78
+ app.log.info("server.mutation", {
79
+ plugin,
80
+ method: request.method,
81
+ path: url.pathname,
82
+ changes: result.applied.length,
83
+ })
84
+ }
85
+ return result
86
+ },
87
+ mutateAsAgent(admission, run) {
88
+ return app.runAgentJob(admission, run)
89
+ },
90
+ handleCredentials() {
91
+ return app.credentialRequest(request)
92
+ },
93
+ })
94
+ }
@@ -0,0 +1,66 @@
1
+ import { posix } from "node:path"
2
+
3
+ const CSS_IMPORT =
4
+ /@import\s+(?:url\(\s*(?:"([^"]+)"|'([^']+)'|([^'"\s)]+))\s*\)|"([^"]+)"|'([^']+)')/gi
5
+ const EXTERNAL = /^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i
6
+
7
+ function importedPath(importer: string, specifier: string) {
8
+ const raw = specifier.split(/[?#]/, 1)[0]
9
+ if (!raw || EXTERNAL.test(raw)) return
10
+ const path = posix.resolve(posix.dirname(importer), raw)
11
+ return path.endsWith(".css") ? path : undefined
12
+ }
13
+
14
+ function cssImports(importer: string, css: string) {
15
+ const imports = new Set<string>()
16
+ for (const match of css.matchAll(CSS_IMPORT)) {
17
+ const specifier = match.slice(1).find((value) => value !== undefined)
18
+ if (!specifier) continue
19
+ const path = importedPath(importer, specifier)
20
+ if (path) imports.add(path)
21
+ }
22
+ return imports
23
+ }
24
+
25
+ /** Internal reverse index for native authored CSS imports. */
26
+ export class CssImportIndex {
27
+ private dependencies = new Map<string, Set<string>>()
28
+ private dependents = new Map<string, Set<string>>()
29
+
30
+ replace(importer: string, css?: string) {
31
+ for (const dependency of this.dependencies.get(importer) ?? []) {
32
+ const importers = this.dependents.get(dependency)
33
+ importers?.delete(importer)
34
+ if (!importers?.size) this.dependents.delete(dependency)
35
+ }
36
+
37
+ if (css === undefined) {
38
+ this.dependencies.delete(importer)
39
+ return
40
+ }
41
+
42
+ const imports = cssImports(importer, css)
43
+ this.dependencies.set(importer, imports)
44
+ for (const dependency of imports) {
45
+ let importers = this.dependents.get(dependency)
46
+ if (!importers) {
47
+ importers = new Set()
48
+ this.dependents.set(dependency, importers)
49
+ }
50
+ importers.add(importer)
51
+ }
52
+ }
53
+
54
+ affected(path: string) {
55
+ const affected = new Set([path])
56
+ const queue = [path]
57
+ for (const dependency of queue) {
58
+ for (const importer of this.dependents.get(dependency) ?? []) {
59
+ if (affected.has(importer)) continue
60
+ affected.add(importer)
61
+ queue.push(importer)
62
+ }
63
+ }
64
+ return affected
65
+ }
66
+ }