@fractary/core 0.3.2 → 0.4.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/dist/__tests__/factories.test.d.ts +5 -0
- package/dist/__tests__/factories.test.d.ts.map +1 -0
- package/dist/__tests__/factories.test.js +66 -0
- package/dist/__tests__/factories.test.js.map +1 -0
- package/dist/auth/__tests__/create-token-provider.test.d.ts +5 -0
- package/dist/auth/__tests__/create-token-provider.test.d.ts.map +1 -0
- package/dist/auth/__tests__/create-token-provider.test.js +104 -0
- package/dist/auth/__tests__/create-token-provider.test.js.map +1 -0
- package/dist/auth/__tests__/github-app-auth.test.d.ts +5 -0
- package/dist/auth/__tests__/github-app-auth.test.d.ts.map +1 -0
- package/dist/auth/__tests__/github-app-auth.test.js +293 -0
- package/dist/auth/__tests__/github-app-auth.test.js.map +1 -0
- package/dist/auth/__tests__/static-token-provider.test.d.ts +5 -0
- package/dist/auth/__tests__/static-token-provider.test.d.ts.map +1 -0
- package/dist/auth/__tests__/static-token-provider.test.js +54 -0
- package/dist/auth/__tests__/static-token-provider.test.js.map +1 -0
- package/dist/auth/github-app-auth.d.ts +109 -0
- package/dist/auth/github-app-auth.d.ts.map +1 -0
- package/dist/auth/github-app-auth.js +262 -0
- package/dist/auth/github-app-auth.js.map +1 -0
- package/dist/auth/github-app-token-provider.d.ts +59 -0
- package/dist/auth/github-app-token-provider.d.ts.map +1 -0
- package/dist/auth/github-app-token-provider.js +68 -0
- package/dist/auth/github-app-token-provider.js.map +1 -0
- package/dist/auth/index.d.ts +45 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +74 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/static-token-provider.d.ts +35 -0
- package/dist/auth/static-token-provider.d.ts.map +1 -0
- package/dist/auth/static-token-provider.js +45 -0
- package/dist/auth/static-token-provider.js.map +1 -0
- package/dist/auth/types.d.ts +49 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +8 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/common/yaml-config.d.ts +10 -0
- package/dist/common/yaml-config.d.ts.map +1 -1
- package/dist/common/yaml-config.js.map +1 -1
- package/dist/config/__tests__/loader.test.d.ts +5 -0
- package/dist/config/__tests__/loader.test.d.ts.map +1 -0
- package/dist/config/__tests__/loader.test.js +129 -0
- package/dist/config/__tests__/loader.test.js.map +1 -0
- package/dist/config/index.d.ts +8 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +27 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +126 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +277 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/docs/index.d.ts +5 -0
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +6 -1
- package/dist/docs/index.js.map +1 -1
- package/dist/docs/manager.d.ts +27 -0
- package/dist/docs/manager.d.ts.map +1 -1
- package/dist/docs/manager.js +168 -15
- package/dist/docs/manager.js.map +1 -1
- package/dist/docs/type-registry.d.ts +123 -0
- package/dist/docs/type-registry.d.ts.map +1 -0
- package/dist/docs/type-registry.js +393 -0
- package/dist/docs/type-registry.js.map +1 -0
- package/dist/docs/types.d.ts +93 -0
- package/dist/docs/types.d.ts.map +1 -1
- package/dist/factories.d.ts +89 -0
- package/dist/factories.d.ts.map +1 -0
- package/dist/factories.js +228 -0
- package/dist/factories.js.map +1 -0
- package/dist/file/factory.d.ts +41 -0
- package/dist/file/factory.d.ts.map +1 -0
- package/dist/file/factory.js +237 -0
- package/dist/file/factory.js.map +1 -0
- package/dist/file/gcs.d.ts +66 -0
- package/dist/file/gcs.d.ts.map +1 -0
- package/dist/file/gcs.js +226 -0
- package/dist/file/gcs.js.map +1 -0
- package/dist/file/gdrive.d.ts +78 -0
- package/dist/file/gdrive.d.ts.map +1 -0
- package/dist/file/gdrive.js +302 -0
- package/dist/file/gdrive.js.map +1 -0
- package/dist/file/index.d.ts +13 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +25 -1
- package/dist/file/index.js.map +1 -1
- package/dist/file/manager.d.ts +83 -2
- package/dist/file/manager.d.ts.map +1 -1
- package/dist/file/manager.js +125 -4
- package/dist/file/manager.js.map +1 -1
- package/dist/file/r2.d.ts +56 -0
- package/dist/file/r2.d.ts.map +1 -0
- package/dist/file/r2.js +96 -0
- package/dist/file/r2.js.map +1 -0
- package/dist/file/s3.d.ts +61 -0
- package/dist/file/s3.d.ts.map +1 -0
- package/dist/file/s3.js +258 -0
- package/dist/file/s3.js.map +1 -0
- package/dist/file/types.d.ts +145 -2
- package/dist/file/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/logs/index.d.ts +1 -0
- package/dist/logs/index.d.ts.map +1 -1
- package/dist/logs/index.js +3 -1
- package/dist/logs/index.js.map +1 -1
- package/dist/logs/manager.d.ts +29 -2
- package/dist/logs/manager.d.ts.map +1 -1
- package/dist/logs/manager.js +48 -7
- package/dist/logs/manager.js.map +1 -1
- package/dist/logs/type-registry.d.ts +180 -0
- package/dist/logs/type-registry.d.ts.map +1 -0
- package/dist/logs/type-registry.js +421 -0
- package/dist/logs/type-registry.js.map +1 -0
- package/dist/logs/type-registry.test.d.ts +5 -0
- package/dist/logs/type-registry.test.d.ts.map +1 -0
- package/dist/logs/type-registry.test.js +671 -0
- package/dist/logs/type-registry.test.js.map +1 -0
- package/dist/logs/types.d.ts +2 -0
- package/dist/logs/types.d.ts.map +1 -1
- package/package.json +62 -8
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @fractary/core - Unified Configuration Loader
|
|
4
|
+
*
|
|
5
|
+
* Builds on yaml-config.ts to provide a unified configuration object
|
|
6
|
+
* with integrated authentication support.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.loadEnv = loadEnv;
|
|
43
|
+
exports.isEnvLoaded = isEnvLoaded;
|
|
44
|
+
exports.loadConfig = loadConfig;
|
|
45
|
+
exports.loadConfigSync = loadConfigSync;
|
|
46
|
+
const dotenv = __importStar(require("dotenv"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const fs = __importStar(require("fs"));
|
|
49
|
+
const yaml_config_1 = require("../common/yaml-config");
|
|
50
|
+
const auth_1 = require("../auth");
|
|
51
|
+
const yaml_config_2 = require("../common/yaml-config");
|
|
52
|
+
/** Track whether loadEnv has been called */
|
|
53
|
+
let envLoaded = false;
|
|
54
|
+
/**
|
|
55
|
+
* Load environment variables from .env files
|
|
56
|
+
*
|
|
57
|
+
* This function explicitly loads .env files - it must be called manually
|
|
58
|
+
* rather than being a side effect of importing the module.
|
|
59
|
+
*
|
|
60
|
+
* Searches for .env files in the following order:
|
|
61
|
+
* 1. Current working directory
|
|
62
|
+
* 2. Project root (directory containing .fractary or .git)
|
|
63
|
+
*
|
|
64
|
+
* @param options Loading options
|
|
65
|
+
* @returns true if .env was loaded, false if no .env file found
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* import { loadEnv, loadConfig } from '@fractary/core';
|
|
70
|
+
*
|
|
71
|
+
* // Explicitly load .env before loading config
|
|
72
|
+
* loadEnv();
|
|
73
|
+
* const config = await loadConfig();
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function loadEnv(options = {}) {
|
|
77
|
+
const { cwd = process.cwd(), force = false } = options;
|
|
78
|
+
// Skip if already loaded (unless force is true)
|
|
79
|
+
if (envLoaded && !force) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// Try loading from current working directory first
|
|
83
|
+
const cwdEnvPath = path.join(cwd, '.env');
|
|
84
|
+
if (fs.existsSync(cwdEnvPath)) {
|
|
85
|
+
dotenv.config({ path: cwdEnvPath });
|
|
86
|
+
envLoaded = true;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
// Try loading from project root
|
|
90
|
+
try {
|
|
91
|
+
const projectRoot = (0, yaml_config_2.findProjectRoot)(cwd);
|
|
92
|
+
const rootEnvPath = path.join(projectRoot, '.env');
|
|
93
|
+
if (fs.existsSync(rootEnvPath)) {
|
|
94
|
+
dotenv.config({ path: rootEnvPath });
|
|
95
|
+
envLoaded = true;
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// findProjectRoot failed - that's okay
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if environment variables have been loaded
|
|
106
|
+
*
|
|
107
|
+
* @returns true if loadEnv() has been called successfully
|
|
108
|
+
*/
|
|
109
|
+
function isEnvLoaded() {
|
|
110
|
+
return envLoaded;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Extract GitHub configuration from yaml config
|
|
114
|
+
*
|
|
115
|
+
* Looks for GitHub configuration in:
|
|
116
|
+
* 1. work.handlers.github
|
|
117
|
+
* 2. repo.handlers.github
|
|
118
|
+
*
|
|
119
|
+
* @param config Raw yaml configuration
|
|
120
|
+
* @returns Extracted GitHub configuration or undefined
|
|
121
|
+
*/
|
|
122
|
+
function extractGitHubConfig(config) {
|
|
123
|
+
// Try work handlers first
|
|
124
|
+
const workGithub = config.work?.handlers?.github;
|
|
125
|
+
const repoGithub = config.repo?.handlers?.github;
|
|
126
|
+
// Merge configurations (work takes priority for auth, repo for project info)
|
|
127
|
+
const github = {};
|
|
128
|
+
let hasConfig = false;
|
|
129
|
+
// Extract token
|
|
130
|
+
if (workGithub?.token) {
|
|
131
|
+
github.token = workGithub.token;
|
|
132
|
+
hasConfig = true;
|
|
133
|
+
}
|
|
134
|
+
else if (repoGithub?.token) {
|
|
135
|
+
github.token = repoGithub.token;
|
|
136
|
+
hasConfig = true;
|
|
137
|
+
}
|
|
138
|
+
// Extract organization
|
|
139
|
+
if (workGithub?.organization) {
|
|
140
|
+
github.organization = workGithub.organization;
|
|
141
|
+
hasConfig = true;
|
|
142
|
+
}
|
|
143
|
+
else if (repoGithub?.organization) {
|
|
144
|
+
github.organization = repoGithub.organization;
|
|
145
|
+
hasConfig = true;
|
|
146
|
+
}
|
|
147
|
+
// Extract project (owner/repo)
|
|
148
|
+
if (workGithub?.project) {
|
|
149
|
+
github.project = workGithub.project;
|
|
150
|
+
hasConfig = true;
|
|
151
|
+
}
|
|
152
|
+
else if (repoGithub?.project) {
|
|
153
|
+
github.project = repoGithub.project;
|
|
154
|
+
hasConfig = true;
|
|
155
|
+
}
|
|
156
|
+
else if (workGithub?.owner && workGithub?.repo) {
|
|
157
|
+
github.project = `${workGithub.owner}/${workGithub.repo}`;
|
|
158
|
+
hasConfig = true;
|
|
159
|
+
}
|
|
160
|
+
else if (repoGithub?.owner && repoGithub?.repo) {
|
|
161
|
+
github.project = `${repoGithub.owner}/${repoGithub.repo}`;
|
|
162
|
+
hasConfig = true;
|
|
163
|
+
}
|
|
164
|
+
// Extract GitHub App config
|
|
165
|
+
const appConfig = workGithub?.app || repoGithub?.app;
|
|
166
|
+
if (appConfig?.id && appConfig?.installation_id) {
|
|
167
|
+
github.app = {
|
|
168
|
+
id: String(appConfig.id),
|
|
169
|
+
installation_id: String(appConfig.installation_id),
|
|
170
|
+
private_key_path: appConfig.private_key_path,
|
|
171
|
+
private_key_env_var: appConfig.private_key_env_var,
|
|
172
|
+
};
|
|
173
|
+
hasConfig = true;
|
|
174
|
+
}
|
|
175
|
+
return hasConfig ? github : undefined;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Load unified configuration with authentication
|
|
179
|
+
*
|
|
180
|
+
* This function:
|
|
181
|
+
* 1. Loads and parses the YAML configuration
|
|
182
|
+
* 2. Extracts GitHub configuration from handlers
|
|
183
|
+
* 3. Creates a TokenProvider for authentication (if configured)
|
|
184
|
+
* 4. Returns a unified config object
|
|
185
|
+
*
|
|
186
|
+
* Note: dotenv should be imported at the entry point, so environment
|
|
187
|
+
* variables are already loaded when this function is called.
|
|
188
|
+
*
|
|
189
|
+
* @param options Configuration loading options
|
|
190
|
+
* @returns Loaded configuration with authentication
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const config = await loadConfig();
|
|
195
|
+
*
|
|
196
|
+
* if (config.tokenProvider) {
|
|
197
|
+
* const token = await config.tokenProvider.getToken();
|
|
198
|
+
* // Use token for API calls
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async function loadConfig(options = {}) {
|
|
203
|
+
const { skipAuth = false, ...yamlOptions } = options;
|
|
204
|
+
// Load raw YAML configuration
|
|
205
|
+
const raw = (0, yaml_config_1.loadYamlConfig)(yamlOptions);
|
|
206
|
+
// Handle case where config file doesn't exist
|
|
207
|
+
if (!raw) {
|
|
208
|
+
return {
|
|
209
|
+
version: '0.0.0',
|
|
210
|
+
raw: { version: '0.0.0' },
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
// Extract GitHub configuration
|
|
214
|
+
const github = extractGitHubConfig(raw);
|
|
215
|
+
// Create token provider (unless skipped)
|
|
216
|
+
let tokenProvider;
|
|
217
|
+
if (!skipAuth && github) {
|
|
218
|
+
try {
|
|
219
|
+
const githubConfig = {
|
|
220
|
+
token: github.token,
|
|
221
|
+
organization: github.organization,
|
|
222
|
+
project: github.project,
|
|
223
|
+
app: github.app,
|
|
224
|
+
};
|
|
225
|
+
tokenProvider = (0, auth_1.createTokenProvider)(githubConfig);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Token provider creation failed - that's okay, it's optional
|
|
229
|
+
// The user might not have configured authentication yet
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
version: raw.version || '0.0.0',
|
|
234
|
+
github,
|
|
235
|
+
tokenProvider,
|
|
236
|
+
work: raw.work,
|
|
237
|
+
repo: raw.repo,
|
|
238
|
+
logs: raw.logs,
|
|
239
|
+
file: raw.file,
|
|
240
|
+
spec: raw.spec,
|
|
241
|
+
docs: raw.docs,
|
|
242
|
+
codex: raw.codex,
|
|
243
|
+
raw,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Load configuration synchronously (without token provider)
|
|
248
|
+
*
|
|
249
|
+
* Useful for cases where you only need the configuration data
|
|
250
|
+
* without authentication.
|
|
251
|
+
*
|
|
252
|
+
* @param options Configuration loading options
|
|
253
|
+
* @returns Loaded configuration without token provider
|
|
254
|
+
*/
|
|
255
|
+
function loadConfigSync(options = {}) {
|
|
256
|
+
const raw = (0, yaml_config_1.loadYamlConfig)(options);
|
|
257
|
+
if (!raw) {
|
|
258
|
+
return {
|
|
259
|
+
version: '0.0.0',
|
|
260
|
+
raw: { version: '0.0.0' },
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const github = extractGitHubConfig(raw);
|
|
264
|
+
return {
|
|
265
|
+
version: raw.version || '0.0.0',
|
|
266
|
+
github,
|
|
267
|
+
work: raw.work,
|
|
268
|
+
repo: raw.repo,
|
|
269
|
+
logs: raw.logs,
|
|
270
|
+
file: raw.file,
|
|
271
|
+
spec: raw.spec,
|
|
272
|
+
docs: raw.docs,
|
|
273
|
+
codex: raw.codex,
|
|
274
|
+
raw,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/docs/index.d.ts
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* @fractary/core - Docs Module
|
|
3
3
|
*
|
|
4
4
|
* Documentation management and organization.
|
|
5
|
+
*
|
|
6
|
+
* Doc types are now stored as YAML/Markdown files in the doc-types/ directory
|
|
7
|
+
* at the repository root. Use DocTypeRegistry to load and access them.
|
|
5
8
|
*/
|
|
6
9
|
export { DocsManager } from './manager';
|
|
10
|
+
export { DocTypeRegistry } from './type-registry';
|
|
11
|
+
export type { CustomDocTypeConfig, DocTypeRegistryConfig } from './type-registry';
|
|
7
12
|
export * from './types';
|
|
8
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/docs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAClF,cAAc,SAAS,CAAC"}
|
package/dist/docs/index.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* @fractary/core - Docs Module
|
|
4
4
|
*
|
|
5
5
|
* Documentation management and organization.
|
|
6
|
+
*
|
|
7
|
+
* Doc types are now stored as YAML/Markdown files in the doc-types/ directory
|
|
8
|
+
* at the repository root. Use DocTypeRegistry to load and access them.
|
|
6
9
|
*/
|
|
7
10
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
11
|
if (k2 === undefined) k2 = k;
|
|
@@ -19,8 +22,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
19
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
23
|
};
|
|
21
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.DocsManager = void 0;
|
|
25
|
+
exports.DocTypeRegistry = exports.DocsManager = void 0;
|
|
23
26
|
var manager_1 = require("./manager");
|
|
24
27
|
Object.defineProperty(exports, "DocsManager", { enumerable: true, get: function () { return manager_1.DocsManager; } });
|
|
28
|
+
var type_registry_1 = require("./type-registry");
|
|
29
|
+
Object.defineProperty(exports, "DocTypeRegistry", { enumerable: true, get: function () { return type_registry_1.DocTypeRegistry; } });
|
|
25
30
|
__exportStar(require("./types"), exports);
|
|
26
31
|
//# sourceMappingURL=index.js.map
|
package/dist/docs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/docs/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;AAEH,qCAAwC;AAA/B,sGAAA,WAAW,OAAA;AACpB,iDAAkD;AAAzC,gHAAA,eAAe,OAAA;AAExB,0CAAwB"}
|
package/dist/docs/manager.d.ts
CHANGED
|
@@ -10,25 +10,52 @@ import { Doc, DocFormat, DocMetadata, DocSearchQuery, DocsManagerConfig } from '
|
|
|
10
10
|
export declare class DocsManager {
|
|
11
11
|
private docsDir;
|
|
12
12
|
private defaultFormat;
|
|
13
|
+
private metadataMode;
|
|
13
14
|
constructor(config: DocsManagerConfig);
|
|
14
15
|
private ensureDir;
|
|
15
16
|
private getDocPath;
|
|
16
17
|
private getMetadataPath;
|
|
17
18
|
private getFileExtension;
|
|
19
|
+
/**
|
|
20
|
+
* Determine the effective metadata mode for a document format
|
|
21
|
+
* Frontmatter only makes sense for markdown files
|
|
22
|
+
*/
|
|
23
|
+
private getEffectiveMetadataMode;
|
|
24
|
+
/**
|
|
25
|
+
* Parse frontmatter from markdown content
|
|
26
|
+
*/
|
|
27
|
+
private parseFrontmatter;
|
|
28
|
+
/**
|
|
29
|
+
* Write frontmatter to markdown content
|
|
30
|
+
*/
|
|
31
|
+
private writeFrontmatter;
|
|
32
|
+
/**
|
|
33
|
+
* Extract body content from content that may have frontmatter
|
|
34
|
+
*/
|
|
35
|
+
private extractBody;
|
|
18
36
|
/**
|
|
19
37
|
* Create a new document
|
|
38
|
+
* @param id - Document identifier
|
|
39
|
+
* @param content - Document body content (without frontmatter)
|
|
40
|
+
* @param metadata - Document metadata
|
|
41
|
+
* @param format - Document format (default: markdown)
|
|
20
42
|
*/
|
|
21
43
|
createDoc(id: string, content: string, metadata: DocMetadata, format?: DocFormat): Promise<Doc>;
|
|
22
44
|
/**
|
|
23
45
|
* Get a document by ID
|
|
46
|
+
* Supports both frontmatter and sidecar metadata modes
|
|
24
47
|
*/
|
|
25
48
|
getDoc(id: string): Promise<Doc | null>;
|
|
26
49
|
/**
|
|
27
50
|
* Update a document
|
|
51
|
+
* @param id - Document identifier
|
|
52
|
+
* @param content - New body content (without frontmatter)
|
|
53
|
+
* @param metadata - Metadata fields to update (merged with existing)
|
|
28
54
|
*/
|
|
29
55
|
updateDoc(id: string, content: string, metadata?: Partial<DocMetadata>): Promise<Doc | null>;
|
|
30
56
|
/**
|
|
31
57
|
* Delete a document
|
|
58
|
+
* Removes both the document file and any sidecar metadata file if it exists
|
|
32
59
|
*/
|
|
33
60
|
deleteDoc(id: string): Promise<boolean>;
|
|
34
61
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/docs/manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,GAAG,EACH,SAAS,EACT,WAAW,EACX,cAAc,EACd,iBAAiB,
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/docs/manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EACL,GAAG,EACH,SAAS,EACT,WAAW,EACX,cAAc,EACd,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAUjB;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,YAAY,CAAe;gBAEvB,MAAM,EAAE,iBAAiB;IAOrC,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,gBAAgB;IAUxB;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAOhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;;;;;OAMG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,WAAW,EACrB,MAAM,CAAC,EAAE,SAAS,GACjB,OAAO,CAAC,GAAG,CAAC;IAmCf;;;OAGG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAwC7C;;;;;OAKG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC9B,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IAsCtB;;;OAGG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqB7C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IA4BhC;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IA2DvD;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI9C"}
|
package/dist/docs/manager.js
CHANGED
|
@@ -48,9 +48,11 @@ const yaml = __importStar(require("js-yaml"));
|
|
|
48
48
|
class DocsManager {
|
|
49
49
|
docsDir;
|
|
50
50
|
defaultFormat;
|
|
51
|
+
metadataMode;
|
|
51
52
|
constructor(config) {
|
|
52
53
|
this.docsDir = config.docsDir;
|
|
53
54
|
this.defaultFormat = config.defaultFormat || 'markdown';
|
|
55
|
+
this.metadataMode = config.metadataMode || 'frontmatter';
|
|
54
56
|
this.ensureDir(this.docsDir);
|
|
55
57
|
}
|
|
56
58
|
ensureDir(dirPath) {
|
|
@@ -74,26 +76,144 @@ class DocsManager {
|
|
|
74
76
|
};
|
|
75
77
|
return extensions[format];
|
|
76
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Determine the effective metadata mode for a document format
|
|
81
|
+
* Frontmatter only makes sense for markdown files
|
|
82
|
+
*/
|
|
83
|
+
getEffectiveMetadataMode(format) {
|
|
84
|
+
if (format !== 'markdown') {
|
|
85
|
+
return 'sidecar';
|
|
86
|
+
}
|
|
87
|
+
return this.metadataMode;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse frontmatter from markdown content
|
|
91
|
+
*/
|
|
92
|
+
parseFrontmatter(content) {
|
|
93
|
+
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
|
|
94
|
+
const match = content.match(frontmatterRegex);
|
|
95
|
+
if (!match) {
|
|
96
|
+
// No frontmatter found, return content as-is with minimal metadata
|
|
97
|
+
return {
|
|
98
|
+
metadata: { title: '' },
|
|
99
|
+
body: content,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const frontmatterContent = match[1];
|
|
103
|
+
const body = match[2];
|
|
104
|
+
let metadata;
|
|
105
|
+
try {
|
|
106
|
+
const parsed = yaml.load(frontmatterContent);
|
|
107
|
+
metadata = {
|
|
108
|
+
title: parsed.title || '',
|
|
109
|
+
description: parsed.description,
|
|
110
|
+
authors: parsed.authors,
|
|
111
|
+
tags: parsed.tags,
|
|
112
|
+
docType: parsed.docType,
|
|
113
|
+
status: parsed.status,
|
|
114
|
+
version: parsed.version,
|
|
115
|
+
};
|
|
116
|
+
// Parse dates
|
|
117
|
+
if (parsed.createdAt) {
|
|
118
|
+
metadata.createdAt = new Date(parsed.createdAt);
|
|
119
|
+
}
|
|
120
|
+
if (parsed.updatedAt) {
|
|
121
|
+
metadata.updatedAt = new Date(parsed.updatedAt);
|
|
122
|
+
}
|
|
123
|
+
// Copy any additional fields
|
|
124
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
125
|
+
if (!(key in metadata)) {
|
|
126
|
+
metadata[key] = value;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
metadata = { title: '' };
|
|
132
|
+
}
|
|
133
|
+
return { metadata, body };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Write frontmatter to markdown content
|
|
137
|
+
*/
|
|
138
|
+
writeFrontmatter(metadata, body) {
|
|
139
|
+
// Prepare metadata object for YAML serialization
|
|
140
|
+
const yamlMetadata = {};
|
|
141
|
+
// Add standard fields
|
|
142
|
+
if (metadata.title)
|
|
143
|
+
yamlMetadata.title = metadata.title;
|
|
144
|
+
if (metadata.description)
|
|
145
|
+
yamlMetadata.description = metadata.description;
|
|
146
|
+
if (metadata.authors && metadata.authors.length > 0)
|
|
147
|
+
yamlMetadata.authors = metadata.authors;
|
|
148
|
+
if (metadata.tags && metadata.tags.length > 0)
|
|
149
|
+
yamlMetadata.tags = metadata.tags;
|
|
150
|
+
if (metadata.docType)
|
|
151
|
+
yamlMetadata.docType = metadata.docType;
|
|
152
|
+
if (metadata.status)
|
|
153
|
+
yamlMetadata.status = metadata.status;
|
|
154
|
+
if (metadata.version)
|
|
155
|
+
yamlMetadata.version = metadata.version;
|
|
156
|
+
// Add dates
|
|
157
|
+
if (metadata.createdAt) {
|
|
158
|
+
yamlMetadata.createdAt = metadata.createdAt instanceof Date
|
|
159
|
+
? metadata.createdAt.toISOString()
|
|
160
|
+
: metadata.createdAt;
|
|
161
|
+
}
|
|
162
|
+
if (metadata.updatedAt) {
|
|
163
|
+
yamlMetadata.updatedAt = metadata.updatedAt instanceof Date
|
|
164
|
+
? metadata.updatedAt.toISOString()
|
|
165
|
+
: metadata.updatedAt;
|
|
166
|
+
}
|
|
167
|
+
// Add any additional custom fields
|
|
168
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
169
|
+
if (value !== undefined &&
|
|
170
|
+
!['title', 'description', 'authors', 'tags', 'docType', 'status', 'version', 'createdAt', 'updatedAt'].includes(key)) {
|
|
171
|
+
yamlMetadata[key] = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const frontmatter = yaml.dump(yamlMetadata, { lineWidth: -1 });
|
|
175
|
+
return `---\n${frontmatter}---\n\n${body}`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Extract body content from content that may have frontmatter
|
|
179
|
+
*/
|
|
180
|
+
extractBody(content) {
|
|
181
|
+
const result = this.parseFrontmatter(content);
|
|
182
|
+
return result.body;
|
|
183
|
+
}
|
|
77
184
|
/**
|
|
78
185
|
* Create a new document
|
|
186
|
+
* @param id - Document identifier
|
|
187
|
+
* @param content - Document body content (without frontmatter)
|
|
188
|
+
* @param metadata - Document metadata
|
|
189
|
+
* @param format - Document format (default: markdown)
|
|
79
190
|
*/
|
|
80
191
|
async createDoc(id, content, metadata, format) {
|
|
81
192
|
const docFormat = format || this.defaultFormat;
|
|
82
193
|
const docPath = this.getDocPath(id, docFormat);
|
|
83
|
-
const
|
|
194
|
+
const effectiveMode = this.getEffectiveMetadataMode(docFormat);
|
|
84
195
|
// Add timestamps
|
|
85
196
|
const fullMetadata = {
|
|
86
197
|
...metadata,
|
|
87
198
|
createdAt: metadata.createdAt || new Date(),
|
|
88
199
|
updatedAt: new Date(),
|
|
89
200
|
};
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
201
|
+
// Extract body content in case content already has frontmatter
|
|
202
|
+
const bodyContent = this.extractBody(content);
|
|
203
|
+
if (effectiveMode === 'frontmatter') {
|
|
204
|
+
// Write content with embedded frontmatter
|
|
205
|
+
const fullContent = this.writeFrontmatter(fullMetadata, bodyContent);
|
|
206
|
+
fs.writeFileSync(docPath, fullContent, 'utf-8');
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Sidecar mode: separate content and metadata files
|
|
210
|
+
const metaPath = this.getMetadataPath(id);
|
|
211
|
+
fs.writeFileSync(docPath, bodyContent, 'utf-8');
|
|
212
|
+
fs.writeFileSync(metaPath, yaml.dump(fullMetadata), 'utf-8');
|
|
213
|
+
}
|
|
94
214
|
return {
|
|
95
215
|
id,
|
|
96
|
-
content,
|
|
216
|
+
content: bodyContent,
|
|
97
217
|
format: docFormat,
|
|
98
218
|
metadata: fullMetadata,
|
|
99
219
|
path: docPath,
|
|
@@ -101,6 +221,7 @@ class DocsManager {
|
|
|
101
221
|
}
|
|
102
222
|
/**
|
|
103
223
|
* Get a document by ID
|
|
224
|
+
* Supports both frontmatter and sidecar metadata modes
|
|
104
225
|
*/
|
|
105
226
|
async getDoc(id) {
|
|
106
227
|
// Try to find the doc with any format
|
|
@@ -108,12 +229,24 @@ class DocsManager {
|
|
|
108
229
|
for (const format of formats) {
|
|
109
230
|
const docPath = this.getDocPath(id, format);
|
|
110
231
|
if (fs.existsSync(docPath)) {
|
|
111
|
-
const
|
|
112
|
-
const
|
|
232
|
+
const rawContent = fs.readFileSync(docPath, 'utf-8');
|
|
233
|
+
const effectiveMode = this.getEffectiveMetadataMode(format);
|
|
113
234
|
let metadata = { title: id };
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
235
|
+
let content;
|
|
236
|
+
if (effectiveMode === 'frontmatter') {
|
|
237
|
+
// Parse frontmatter from content
|
|
238
|
+
const result = this.parseFrontmatter(rawContent);
|
|
239
|
+
metadata = result.metadata.title ? result.metadata : { ...metadata, ...result.metadata };
|
|
240
|
+
content = result.body;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
// Sidecar mode: check for .meta.yaml file
|
|
244
|
+
content = rawContent;
|
|
245
|
+
const metaPath = this.getMetadataPath(id);
|
|
246
|
+
if (fs.existsSync(metaPath)) {
|
|
247
|
+
const metaContent = fs.readFileSync(metaPath, 'utf-8');
|
|
248
|
+
metadata = yaml.load(metaContent);
|
|
249
|
+
}
|
|
117
250
|
}
|
|
118
251
|
return {
|
|
119
252
|
id,
|
|
@@ -128,6 +261,9 @@ class DocsManager {
|
|
|
128
261
|
}
|
|
129
262
|
/**
|
|
130
263
|
* Update a document
|
|
264
|
+
* @param id - Document identifier
|
|
265
|
+
* @param content - New body content (without frontmatter)
|
|
266
|
+
* @param metadata - Metadata fields to update (merged with existing)
|
|
131
267
|
*/
|
|
132
268
|
async updateDoc(id, content, metadata) {
|
|
133
269
|
const existingDoc = await this.getDoc(id);
|
|
@@ -140,12 +276,23 @@ class DocsManager {
|
|
|
140
276
|
updatedAt: new Date(),
|
|
141
277
|
};
|
|
142
278
|
const docPath = this.getDocPath(id, existingDoc.format);
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
279
|
+
const effectiveMode = this.getEffectiveMetadataMode(existingDoc.format);
|
|
280
|
+
// Extract body content in case content already has frontmatter
|
|
281
|
+
const bodyContent = this.extractBody(content);
|
|
282
|
+
if (effectiveMode === 'frontmatter') {
|
|
283
|
+
// Write content with embedded frontmatter
|
|
284
|
+
const fullContent = this.writeFrontmatter(updatedMetadata, bodyContent);
|
|
285
|
+
fs.writeFileSync(docPath, fullContent, 'utf-8');
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
// Sidecar mode: separate content and metadata files
|
|
289
|
+
const metaPath = this.getMetadataPath(id);
|
|
290
|
+
fs.writeFileSync(docPath, bodyContent, 'utf-8');
|
|
291
|
+
fs.writeFileSync(metaPath, yaml.dump(updatedMetadata), 'utf-8');
|
|
292
|
+
}
|
|
146
293
|
return {
|
|
147
294
|
id,
|
|
148
|
-
content,
|
|
295
|
+
content: bodyContent,
|
|
149
296
|
format: existingDoc.format,
|
|
150
297
|
metadata: updatedMetadata,
|
|
151
298
|
path: docPath,
|
|
@@ -153,6 +300,7 @@ class DocsManager {
|
|
|
153
300
|
}
|
|
154
301
|
/**
|
|
155
302
|
* Delete a document
|
|
303
|
+
* Removes both the document file and any sidecar metadata file if it exists
|
|
156
304
|
*/
|
|
157
305
|
async deleteDoc(id) {
|
|
158
306
|
const doc = await this.getDoc(id);
|
|
@@ -164,6 +312,7 @@ class DocsManager {
|
|
|
164
312
|
if (fs.existsSync(docPath)) {
|
|
165
313
|
fs.unlinkSync(docPath);
|
|
166
314
|
}
|
|
315
|
+
// Also delete sidecar metadata file if it exists (for backward compatibility)
|
|
167
316
|
if (fs.existsSync(metaPath)) {
|
|
168
317
|
fs.unlinkSync(metaPath);
|
|
169
318
|
}
|
|
@@ -216,6 +365,10 @@ class DocsManager {
|
|
|
216
365
|
if (query.author) {
|
|
217
366
|
results = results.filter((doc) => doc.metadata.authors?.includes(query.author));
|
|
218
367
|
}
|
|
368
|
+
// Filter by docType
|
|
369
|
+
if (query.docType) {
|
|
370
|
+
results = results.filter((doc) => doc.metadata.docType === query.docType);
|
|
371
|
+
}
|
|
219
372
|
// Filter by date range
|
|
220
373
|
if (query.dateRange) {
|
|
221
374
|
results = results.filter((doc) => {
|