@asterdoc/resolvers 0.0.0-stage → 0.10.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.
package/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Paradoc AI, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ ---
24
+
25
+ **Trademark Notice**: This license does not grant permission to use the trade names, trademarks, service marks, logos, taglines, or product names of Asterdoc, except as required for reasonable and customary use in describing the origin of the Software.
package/README.md CHANGED
@@ -1,3 +1,158 @@
1
- # Temporary Holding Version
1
+ <p align="center">
2
+ <a href="https://asterdoc.com?utm_source=github&utm_medium=resolvers" target="_blank" rel="noopener noreferrer">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://assets.asterdoc.com/asterdoc-logo-400x400-dark.png" type="image/png">
5
+ <img src="https://assets.asterdoc.com/asterdoc-logo-400x400-dark.png" height="64" alt="Asterdoc logo">
6
+ </picture>
7
+ </a>
8
+ <br />
9
+ </p>
2
10
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
11
+ <h1 align="center">@asterdoc/resolvers</h1>
12
+
13
+ <div align="center">
14
+
15
+ [![Asterdoc documentation](https://img.shields.io/badge/Documentation-Asterdoc-red.svg)](https://docs.asterdoc.com?utm_source=github&utm_medium=resolvers)
16
+ [![Follow on Twitter](https://img.shields.io/twitter/follow/asterdoc?style=social)](https://x.com/asterdoc)
17
+
18
+ </div>
19
+
20
+ [Asterdoc](https://asterdoc.com?utm_source=github&utm_medium=resolvers) is **documents as code**. It lets developers and AI agents define, validate, and render business documents using typed, composable schemas. This eliminates template drift, broken mappings, and brittle glue code — while giving AI systems a reliable document layer they can safely read, reason over, and generate against in production workflows.
21
+
22
+ ## Package overview
23
+
24
+ Environment-specific resolvers for Asterdoc. Use these to read layer files, templates, and other assets in your Asterdoc applications.
25
+
26
+ - 📂 **Filesystem resolver** - Read root-confined local files in Node.js
27
+ - 🌐 **HTTP resolver** - Read files beneath a base URL in any runtime with `fetch`
28
+ - 🧠 **Memory resolver** - Read exact-key text and bytes in any JavaScript environment
29
+ - ✅ **Type-safe** - Full TypeScript support
30
+ - 🔌 **Pluggable** - Implements the `Resolver` interface from `@asterdoc/types`
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ npm install @asterdoc/resolvers
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### Filesystem resolver
41
+
42
+ Create a resolver to read files from your filesystem:
43
+
44
+ ```typescript
45
+ import { createFsResolver } from "@asterdoc/resolvers/fs";
46
+
47
+ const resolver = createFsResolver({ root: process.cwd() });
48
+
49
+ // Read a file relative to root
50
+ const bytes = await resolver.read("/templates/form.md");
51
+ ```
52
+
53
+ Filesystem paths always resolve beneath `root`. A single leading slash means the
54
+ resolver root, not the operating-system root. Parent traversal, outward symlinks,
55
+ backslashes, drive paths, and UNC paths are rejected. Relative roots are anchored
56
+ when the resolver is created. Missing files retain native Node.js error codes;
57
+ policy failures use `ERR_RESOLVER_OUTSIDE_ROOT` or `ERR_RESOLVER_INVALID_PATH`,
58
+ and an empty or non-string `root` throws `ERR_RESOLVER_INVALID_OPTIONS`.
59
+ The root is checked on each read until it is found. A missing root rejects that
60
+ read with Node.js's native `ENOENT` error, and a root created later becomes
61
+ readable.
62
+
63
+ Artifact paths use forward slashes on every supported host, including Windows.
64
+ Containment assumes the filesystem tree is stable during a read; this resolver
65
+ is not a race-proof sandbox for a concurrently hostile filesystem.
66
+
67
+ ### HTTP resolver
68
+
69
+ Read files beneath a base URL in any runtime with the Fetch API:
70
+
71
+ ```typescript
72
+ import { createHttpResolver } from "@asterdoc/resolvers/http";
73
+
74
+ const resolver = createHttpResolver({ baseUrl: "https://example.com/forms/w-9/" });
75
+
76
+ // Fetches https://example.com/forms/w-9/templates/form.pdf
77
+ const bytes = await resolver.read("/templates/form.pdf");
78
+ ```
79
+
80
+ Paths follow the filesystem rules: forward slashes only, and a single leading
81
+ slash means the base URL, not the origin root. Each segment is percent-encoded.
82
+ A path that resolves outside the base URL rejects with
83
+ `ERR_RESOLVER_OUTSIDE_ROOT`, and one that names the base URL itself with
84
+ `ERR_RESOLVER_INVALID_PATH`, before any request. A 404 rejects with
85
+ `ERR_RESOLVER_NOT_FOUND`, and any other failed status with
86
+ `ERR_RESOLVER_FETCH_FAILED`. Pass `fetch` to add transport policy, such as
87
+ allowed hosts, redirect handling, timeouts, or body size limits. Redirects
88
+ follow the fetch function's own policy. An error thrown by a supplied
89
+ `fetch` passes through unchanged.
90
+
91
+ ### With form rendering
92
+
93
+ Bind a resolver once, when a form with file-based layers is constructed.
94
+ Every instance you derive from it afterward — every `fill`, every render —
95
+ carries the same resolver:
96
+
97
+ ```typescript
98
+ import { a } from "@asterdoc/sdk";
99
+ import { createFsResolver } from "@asterdoc/resolvers/fs";
100
+
101
+ const resolver = createFsResolver({ root: "./templates" });
102
+
103
+ const form = a.form(formSchema, { resolver });
104
+
105
+ const result = await form
106
+ .fill({
107
+ fields: {
108
+ /* ... */
109
+ },
110
+ })
111
+ .render({
112
+ layer: "pdf",
113
+ });
114
+ ```
115
+
116
+ ### Using subpath imports
117
+
118
+ Import each adapter from its environment-specific entrypoint:
119
+
120
+ ```typescript
121
+ import { createFsResolver } from "@asterdoc/resolvers/fs";
122
+ import { createHttpResolver } from "@asterdoc/resolvers/http";
123
+ import { createMemoryResolver } from "@asterdoc/resolvers/memory";
124
+ ```
125
+
126
+ ### Memory resolver for testing
127
+
128
+ For testing and browser environments, use the memory entrypoint. Keys are matched exactly, and binary content (including a Node.js `Buffer`) is copied on input and output. Missing `contents`, or a value that is not a string or `Uint8Array`, throws `ERR_RESOLVER_INVALID_OPTIONS`:
129
+
130
+ ```typescript
131
+ import { createMemoryResolver } from "@asterdoc/resolvers/memory";
132
+
133
+ const resolver = createMemoryResolver({
134
+ contents: {
135
+ "/templates/form.md": "# {{fields.title}}",
136
+ "/assets/logo.png": myLogoBytes,
137
+ },
138
+ });
139
+ ```
140
+
141
+ ## Changelog
142
+
143
+ View the [Changelog](https://github.com/asterdoc/asterdoc/blob/main/CHANGELOG.md) for updates.
144
+
145
+ ## Related packages
146
+
147
+ - [`@asterdoc/sdk`](../sdk) - Asterdoc framework SDK
148
+ - [`@asterdoc/core`](../core) - Core framework behavior
149
+
150
+ ## Contributing
151
+
152
+ We're open to all community contributions! If you'd like to contribute in any way, please read our [contribution guidelines](https://github.com/asterdoc/asterdoc/blob/main/CONTRIBUTING.md) and [code of conduct](https://github.com/asterdoc/asterdoc/blob/main/CODE_OF_CONDUCT.md).
153
+
154
+ ## License
155
+
156
+ This project is licensed under the MIT license.
157
+
158
+ See [LICENSE](https://github.com/asterdoc/asterdoc/blob/main/LICENSE) for more information.
package/dist/fs.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { Resolver } from '@asterdoc/types';
2
+
3
+ /**
4
+ * Filesystem resolver for Node.js environments.
5
+ */
6
+
7
+ /**
8
+ * Options for creating a filesystem resolver.
9
+ */
10
+ interface FsResolverOptions {
11
+ /**
12
+ * Absolute or current-working-directory-relative path to the root directory.
13
+ * Relative roots are anchored when the resolver is created.
14
+ */
15
+ root: string;
16
+ }
17
+ /**
18
+ * Create a filesystem resolver for Node.js environments.
19
+ *
20
+ * Security: The resolver validates that all resolved paths stay within the root
21
+ * directory to prevent path traversal attacks.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * import { createFsResolver } from '@asterdoc/resolvers/fs'
26
+ *
27
+ * const resolver = createFsResolver({ root: process.cwd() })
28
+ *
29
+ * // Read a file relative to root
30
+ * const bytes = await resolver.read('/templates/form.md')
31
+ * ```
32
+ */
33
+ declare function createFsResolver(options: FsResolverOptions): Resolver;
34
+
35
+ export { type FsResolverOptions, createFsResolver };
package/dist/fs.js ADDED
@@ -0,0 +1,71 @@
1
+ // src/fs/index.ts
2
+ import { readFile, realpath } from "fs/promises";
3
+ import { isAbsolute, relative, resolve, sep } from "path";
4
+
5
+ // src/shared/errors.ts
6
+ function resolverError(code, message, ErrorType = Error) {
7
+ return Object.assign(new ErrorType(message), { code });
8
+ }
9
+ function invalidOptions(message) {
10
+ return resolverError("ERR_RESOLVER_INVALID_OPTIONS", message, TypeError);
11
+ }
12
+ function invalidPath(message) {
13
+ return resolverError("ERR_RESOLVER_INVALID_PATH", message, TypeError);
14
+ }
15
+ function outsideRoot(path) {
16
+ return resolverError("ERR_RESOLVER_OUTSIDE_ROOT", `Resolver path "${path}" resolves outside the configured root`);
17
+ }
18
+
19
+ // src/shared/path.ts
20
+ function normalizeRootedPath(path) {
21
+ if (typeof path !== "string" || path.length === 0) {
22
+ throw invalidPath("Resolver path must be a non-empty string");
23
+ }
24
+ if (path.includes("\0")) {
25
+ throw invalidPath("Resolver path cannot contain a null byte");
26
+ }
27
+ if (path.includes("\\")) {
28
+ throw invalidPath("Resolver paths must use forward slashes");
29
+ }
30
+ if (/^[a-zA-Z]:/.test(path) || path.startsWith("//")) {
31
+ throw invalidPath("Resolver paths cannot use drive or UNC syntax");
32
+ }
33
+ return path.startsWith("/") ? path.slice(1) : path;
34
+ }
35
+
36
+ // src/fs/index.ts
37
+ function createFsResolver(options) {
38
+ if (!options || typeof options.root !== "string" || options.root.length === 0) {
39
+ throw invalidOptions("Resolver root must be a non-empty string");
40
+ }
41
+ const rootPath = resolve(options.root);
42
+ let canonicalRoot;
43
+ const resolveRoot = () => canonicalRoot ??= realpath(rootPath).catch((error) => {
44
+ canonicalRoot = void 0;
45
+ throw error;
46
+ });
47
+ return {
48
+ async read(path) {
49
+ const logicalPath = normalizeRootedPath(path);
50
+ const fullPath = resolve(rootPath, logicalPath);
51
+ if (!isContained(rootPath, fullPath)) {
52
+ throw outsideRoot(path);
53
+ }
54
+ const [resolvedRoot, canonicalPath] = await Promise.all([
55
+ resolveRoot(),
56
+ realpath(fullPath)
57
+ ]);
58
+ if (!isContained(resolvedRoot, canonicalPath)) {
59
+ throw outsideRoot(path);
60
+ }
61
+ return readFile(canonicalPath);
62
+ }
63
+ };
64
+ }
65
+ function isContained(root, candidate) {
66
+ const fromRoot = relative(root, candidate);
67
+ return fromRoot === "" || !isAbsolute(fromRoot) && fromRoot !== ".." && !fromRoot.startsWith(`..${sep}`);
68
+ }
69
+ export {
70
+ createFsResolver
71
+ };
package/dist/http.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { Resolver } from '@asterdoc/types';
2
+
3
+ /**
4
+ * HTTP resolver for any environment with the Fetch API.
5
+ */
6
+
7
+ /** Options for creating an HTTP resolver. */
8
+ interface HttpResolverOptions {
9
+ /**
10
+ * Absolute `http:` or `https:` URL of the root directory. Every read resolves
11
+ * beneath it. Its query and fragment are ignored.
12
+ */
13
+ baseUrl: string;
14
+ /**
15
+ * Fetch function for each read. Defaults to the global `fetch`. Supply one to
16
+ * add transport policy such as allowed hosts, timeouts, redirects, or body
17
+ * size limits.
18
+ */
19
+ fetch?: (url: string) => Promise<Response>;
20
+ }
21
+ /**
22
+ * Create a resolver that reads content over HTTP beneath a base URL.
23
+ *
24
+ * Paths follow the filesystem resolver's rules: forward slashes only, and a
25
+ * single leading slash means the base URL, not the origin root. Each path
26
+ * segment is percent-encoded, so `?`, `#`, and `%` are part of a file name.
27
+ * Paths that resolve outside the base URL reject with
28
+ * `ERR_RESOLVER_OUTSIDE_ROOT`, and a path that names the base URL itself with
29
+ * `ERR_RESOLVER_INVALID_PATH`, before any request. Redirects follow the fetch
30
+ * function's own policy. A 404 rejects with `ERR_RESOLVER_NOT_FOUND`,
31
+ * and any other non-2xx status rejects with `ERR_RESOLVER_FETCH_FAILED`.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import { createHttpResolver } from '@asterdoc/resolvers/http'
36
+ *
37
+ * const resolver = createHttpResolver({ baseUrl: 'https://example.com/forms/w-9/' })
38
+ *
39
+ * // Fetches https://example.com/forms/w-9/templates/form.pdf
40
+ * const bytes = await resolver.read('/templates/form.pdf')
41
+ * ```
42
+ */
43
+ declare function createHttpResolver(options: HttpResolverOptions): Resolver;
44
+
45
+ export { type HttpResolverOptions, createHttpResolver };
package/dist/http.js ADDED
@@ -0,0 +1,88 @@
1
+ // src/shared/errors.ts
2
+ function resolverError(code, message, ErrorType = Error) {
3
+ return Object.assign(new ErrorType(message), { code });
4
+ }
5
+ function invalidOptions(message) {
6
+ return resolverError("ERR_RESOLVER_INVALID_OPTIONS", message, TypeError);
7
+ }
8
+ function invalidPath(message) {
9
+ return resolverError("ERR_RESOLVER_INVALID_PATH", message, TypeError);
10
+ }
11
+ function outsideRoot(path) {
12
+ return resolverError("ERR_RESOLVER_OUTSIDE_ROOT", `Resolver path "${path}" resolves outside the configured root`);
13
+ }
14
+ function notFound(path) {
15
+ return resolverError("ERR_RESOLVER_NOT_FOUND", `Resolver content not found: "${path}"`);
16
+ }
17
+
18
+ // src/shared/path.ts
19
+ function normalizeRootedPath(path) {
20
+ if (typeof path !== "string" || path.length === 0) {
21
+ throw invalidPath("Resolver path must be a non-empty string");
22
+ }
23
+ if (path.includes("\0")) {
24
+ throw invalidPath("Resolver path cannot contain a null byte");
25
+ }
26
+ if (path.includes("\\")) {
27
+ throw invalidPath("Resolver paths must use forward slashes");
28
+ }
29
+ if (/^[a-zA-Z]:/.test(path) || path.startsWith("//")) {
30
+ throw invalidPath("Resolver paths cannot use drive or UNC syntax");
31
+ }
32
+ return path.startsWith("/") ? path.slice(1) : path;
33
+ }
34
+
35
+ // src/http/index.ts
36
+ function createHttpResolver(options) {
37
+ const root = parseBaseUrl(options?.baseUrl);
38
+ const fetchFn = options.fetch ?? ((url) => globalThis.fetch(url));
39
+ if (typeof fetchFn !== "function") {
40
+ throw invalidOptions("HTTP resolver fetch must be a function");
41
+ }
42
+ return {
43
+ async read(path) {
44
+ const url = resolveUrl(root, path);
45
+ const response = await fetchFn(url);
46
+ if (response.status === 404) throw notFound(path);
47
+ if (!response.ok) {
48
+ throw resolverError(
49
+ "ERR_RESOLVER_FETCH_FAILED",
50
+ `Resolver fetch failed for "${path}" with status ${response.status}`
51
+ );
52
+ }
53
+ return new Uint8Array(await response.arrayBuffer());
54
+ }
55
+ };
56
+ }
57
+ function parseBaseUrl(baseUrl) {
58
+ if (typeof baseUrl !== "string" || baseUrl.length === 0) {
59
+ throw invalidOptions("HTTP resolver baseUrl must be a non-empty string");
60
+ }
61
+ let root;
62
+ try {
63
+ root = new URL(baseUrl);
64
+ } catch {
65
+ throw invalidOptions(`HTTP resolver baseUrl must be an absolute URL: "${baseUrl}"`);
66
+ }
67
+ if (root.protocol !== "https:" && root.protocol !== "http:") {
68
+ throw invalidOptions(`HTTP resolver baseUrl must use http or https: "${baseUrl}"`);
69
+ }
70
+ root.search = "";
71
+ root.hash = "";
72
+ if (!root.pathname.endsWith("/")) root.pathname = `${root.pathname}/`;
73
+ return root;
74
+ }
75
+ function resolveUrl(root, path) {
76
+ const encoded = normalizeRootedPath(path).split("/").map((segment) => segment === "." || segment === ".." ? segment : encodeURIComponent(segment)).join("/");
77
+ const url = new URL(encoded, root);
78
+ if (url.origin !== root.origin || !url.pathname.startsWith(root.pathname)) {
79
+ throw outsideRoot(path);
80
+ }
81
+ if (url.pathname === root.pathname) {
82
+ throw invalidPath("Resolver path must name a file beneath the base URL");
83
+ }
84
+ return url.toString();
85
+ }
86
+ export {
87
+ createHttpResolver
88
+ };
@@ -0,0 +1,20 @@
1
+ import { Resolver } from '@asterdoc/types';
2
+
3
+ /** Options for creating an in-memory resolver. */
4
+ interface MemoryResolverOptions {
5
+ /** Exact resolver paths mapped to UTF-8 text or binary content. */
6
+ contents: Record<string, Uint8Array | string>;
7
+ }
8
+ /**
9
+ * Create a browser-safe resolver backed by an exact-key content map.
10
+ *
11
+ * Binary inputs, including Node.js `Buffer`s, are copied at construction and
12
+ * every read returns a fresh `Uint8Array` copy, so mutations by either the
13
+ * caller or a consumer cannot change stored content.
14
+ *
15
+ * Throws `ERR_RESOLVER_INVALID_OPTIONS` when `contents` is not an object or a
16
+ * value is neither a string nor a `Uint8Array`.
17
+ */
18
+ declare function createMemoryResolver(options: MemoryResolverOptions): Resolver;
19
+
20
+ export { type MemoryResolverOptions, createMemoryResolver };
package/dist/memory.js ADDED
@@ -0,0 +1,39 @@
1
+ // src/shared/errors.ts
2
+ function resolverError(code, message, ErrorType = Error) {
3
+ return Object.assign(new ErrorType(message), { code });
4
+ }
5
+ function invalidOptions(message) {
6
+ return resolverError("ERR_RESOLVER_INVALID_OPTIONS", message, TypeError);
7
+ }
8
+ function notFound(path) {
9
+ return resolverError("ERR_RESOLVER_NOT_FOUND", `Resolver content not found: "${path}"`);
10
+ }
11
+
12
+ // src/memory/index.ts
13
+ function createMemoryResolver(options) {
14
+ const supplied = options?.contents;
15
+ if (typeof supplied !== "object" || supplied === null || Array.isArray(supplied)) {
16
+ throw invalidOptions("Memory resolver contents must be an object of paths to strings or Uint8Arrays");
17
+ }
18
+ const encoder = new TextEncoder();
19
+ const contents = /* @__PURE__ */ new Map();
20
+ for (const [path, content] of Object.entries(supplied)) {
21
+ if (typeof content === "string") {
22
+ contents.set(path, encoder.encode(content));
23
+ } else if (content instanceof Uint8Array) {
24
+ contents.set(path, new Uint8Array(content));
25
+ } else {
26
+ throw invalidOptions(`Memory resolver content for "${path}" must be a string or Uint8Array`);
27
+ }
28
+ }
29
+ return {
30
+ async read(path) {
31
+ const content = contents.get(path);
32
+ if (content === void 0) throw notFound(path);
33
+ return new Uint8Array(content);
34
+ }
35
+ };
36
+ }
37
+ export {
38
+ createMemoryResolver
39
+ };
package/package.json CHANGED
@@ -1,6 +1,80 @@
1
1
  {
2
2
  "name": "@asterdoc/resolvers",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.10.0",
4
+ "description": "Read Asterdoc artifact content from the local filesystem, over HTTP, or from memory.",
5
+ "type": "module",
6
+ "exports": {
7
+ "./fs": {
8
+ "types": "./dist/fs.d.ts",
9
+ "import": "./dist/fs.js",
10
+ "default": "./dist/fs.js"
11
+ },
12
+ "./http": {
13
+ "types": "./dist/http.d.ts",
14
+ "import": "./dist/http.js",
15
+ "default": "./dist/http.js"
16
+ },
17
+ "./memory": {
18
+ "types": "./dist/memory.d.ts",
19
+ "import": "./dist/memory.js",
20
+ "default": "./dist/memory.js"
21
+ }
22
+ },
23
+ "sideEffects": false,
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "keywords": [
30
+ "asterdoc",
31
+ "resolvers",
32
+ "filesystem",
33
+ "http",
34
+ "storage",
35
+ "memory"
36
+ ],
37
+ "license": "MIT",
38
+ "author": {
39
+ "name": "Asterdoc",
40
+ "url": "https://asterdoc.com"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/asterdoc/asterdoc.git",
48
+ "directory": "packages/resolvers"
49
+ },
50
+ "homepage": "https://asterdoc.com",
51
+ "bugs": {
52
+ "url": "https://github.com/asterdoc/asterdoc/issues"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public"
56
+ },
57
+ "dependencies": {
58
+ "@asterdoc/types": "^0.10.0"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.15.3",
62
+ "eslint": "^9.34.0",
63
+ "tsup": "^8.4.0",
64
+ "typescript": "5.9.2",
65
+ "vitest": "^2.1.8",
66
+ "@asterdoc/eslint-config": "0.1.0",
67
+ "@asterdoc/typescript-config": "0.1.0"
68
+ },
69
+ "scripts": {
70
+ "build": "tsup",
71
+ "dev": "tsup --watch",
72
+ "clean": "rm -rf dist",
73
+ "prebuild": "pnpm run clean",
74
+ "lint": "eslint .",
75
+ "check-types": "tsc --noEmit",
76
+ "check": "pnpm lint && pnpm check-types",
77
+ "test": "vitest run",
78
+ "test:watch": "vitest"
79
+ }
6
80
  }