@kb-labs/workflow-artifacts 1.1.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/README.md +214 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# @kb-labs/workflow-artifacts
|
|
2
|
+
|
|
3
|
+
Artifact helpers for KB Labs workflow engine.
|
|
4
|
+
|
|
5
|
+
## Vision & Purpose
|
|
6
|
+
|
|
7
|
+
**@kb-labs/workflow-artifacts** provides artifact helpers for the KB Labs workflow engine. It includes file system client for reading and writing workflow artifacts, artifact management, and path organization.
|
|
8
|
+
|
|
9
|
+
### Core Goals
|
|
10
|
+
|
|
11
|
+
- **File System Client**: Operations for reading and writing workflow artifacts
|
|
12
|
+
- **Artifact Management**: Helpers for artifact paths and organization
|
|
13
|
+
- **Stream Support**: Support for streaming artifacts
|
|
14
|
+
|
|
15
|
+
## Package Status
|
|
16
|
+
|
|
17
|
+
- **Version**: 0.1.0
|
|
18
|
+
- **Stage**: Stable
|
|
19
|
+
- **Status**: Production Ready ✅
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
### High-Level Overview
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Workflow Artifacts
|
|
27
|
+
│
|
|
28
|
+
├──► File System Client
|
|
29
|
+
├──► Artifact Types
|
|
30
|
+
└──► Path Management
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Key Components
|
|
34
|
+
|
|
35
|
+
1. **FileSystemArtifactClient** (`fs-client.ts`): File system-based artifact client
|
|
36
|
+
2. **Types** (`types.ts`): Artifact type definitions
|
|
37
|
+
|
|
38
|
+
## ✨ Features
|
|
39
|
+
|
|
40
|
+
- **File system client** for artifacts
|
|
41
|
+
- **Read/write operations** for artifacts
|
|
42
|
+
- **Stream support** for large artifacts
|
|
43
|
+
- **Path validation** and security
|
|
44
|
+
- **List operations** for artifact discovery
|
|
45
|
+
|
|
46
|
+
## 📦 API Reference
|
|
47
|
+
|
|
48
|
+
### Main Exports
|
|
49
|
+
|
|
50
|
+
#### Client Classes
|
|
51
|
+
|
|
52
|
+
- `FileSystemArtifactClient`: File system-based artifact client
|
|
53
|
+
- `createFileSystemArtifactClient(options)`: Factory function
|
|
54
|
+
|
|
55
|
+
#### Types & Interfaces
|
|
56
|
+
|
|
57
|
+
- `ArtifactClient`: Artifact client interface
|
|
58
|
+
- `ArtifactInput`: Artifact input types
|
|
59
|
+
- `ArtifactOutput`: Artifact output type
|
|
60
|
+
- `ArtifactReference`: Artifact reference type
|
|
61
|
+
|
|
62
|
+
### Types & Interfaces
|
|
63
|
+
|
|
64
|
+
#### `ArtifactClient`
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
interface ArtifactClient {
|
|
68
|
+
produce(path: string, input: ArtifactInput): Promise<void>;
|
|
69
|
+
consume(path: string): Promise<ArtifactOutput>;
|
|
70
|
+
list?(prefix?: string): Promise<ArtifactReference[]>;
|
|
71
|
+
basePath?: () => string;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### `ArtifactInput`
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
type ArtifactInput =
|
|
79
|
+
| string
|
|
80
|
+
| Buffer
|
|
81
|
+
| Uint8Array
|
|
82
|
+
| NodeJS.ReadableStream;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### `ArtifactReference`
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
interface ArtifactReference {
|
|
89
|
+
path: string;
|
|
90
|
+
size?: number;
|
|
91
|
+
contentType?: string;
|
|
92
|
+
modifiedAt?: Date;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 🔧 Configuration
|
|
97
|
+
|
|
98
|
+
### Configuration Options
|
|
99
|
+
|
|
100
|
+
#### FileSystemArtifactClientOptions
|
|
101
|
+
|
|
102
|
+
- **root**: Root directory for artifacts (required)
|
|
103
|
+
- **defaultContentType**: Default content type
|
|
104
|
+
|
|
105
|
+
## 🔗 Dependencies
|
|
106
|
+
|
|
107
|
+
### Runtime Dependencies
|
|
108
|
+
|
|
109
|
+
- `pathe` (`^1.1.2`): Path utilities
|
|
110
|
+
|
|
111
|
+
### Development Dependencies
|
|
112
|
+
|
|
113
|
+
- `@kb-labs/devkit` (`link:../../../kb-labs-devkit`): DevKit presets
|
|
114
|
+
- `@types/node` (`^24.3.3`): Node.js types
|
|
115
|
+
- `tsup` (`^8.5.0`): TypeScript bundler
|
|
116
|
+
- `typescript` (`^5.6.3`): TypeScript compiler
|
|
117
|
+
- `vitest` (`^3.2.4`): Test runner
|
|
118
|
+
|
|
119
|
+
## 🧪 Testing
|
|
120
|
+
|
|
121
|
+
### Test Structure
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
src/__tests__/
|
|
125
|
+
└── (tests to be added)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Test Coverage
|
|
129
|
+
|
|
130
|
+
- **Current Coverage**: ~0% (tests to be added)
|
|
131
|
+
- **Target Coverage**: 90%
|
|
132
|
+
|
|
133
|
+
## 📈 Performance
|
|
134
|
+
|
|
135
|
+
### Performance Characteristics
|
|
136
|
+
|
|
137
|
+
- **Time Complexity**: O(1) for operations, O(n) for listing
|
|
138
|
+
- **Space Complexity**: O(1)
|
|
139
|
+
- **Bottlenecks**: File I/O operations
|
|
140
|
+
|
|
141
|
+
## 🔒 Security
|
|
142
|
+
|
|
143
|
+
### Security Considerations
|
|
144
|
+
|
|
145
|
+
- **Path Validation**: Path escaping prevention
|
|
146
|
+
- **Root Directory**: Artifacts restricted to root directory
|
|
147
|
+
|
|
148
|
+
### Known Vulnerabilities
|
|
149
|
+
|
|
150
|
+
- None
|
|
151
|
+
|
|
152
|
+
## 🐛 Known Issues & Limitations
|
|
153
|
+
|
|
154
|
+
### Known Issues
|
|
155
|
+
|
|
156
|
+
- None currently
|
|
157
|
+
|
|
158
|
+
### Limitations
|
|
159
|
+
|
|
160
|
+
- **File System Only**: Only file system implementation
|
|
161
|
+
- **No Remote Storage**: No S3/remote storage support
|
|
162
|
+
|
|
163
|
+
### Future Improvements
|
|
164
|
+
|
|
165
|
+
- **Remote Storage**: S3/remote storage support
|
|
166
|
+
- **Compression**: Artifact compression support
|
|
167
|
+
|
|
168
|
+
## 🔄 Migration & Breaking Changes
|
|
169
|
+
|
|
170
|
+
### Migration from Previous Versions
|
|
171
|
+
|
|
172
|
+
No breaking changes in current version (0.1.0).
|
|
173
|
+
|
|
174
|
+
### Breaking Changes in Future Versions
|
|
175
|
+
|
|
176
|
+
- None planned
|
|
177
|
+
|
|
178
|
+
## 📚 Examples
|
|
179
|
+
|
|
180
|
+
### Example 1: Create Artifact Client
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { createFileSystemArtifactClient } from '@kb-labs/workflow-artifacts';
|
|
184
|
+
|
|
185
|
+
const client = createFileSystemArtifactClient({
|
|
186
|
+
root: '/path/to/artifacts',
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Example 2: Read Artifact
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const content = await client.consume('run-123/job-abc/artifact.txt');
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Example 3: Write Artifact
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
await client.produce('run-123/job-abc/artifact.txt', 'content');
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Example 4: List Artifacts
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const artifacts = await client.list('run-123/');
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 🤝 Contributing
|
|
209
|
+
|
|
210
|
+
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
|
|
211
|
+
|
|
212
|
+
## 📄 License
|
|
213
|
+
|
|
214
|
+
MIT © KB Labs
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type ArtifactInput = string | Buffer | Uint8Array | NodeJS.ReadableStream;
|
|
2
|
+
type ArtifactOutput = Buffer;
|
|
3
|
+
interface ArtifactReference {
|
|
4
|
+
path: string;
|
|
5
|
+
size?: number;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
modifiedAt?: Date;
|
|
8
|
+
}
|
|
9
|
+
interface ArtifactClient {
|
|
10
|
+
produce(path: string, input: ArtifactInput): Promise<void>;
|
|
11
|
+
consume(path: string): Promise<ArtifactOutput>;
|
|
12
|
+
list?(prefix?: string): Promise<ArtifactReference[]>;
|
|
13
|
+
basePath?: () => string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface FileSystemArtifactClientOptions {
|
|
17
|
+
root: string;
|
|
18
|
+
defaultContentType?: string;
|
|
19
|
+
}
|
|
20
|
+
declare class FileSystemArtifactClient implements ArtifactClient {
|
|
21
|
+
private readonly options;
|
|
22
|
+
constructor(options: FileSystemArtifactClientOptions);
|
|
23
|
+
basePath(): string;
|
|
24
|
+
produce(path: string, input: ArtifactInput): Promise<void>;
|
|
25
|
+
consume(path: string): Promise<ArtifactOutput>;
|
|
26
|
+
stream(path: string): Promise<NodeJS.ReadableStream>;
|
|
27
|
+
list(prefix?: string): Promise<ArtifactReference[]>;
|
|
28
|
+
}
|
|
29
|
+
declare function createFileSystemArtifactClient(root: string): FileSystemArtifactClient;
|
|
30
|
+
|
|
31
|
+
export { type ArtifactClient, type ArtifactInput, type ArtifactOutput, type ArtifactReference, FileSystemArtifactClient, type FileSystemArtifactClientOptions, createFileSystemArtifactClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createReadStream, createWriteStream } from 'fs';
|
|
2
|
+
import { readFile, writeFile, readdir, stat, mkdir } from 'fs/promises';
|
|
3
|
+
import { pipeline } from 'stream/promises';
|
|
4
|
+
import { resolve, join, relative, dirname } from 'pathe';
|
|
5
|
+
|
|
6
|
+
// src/fs-client.ts
|
|
7
|
+
function ensureWithinRoot(root, targetPath) {
|
|
8
|
+
const normalizedRoot = root.endsWith("/") ? root : `${root}/`;
|
|
9
|
+
const target = resolve(root, targetPath);
|
|
10
|
+
if (target === normalizedRoot.slice(0, -1)) {
|
|
11
|
+
return target;
|
|
12
|
+
}
|
|
13
|
+
if (!target.startsWith(normalizedRoot)) {
|
|
14
|
+
throw new Error(`Artifact path escapes root: ${targetPath}`);
|
|
15
|
+
}
|
|
16
|
+
return target;
|
|
17
|
+
}
|
|
18
|
+
async function writeInput(destination, input) {
|
|
19
|
+
if (typeof input === "string" || input instanceof Buffer || input instanceof Uint8Array) {
|
|
20
|
+
await createParentDir(destination);
|
|
21
|
+
await writeFile(destination, input);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (input && typeof input.pipe === "function") {
|
|
25
|
+
await createParentDir(destination);
|
|
26
|
+
await pipeline(input, createWriteStream(destination));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
throw new Error("Unsupported artifact input type");
|
|
30
|
+
}
|
|
31
|
+
async function createParentDir(path) {
|
|
32
|
+
await mkdir(dirname(path), { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
async function walk(root, prefix) {
|
|
35
|
+
const base = prefix ? ensureWithinRoot(root, prefix) : root;
|
|
36
|
+
const entries = await readdir(base, { withFileTypes: true });
|
|
37
|
+
const entryPromises = entries.map(async (entry) => {
|
|
38
|
+
const absolute = join(base, entry.name);
|
|
39
|
+
const rel = relative(root, absolute);
|
|
40
|
+
if (entry.isDirectory()) {
|
|
41
|
+
return walk(root, rel);
|
|
42
|
+
} else if (entry.isFile()) {
|
|
43
|
+
const s = await stat(absolute);
|
|
44
|
+
return [{
|
|
45
|
+
path: rel,
|
|
46
|
+
size: s.size,
|
|
47
|
+
modifiedAt: s.mtime
|
|
48
|
+
}];
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
});
|
|
52
|
+
const nestedResults = await Promise.all(entryPromises);
|
|
53
|
+
return nestedResults.flat();
|
|
54
|
+
}
|
|
55
|
+
var FileSystemArtifactClient = class {
|
|
56
|
+
constructor(options) {
|
|
57
|
+
this.options = options;
|
|
58
|
+
}
|
|
59
|
+
basePath() {
|
|
60
|
+
return this.options.root;
|
|
61
|
+
}
|
|
62
|
+
async produce(path, input) {
|
|
63
|
+
const target = ensureWithinRoot(this.options.root, path);
|
|
64
|
+
await writeInput(target, input);
|
|
65
|
+
}
|
|
66
|
+
async consume(path) {
|
|
67
|
+
const target = ensureWithinRoot(this.options.root, path);
|
|
68
|
+
return readFile(target);
|
|
69
|
+
}
|
|
70
|
+
async stream(path) {
|
|
71
|
+
const target = ensureWithinRoot(this.options.root, path);
|
|
72
|
+
return createReadStream(target);
|
|
73
|
+
}
|
|
74
|
+
async list(prefix) {
|
|
75
|
+
return walk(this.options.root, prefix);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
function createFileSystemArtifactClient(root) {
|
|
79
|
+
return new FileSystemArtifactClient({ root });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { FileSystemArtifactClient, createFileSystemArtifactClient };
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fs-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { createWriteStream, createReadStream } from 'node:fs'\nimport { mkdir, stat, readdir, readFile, writeFile } from 'node:fs/promises'\nimport { pipeline } from 'node:stream/promises'\nimport { dirname, resolve, join, relative } from 'pathe'\nimport type {\n ArtifactClient,\n ArtifactInput,\n ArtifactOutput,\n ArtifactReference,\n} from './types'\n\nfunction ensureWithinRoot(root: string, targetPath: string): string {\n const normalizedRoot = root.endsWith('/') ? root : `${root}/`\n const target = resolve(root, targetPath)\n if (target === normalizedRoot.slice(0, -1)) {\n return target\n }\n if (!target.startsWith(normalizedRoot)) {\n throw new Error(`Artifact path escapes root: ${targetPath}`)\n }\n return target\n}\n\nasync function writeInput(\n destination: string,\n input: ArtifactInput,\n): Promise<void> {\n if (\n typeof input === 'string' ||\n input instanceof Buffer ||\n input instanceof Uint8Array\n ) {\n await createParentDir(destination)\n await writeFile(destination, input)\n return\n }\n\n if (input && typeof input.pipe === 'function') {\n await createParentDir(destination)\n await pipeline(input, createWriteStream(destination))\n return\n }\n\n throw new Error('Unsupported artifact input type')\n}\n\nasync function createParentDir(path: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true })\n}\n\nasync function walk(root: string, prefix?: string): Promise<ArtifactReference[]> {\n const base = prefix ? ensureWithinRoot(root, prefix) : root\n const entries = await readdir(base, { withFileTypes: true })\n\n // Process all entries in parallel\n const entryPromises = entries.map(async (entry) => {\n const absolute = join(base, entry.name)\n const rel = relative(root, absolute)\n\n if (entry.isDirectory()) {\n return walk(root, rel)\n } else if (entry.isFile()) {\n const s = await stat(absolute)\n return [{\n path: rel,\n size: s.size,\n modifiedAt: s.mtime,\n }]\n }\n return []\n })\n\n const nestedResults = await Promise.all(entryPromises)\n return nestedResults.flat()\n}\n\nexport interface FileSystemArtifactClientOptions {\n root: string\n defaultContentType?: string\n}\n\nexport class FileSystemArtifactClient implements ArtifactClient {\n constructor(private readonly options: FileSystemArtifactClientOptions) {}\n\n basePath(): string {\n return this.options.root\n }\n\n async produce(path: string, input: ArtifactInput): Promise<void> {\n const target = ensureWithinRoot(this.options.root, path)\n await writeInput(target, input)\n }\n\n async consume(path: string): Promise<ArtifactOutput> {\n const target = ensureWithinRoot(this.options.root, path)\n return readFile(target)\n }\n\n async stream(path: string): Promise<NodeJS.ReadableStream> {\n const target = ensureWithinRoot(this.options.root, path)\n return createReadStream(target)\n }\n\n async list(prefix?: string): Promise<ArtifactReference[]> {\n return walk(this.options.root, prefix)\n }\n}\n\nexport function createFileSystemArtifactClient(\n root: string,\n): FileSystemArtifactClient {\n return new FileSystemArtifactClient({ root })\n}\n\n\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/workflow-artifacts",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Artifact helpers for KB Labs workflow engine.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"scripts": {
|
|
22
|
+
"clean": "rimraf dist",
|
|
23
|
+
"build": "pnpm clean && tsup --config tsup.config.ts",
|
|
24
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
25
|
+
"type-check": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run --passWithNoTests",
|
|
27
|
+
"lint": "eslint . --ignore-pattern 'dist/**'",
|
|
28
|
+
"lint:fix": "eslint . --fix --ignore-pattern 'dist/**'",
|
|
29
|
+
"test:watch": "vitest"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"pathe": "^1.1.2"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
|
|
36
|
+
"@types/node": "^24.3.3",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^8",
|
|
38
|
+
"@typescript-eslint/parser": "^8",
|
|
39
|
+
"eslint": "^9",
|
|
40
|
+
"rimraf": "^6.0.1",
|
|
41
|
+
"tsup": "^8.5.0",
|
|
42
|
+
"typescript": "^5.6.3",
|
|
43
|
+
"vitest": "^3.2.4"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20.0.0",
|
|
47
|
+
"pnpm": ">=9.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|