chuk-artifacts 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- chuk_artifacts/admin.py +97 -19
- chuk_artifacts/base.py +9 -3
- chuk_artifacts/batch.py +44 -29
- chuk_artifacts/core.py +88 -113
- chuk_artifacts/metadata.py +141 -240
- chuk_artifacts/presigned.py +60 -23
- chuk_artifacts/store.py +393 -267
- {chuk_artifacts-0.1.2.dist-info → chuk_artifacts-0.1.4.dist-info}/METADATA +201 -192
- {chuk_artifacts-0.1.2.dist-info → chuk_artifacts-0.1.4.dist-info}/RECORD +12 -13
- chuk_artifacts/session_operations.py +0 -367
- {chuk_artifacts-0.1.2.dist-info → chuk_artifacts-0.1.4.dist-info}/WHEEL +0 -0
- {chuk_artifacts-0.1.2.dist-info → chuk_artifacts-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {chuk_artifacts-0.1.2.dist-info → chuk_artifacts-0.1.4.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: chuk-artifacts
|
3
|
-
Version: 0.1.
|
4
|
-
Summary:
|
3
|
+
Version: 0.1.4
|
4
|
+
Summary: Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and strict session-based security.
|
5
5
|
License: MIT
|
6
6
|
Requires-Python: >=3.11
|
7
7
|
Description-Content-Type: text/markdown
|
@@ -12,7 +12,7 @@ Requires-Dist: pyyaml>=6.0.2
|
|
12
12
|
Requires-Dist: aioboto3>=14.3.0
|
13
13
|
Requires-Dist: redis>=6.2.0
|
14
14
|
Requires-Dist: ibm-cos-sdk>=2.13.5
|
15
|
-
Requires-Dist: chuk-sessions>=0.1.
|
15
|
+
Requires-Dist: chuk-sessions>=0.1.1
|
16
16
|
Provides-Extra: websocket
|
17
17
|
Requires-Dist: websockets>=10.0; extra == "websocket"
|
18
18
|
Provides-Extra: dev
|
@@ -23,20 +23,21 @@ Dynamic: license-file
|
|
23
23
|
|
24
24
|
# Chuk Artifacts
|
25
25
|
|
26
|
-
[](https://github.com/your-org/chuk-artifacts)
|
27
27
|
[](https://python.org)
|
28
28
|
[](LICENSE)
|
29
29
|
|
30
|
-
**Asynchronous, multi-backend artifact storage with session-based security and
|
30
|
+
**Asynchronous, multi-backend artifact storage with mandatory session-based security and grid architecture**
|
31
31
|
|
32
32
|
Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and **strict session-based security**.
|
33
33
|
|
34
34
|
## ✨ Key Features
|
35
35
|
|
36
|
-
- 🏗️ **Modular Architecture**:
|
37
|
-
- 🔒 **Session
|
36
|
+
- 🏗️ **Modular Architecture**: 5 specialized operation modules for clean separation of concerns
|
37
|
+
- 🔒 **Mandatory Session Security**: Strict isolation with no anonymous artifacts or cross-session operations
|
38
|
+
- 🌐 **Grid Architecture**: `grid/{sandbox_id}/{session_id}/{artifact_id}` paths for federation-ready organization
|
38
39
|
- 🔄 **Multi-Backend Support**: Memory, filesystem, S3, IBM COS with seamless switching
|
39
|
-
- ⚡ **
|
40
|
+
- ⚡ **High Performance**: Built with async/await for high throughput (3,000+ ops/sec)
|
40
41
|
- 🔗 **Presigned URLs**: Secure, time-limited access without credential exposure
|
41
42
|
- 📊 **Batch Operations**: Efficient multi-file uploads and processing
|
42
43
|
- 🗃️ **Metadata Caching**: Fast lookups with Redis or memory-based sessions
|
@@ -60,61 +61,61 @@ uv add chuk-artifacts
|
|
60
61
|
from chuk_artifacts import ArtifactStore
|
61
62
|
|
62
63
|
# Zero-config setup (uses memory provider)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
data
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
download_url = await store.presign_medium(artifact_id) # 1 hour
|
64
|
+
async with ArtifactStore() as store:
|
65
|
+
# Store an artifact (session auto-allocated)
|
66
|
+
artifact_id = await store.store(
|
67
|
+
data=b"Hello, world!",
|
68
|
+
mime="text/plain",
|
69
|
+
summary="A simple greeting",
|
70
|
+
filename="hello.txt"
|
71
|
+
# session_id auto-allocated if not provided
|
72
|
+
)
|
73
|
+
|
74
|
+
# Retrieve it
|
75
|
+
data = await store.retrieve(artifact_id)
|
76
|
+
print(data.decode()) # "Hello, world!"
|
77
|
+
|
78
|
+
# Generate a presigned URL
|
79
|
+
download_url = await store.presign_medium(artifact_id) # 1 hour
|
80
80
|
```
|
81
81
|
|
82
82
|
### Session-Based File Management
|
83
83
|
|
84
84
|
```python
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# List files in a session
|
94
|
-
files = await store.list_by_session("user_alice")
|
95
|
-
print(f"Alice has {len(files)} files")
|
96
|
-
|
97
|
-
# List directory-like contents
|
98
|
-
docs = await store.get_directory_contents("user_alice", "docs/")
|
99
|
-
print(f"Alice's docs: {len(docs)} files")
|
100
|
-
|
101
|
-
# Copy within same session (allowed)
|
102
|
-
backup_id = await store.copy_file(
|
103
|
-
doc_id,
|
104
|
-
new_filename="docs/private_backup.md"
|
105
|
-
)
|
106
|
-
|
107
|
-
# Cross-session operations are BLOCKED for security
|
108
|
-
try:
|
109
|
-
await store.copy_file(
|
110
|
-
doc_id,
|
111
|
-
target_session_id="user_bob" # This will fail
|
85
|
+
async with ArtifactStore() as store:
|
86
|
+
# Create files in user sessions
|
87
|
+
doc_id = await store.write_file(
|
88
|
+
content="# User's Document\n\nPrivate content here.",
|
89
|
+
filename="docs/private.md",
|
90
|
+
mime="text/markdown",
|
91
|
+
session_id="user_alice"
|
112
92
|
)
|
113
|
-
|
114
|
-
|
93
|
+
|
94
|
+
# List files in a session
|
95
|
+
files = await store.list_by_session("user_alice")
|
96
|
+
print(f"Alice has {len(files)} files")
|
97
|
+
|
98
|
+
# List directory-like contents
|
99
|
+
docs = await store.get_directory_contents("user_alice", "docs/")
|
100
|
+
print(f"Alice's docs: {len(docs)} files")
|
101
|
+
|
102
|
+
# Copy within same session (allowed)
|
103
|
+
backup_id = await store.copy_file(
|
104
|
+
doc_id,
|
105
|
+
new_filename="docs/private_backup.md"
|
106
|
+
)
|
107
|
+
|
108
|
+
# Cross-session operations are BLOCKED for security
|
109
|
+
try:
|
110
|
+
await store.copy_file(
|
111
|
+
doc_id,
|
112
|
+
target_session_id="user_bob" # This will fail
|
113
|
+
)
|
114
|
+
except ArtifactStoreError:
|
115
|
+
print("✅ Cross-session operations blocked!")
|
115
116
|
```
|
116
117
|
|
117
|
-
###
|
118
|
+
### Configuration
|
118
119
|
|
119
120
|
```python
|
120
121
|
# Production setup with S3 and Redis
|
@@ -134,29 +135,56 @@ store = ArtifactStore(
|
|
134
135
|
store = ArtifactStore() # Auto-loads configuration
|
135
136
|
```
|
136
137
|
|
137
|
-
## 🏗️ Architecture
|
138
|
+
## 🏗️ Modular Architecture
|
138
139
|
|
139
|
-
Chuk Artifacts uses a modular architecture with specialized operation modules:
|
140
|
+
Chuk Artifacts uses a clean modular architecture with specialized operation modules:
|
140
141
|
|
141
142
|
```
|
142
143
|
ArtifactStore (Main Coordinator)
|
143
144
|
├── CoreStorageOperations # store() and retrieve()
|
144
|
-
├──
|
145
|
-
├──
|
146
|
-
├── SessionOperations # session-based file operations (NEW)
|
145
|
+
├── MetadataOperations # metadata, exists, delete, update, list operations
|
146
|
+
├── PresignedURLOperations # URL generation and upload workflows
|
147
147
|
├── BatchOperations # store_batch() for multiple files
|
148
148
|
└── AdminOperations # validate_configuration, get_stats
|
149
149
|
```
|
150
150
|
|
151
|
+
### Grid Architecture
|
152
|
+
|
153
|
+
All artifacts are organized using a consistent grid structure:
|
154
|
+
|
155
|
+
```
|
156
|
+
grid/{sandbox_id}/{session_id}/{artifact_id}
|
157
|
+
```
|
158
|
+
|
159
|
+
**Benefits:**
|
160
|
+
- **Federation Ready**: Cross-sandbox discovery and routing
|
161
|
+
- **Session Isolation**: Clear boundaries for security
|
162
|
+
- **Predictable Paths**: Easy to understand and manage
|
163
|
+
- **Scalable**: Handles multi-tenant applications
|
164
|
+
|
151
165
|
This design provides:
|
152
166
|
- **Better testability**: Each module can be tested independently
|
153
167
|
- **Enhanced maintainability**: Clear separation of concerns
|
154
168
|
- **Easy extensibility**: Add new operation types without touching core
|
155
169
|
- **Improved debugging**: Isolated functionality for easier troubleshooting
|
156
|
-
- **Session security**: Dedicated module for secure session operations
|
157
170
|
|
158
171
|
## 🔒 Session-Based Security
|
159
172
|
|
173
|
+
### Mandatory Sessions
|
174
|
+
```python
|
175
|
+
# Every artifact belongs to a session - no anonymous artifacts
|
176
|
+
artifact_id = await store.store(
|
177
|
+
data=b"content",
|
178
|
+
mime="text/plain",
|
179
|
+
summary="description"
|
180
|
+
# session_id auto-allocated if not provided
|
181
|
+
)
|
182
|
+
|
183
|
+
# Get the session it was allocated to
|
184
|
+
metadata = await store.metadata(artifact_id)
|
185
|
+
session_id = metadata["session_id"]
|
186
|
+
```
|
187
|
+
|
160
188
|
### Strict Session Isolation
|
161
189
|
```python
|
162
190
|
# Users can only access their own files
|
@@ -178,19 +206,6 @@ company_b_files = await store.list_by_session("company_b")
|
|
178
206
|
# Compliance-ready: GDPR, SOX, HIPAA
|
179
207
|
```
|
180
208
|
|
181
|
-
### Directory-Like Organization
|
182
|
-
```python
|
183
|
-
# Organize files with path-like prefixes
|
184
|
-
await store.write_file(content, filename="docs/reports/q1_sales.pdf", session_id="user_123")
|
185
|
-
await store.write_file(content, filename="docs/contracts/client_a.pdf", session_id="user_123")
|
186
|
-
await store.write_file(content, filename="images/profile.jpg", session_id="user_123")
|
187
|
-
|
188
|
-
# List by directory
|
189
|
-
docs = await store.get_directory_contents("user_123", "docs/")
|
190
|
-
reports = await store.get_directory_contents("user_123", "docs/reports/")
|
191
|
-
images = await store.get_directory_contents("user_123", "images/")
|
192
|
-
```
|
193
|
-
|
194
209
|
## 📦 Storage Providers
|
195
210
|
|
196
211
|
### Memory Provider
|
@@ -200,7 +215,7 @@ store = ArtifactStore(storage_provider="memory")
|
|
200
215
|
- Perfect for development and testing
|
201
216
|
- Zero configuration required
|
202
217
|
- Non-persistent (data lost on restart)
|
203
|
-
-
|
218
|
+
- **Note**: Provider isolation limitations for testing
|
204
219
|
|
205
220
|
### Filesystem Provider
|
206
221
|
```python
|
@@ -212,7 +227,7 @@ os.environ["ARTIFACT_FS_ROOT"] = "./my-artifacts"
|
|
212
227
|
- Persistent across restarts
|
213
228
|
- `file://` URLs for local access
|
214
229
|
- **Full session listing support**
|
215
|
-
- Great for development and
|
230
|
+
- Great for development and staging
|
216
231
|
|
217
232
|
### AWS S3 Provider
|
218
233
|
```python
|
@@ -295,7 +310,7 @@ async def upload_file(data_base64: str, filename: str, mime: str, session_id: st
|
|
295
310
|
|
296
311
|
# MCP tool: List session files
|
297
312
|
async def list_session_files(session_id: str, prefix: str = ""):
|
298
|
-
files = await store.
|
313
|
+
files = await store.get_directory_contents(session_id, prefix)
|
299
314
|
return {"files": files}
|
300
315
|
|
301
316
|
# MCP tool: Copy file (within session only)
|
@@ -337,39 +352,6 @@ async def list_user_files(user_id: str, directory: str = ""):
|
|
337
352
|
return await store.get_directory_contents(f"user_{user_id}", directory)
|
338
353
|
```
|
339
354
|
|
340
|
-
### Multi-Tenant SaaS Application
|
341
|
-
|
342
|
-
```python
|
343
|
-
# Tenant isolation
|
344
|
-
async def create_tenant_workspace(tenant_id: str):
|
345
|
-
"""Create isolated workspace for tenant"""
|
346
|
-
|
347
|
-
# Create tenant directory structure
|
348
|
-
directories = ["documents/", "images/", "reports/", "config/"]
|
349
|
-
|
350
|
-
for directory in directories:
|
351
|
-
# Create a marker file for the directory
|
352
|
-
await store.write_file(
|
353
|
-
content=f"# {directory.rstrip('/')} Directory\n\nTenant workspace created.",
|
354
|
-
filename=f"{directory}README.md",
|
355
|
-
session_id=f"tenant_{tenant_id}"
|
356
|
-
)
|
357
|
-
|
358
|
-
return {"tenant_id": tenant_id, "directories": directories}
|
359
|
-
|
360
|
-
async def get_tenant_usage(tenant_id: str):
|
361
|
-
"""Get storage usage for a tenant"""
|
362
|
-
files = await store.list_by_session(f"tenant_{tenant_id}")
|
363
|
-
total_bytes = sum(file.get('bytes', 0) for file in files)
|
364
|
-
|
365
|
-
return {
|
366
|
-
"tenant_id": tenant_id,
|
367
|
-
"file_count": len(files),
|
368
|
-
"total_bytes": total_bytes,
|
369
|
-
"total_mb": round(total_bytes / 1024 / 1024, 2)
|
370
|
-
}
|
371
|
-
```
|
372
|
-
|
373
355
|
### Advanced File Operations
|
374
356
|
|
375
357
|
```python
|
@@ -391,13 +373,15 @@ await store.move_file(
|
|
391
373
|
new_filename="documents/renamed_doc.md"
|
392
374
|
)
|
393
375
|
|
394
|
-
# Update
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
overwrite_artifact_id=old_artifact_id
|
376
|
+
# Update metadata
|
377
|
+
await store.update_metadata(
|
378
|
+
artifact_id,
|
379
|
+
summary="Updated summary",
|
380
|
+
meta={"version": 2, "updated_by": "user_123"}
|
400
381
|
)
|
382
|
+
|
383
|
+
# Extend TTL
|
384
|
+
await store.extend_ttl(artifact_id, additional_seconds=3600)
|
401
385
|
```
|
402
386
|
|
403
387
|
### Batch Processing
|
@@ -423,43 +407,40 @@ items = [
|
|
423
407
|
artifact_ids = await store.store_batch(items, session_id="product-catalog")
|
424
408
|
```
|
425
409
|
|
426
|
-
### Context Manager Usage
|
427
|
-
|
428
|
-
```python
|
429
|
-
async with ArtifactStore() as store:
|
430
|
-
artifact_id = await store.store(
|
431
|
-
data=b"Temporary data",
|
432
|
-
mime="text/plain",
|
433
|
-
summary="Auto-cleanup example",
|
434
|
-
session_id="temp_session"
|
435
|
-
)
|
436
|
-
# Store automatically closed on exit
|
437
|
-
```
|
438
|
-
|
439
410
|
## 🧪 Testing
|
440
411
|
|
441
412
|
### Run All Tests
|
442
413
|
```bash
|
443
|
-
#
|
444
|
-
uv run examples/
|
414
|
+
# MCP server scenarios (recommended)
|
415
|
+
uv run examples/mcp_test_demo.py
|
445
416
|
|
446
|
-
#
|
447
|
-
uv run examples/artifact_usage_examples.py
|
448
|
-
|
449
|
-
# Session operations demo (NEW)
|
417
|
+
# Session security testing
|
450
418
|
uv run examples/session_operations_demo.py
|
419
|
+
|
420
|
+
# Grid architecture demo
|
421
|
+
uv run examples/grid_demo.py
|
422
|
+
|
423
|
+
# Complete verification
|
424
|
+
uv run examples/complete_verification.py
|
451
425
|
```
|
452
426
|
|
453
|
-
###
|
454
|
-
|
455
|
-
|
456
|
-
|
427
|
+
### Test Results
|
428
|
+
Recent test results show excellent performance:
|
429
|
+
```
|
430
|
+
📤 Test 1: Rapid file creation...
|
431
|
+
✅ Created 20 files in 0.006s (3,083 files/sec)
|
457
432
|
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
433
|
+
📋 Test 2: Session listing performance...
|
434
|
+
✅ Listed 20 files in 0.002s
|
435
|
+
|
436
|
+
📁 Test 3: Directory operations...
|
437
|
+
✅ Listed uploads/ directory (20 files) in 0.002s
|
438
|
+
|
439
|
+
📖 Test 4: Batch read operations...
|
440
|
+
✅ Read 10 files in 0.002s (4,693 reads/sec)
|
441
|
+
|
442
|
+
📋 Test 5: Copy operations...
|
443
|
+
✅ Copied 5 files in 0.003s (1,811 copies/sec)
|
463
444
|
```
|
464
445
|
|
465
446
|
### Development Setup
|
@@ -485,6 +466,7 @@ store = testing_setup("./test-artifacts") # Uses filesystem
|
|
485
466
|
ARTIFACT_PROVIDER=s3 # memory, filesystem, s3, ibm_cos, ibm_cos_iam
|
486
467
|
ARTIFACT_BUCKET=my-artifacts # Bucket/container name
|
487
468
|
ARTIFACT_FS_ROOT=./artifacts # Filesystem root (filesystem provider)
|
469
|
+
ARTIFACT_SANDBOX_ID=my-app # Sandbox identifier for multi-tenancy
|
488
470
|
|
489
471
|
# Session configuration
|
490
472
|
SESSION_PROVIDER=redis # memory, redis
|
@@ -529,42 +511,47 @@ store = ArtifactStore()
|
|
529
511
|
- **Connection Pooling**: Efficient resource usage with aioboto3
|
530
512
|
- **Metadata Caching**: Sub-millisecond lookups with Redis
|
531
513
|
- **Batch Operations**: Reduced overhead for multiple files
|
532
|
-
- **
|
533
|
-
- **Session Listing**: Optimized prefix-based queries
|
514
|
+
- **Grid Architecture**: Optimized session-based queries
|
534
515
|
|
535
516
|
### Performance Benchmarks
|
536
517
|
```
|
537
|
-
✅
|
538
|
-
✅
|
539
|
-
✅
|
540
|
-
✅
|
518
|
+
✅ File Creation: 3,083 files/sec
|
519
|
+
✅ File Reading: 4,693 reads/sec
|
520
|
+
✅ File Copying: 1,811 copies/sec
|
521
|
+
✅ Session Listing: ~0.002s for 20+ files
|
522
|
+
✅ Directory Listing: ~0.002s for filtered results
|
541
523
|
```
|
542
524
|
|
543
525
|
## 🔒 Security
|
544
526
|
|
527
|
+
- **Mandatory Sessions**: No anonymous artifacts allowed
|
545
528
|
- **Session Isolation**: Strict boundaries prevent cross-session access
|
546
529
|
- **No Cross-Session Operations**: Copy, move, overwrite blocked across sessions
|
530
|
+
- **Grid Architecture**: Clear audit trail in paths
|
547
531
|
- **Presigned URLs**: Time-limited access without credential sharing
|
548
532
|
- **Secure Defaults**: Conservative TTL and expiration settings
|
549
533
|
- **Credential Isolation**: Environment-based configuration
|
550
534
|
- **Error Handling**: No sensitive data in logs or exceptions
|
551
|
-
- **Multi-Tenant Ready**: Perfect for SaaS applications
|
552
535
|
|
553
536
|
### Security Validation
|
554
537
|
```python
|
555
538
|
# All these operations are blocked for security
|
556
539
|
await store.copy_file(user_a_file, target_session_id="user_b") # ❌ Blocked
|
557
540
|
await store.move_file(user_a_file, new_session_id="user_b") # ❌ Blocked
|
558
|
-
|
559
|
-
|
541
|
+
|
542
|
+
# Security test results:
|
543
|
+
# ✅ Cross-session copy correctly blocked
|
544
|
+
# ✅ Cross-session move correctly blocked
|
545
|
+
# ✅ Cross-session overwrite correctly blocked
|
546
|
+
# 🛡️ ALL SECURITY TESTS PASSED!
|
560
547
|
```
|
561
548
|
|
562
549
|
## 📝 API Reference
|
563
550
|
|
564
551
|
### Core Methods
|
565
552
|
|
566
|
-
#### `store(data, *, mime, summary, meta=None, filename=None, session_id=None, ttl=900)`
|
567
|
-
Store artifact data with metadata.
|
553
|
+
#### `store(data, *, mime, summary, meta=None, filename=None, session_id=None, user_id=None, ttl=900)`
|
554
|
+
Store artifact data with metadata. Session auto-allocated if not provided.
|
568
555
|
|
569
556
|
#### `retrieve(artifact_id)`
|
570
557
|
Retrieve artifact data by ID.
|
@@ -575,28 +562,44 @@ Get artifact metadata.
|
|
575
562
|
#### `exists(artifact_id)` / `delete(artifact_id)`
|
576
563
|
Check existence or delete artifacts.
|
577
564
|
|
578
|
-
### Session Operations
|
565
|
+
### Session Operations
|
566
|
+
|
567
|
+
#### `create_session(user_id=None, ttl_hours=None)`
|
568
|
+
Create a new session explicitly.
|
569
|
+
|
570
|
+
#### `validate_session(session_id)` / `get_session_info(session_id)`
|
571
|
+
Session validation and information retrieval.
|
579
572
|
|
580
573
|
#### `list_by_session(session_id, limit=100)`
|
581
574
|
List all artifacts in a session.
|
582
575
|
|
583
|
-
#### `list_by_prefix(session_id, prefix="", limit=100)`
|
584
|
-
List artifacts with filename prefix (directory-like).
|
585
|
-
|
586
576
|
#### `get_directory_contents(session_id, directory_prefix="", limit=100)`
|
587
577
|
Get files in a directory-like structure.
|
588
578
|
|
589
|
-
|
590
|
-
Copy file within same session only (cross-session blocked).
|
579
|
+
### File Operations
|
591
580
|
|
592
|
-
#### `
|
593
|
-
|
581
|
+
#### `write_file(content, *, filename, mime="text/plain", session_id=None, ...)`
|
582
|
+
Write content to new file.
|
594
583
|
|
595
584
|
#### `read_file(artifact_id, *, encoding="utf-8", as_text=True)`
|
596
585
|
Read file content directly as text or binary.
|
597
586
|
|
598
|
-
#### `
|
599
|
-
|
587
|
+
#### `copy_file(artifact_id, *, new_filename=None, new_meta=None, summary=None)`
|
588
|
+
Copy file within same session only (cross-session blocked).
|
589
|
+
|
590
|
+
#### `move_file(artifact_id, *, new_filename=None, new_meta=None)`
|
591
|
+
Move/rename file within same session only (cross-session blocked).
|
592
|
+
|
593
|
+
#### `list_files(session_id, prefix="", limit=100)`
|
594
|
+
List files with optional prefix filtering.
|
595
|
+
|
596
|
+
### Metadata Operations
|
597
|
+
|
598
|
+
#### `update_metadata(artifact_id, *, summary=None, meta=None, merge=True, **kwargs)`
|
599
|
+
Update artifact metadata.
|
600
|
+
|
601
|
+
#### `extend_ttl(artifact_id, additional_seconds)`
|
602
|
+
Extend artifact TTL.
|
600
603
|
|
601
604
|
### Presigned URLs
|
602
605
|
|
@@ -609,6 +612,9 @@ Generate URLs with predefined durations (15min/1hr/24hr).
|
|
609
612
|
#### `presign_upload(session_id=None, filename=None, mime_type="application/octet-stream", expires=3600)`
|
610
613
|
Generate presigned URL for upload.
|
611
614
|
|
615
|
+
#### `register_uploaded_artifact(artifact_id, *, mime, summary, ...)`
|
616
|
+
Register metadata for presigned uploads.
|
617
|
+
|
612
618
|
### Batch Operations
|
613
619
|
|
614
620
|
#### `store_batch(items, session_id=None, ttl=900)`
|
@@ -622,23 +628,15 @@ Validate storage and session provider connectivity.
|
|
622
628
|
#### `get_stats()`
|
623
629
|
Get storage statistics and configuration info.
|
624
630
|
|
625
|
-
|
631
|
+
### Grid Operations
|
626
632
|
|
627
|
-
|
628
|
-
|
629
|
-
# Create custom storage provider
|
630
|
-
def my_custom_factory():
|
631
|
-
@asynccontextmanager
|
632
|
-
async def _ctx():
|
633
|
-
client = MyCustomClient()
|
634
|
-
try:
|
635
|
-
yield client
|
636
|
-
finally:
|
637
|
-
await client.close()
|
638
|
-
return _ctx
|
633
|
+
#### `get_canonical_prefix(session_id)`
|
634
|
+
Get grid path prefix for session.
|
639
635
|
|
640
|
-
|
641
|
-
|
636
|
+
#### `generate_artifact_key(session_id, artifact_id)`
|
637
|
+
Generate grid artifact key.
|
638
|
+
|
639
|
+
## 🛠️ Advanced Features
|
642
640
|
|
643
641
|
### Error Handling
|
644
642
|
```python
|
@@ -646,7 +644,8 @@ from chuk_artifacts import (
|
|
646
644
|
ArtifactNotFoundError,
|
647
645
|
ArtifactExpiredError,
|
648
646
|
ProviderError,
|
649
|
-
|
647
|
+
SessionError,
|
648
|
+
ArtifactStoreError # For session security violations
|
650
649
|
)
|
651
650
|
|
652
651
|
try:
|
@@ -670,6 +669,18 @@ print(f"Session: {config_status['session']['status']}")
|
|
670
669
|
stats = await store.get_stats()
|
671
670
|
print(f"Provider: {stats['storage_provider']}")
|
672
671
|
print(f"Bucket: {stats['bucket']}")
|
672
|
+
print(f"Sandbox: {stats['sandbox_id']}")
|
673
|
+
```
|
674
|
+
|
675
|
+
### Context Manager Usage
|
676
|
+
```python
|
677
|
+
async with ArtifactStore() as store:
|
678
|
+
artifact_id = await store.store(
|
679
|
+
data=b"Temporary data",
|
680
|
+
mime="text/plain",
|
681
|
+
summary="Auto-cleanup example"
|
682
|
+
)
|
683
|
+
# Store automatically closed on exit
|
673
684
|
```
|
674
685
|
|
675
686
|
## 🤝 Contributing
|
@@ -677,7 +688,7 @@ print(f"Bucket: {stats['bucket']}")
|
|
677
688
|
1. Fork the repository
|
678
689
|
2. Create a feature branch: `git checkout -b feature-name`
|
679
690
|
3. Make your changes
|
680
|
-
4. Run tests: `uv run examples/
|
691
|
+
4. Run tests: `uv run examples/mcp_test_demo.py`
|
681
692
|
5. Test session operations: `uv run examples/session_operations_demo.py`
|
682
693
|
6. Submit a pull request
|
683
694
|
|
@@ -685,26 +696,24 @@ print(f"Bucket: {stats['bucket']}")
|
|
685
696
|
|
686
697
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
687
698
|
|
688
|
-
## 🔗 Links
|
689
|
-
|
690
|
-
- **Documentation**: [docs.example.com](https://docs.example.com)
|
691
|
-
- **Issue Tracker**: [github.com/your-org/chuk-artifacts/issues](https://github.com/your-org/chuk-artifacts/issues)
|
692
|
-
- **PyPI**: [pypi.org/project/chuk-artifacts](https://pypi.org/project/chuk-artifacts)
|
693
|
-
|
694
699
|
## 🎯 Roadmap
|
695
700
|
|
696
701
|
- [x] **Session-based security** with strict isolation
|
697
|
-
- [x] **
|
702
|
+
- [x] **Grid architecture** with federation-ready paths
|
703
|
+
- [x] **Modular design** with specialized operation modules
|
698
704
|
- [x] **High-performance operations** (3,000+ ops/sec)
|
705
|
+
- [x] **Directory-like operations** with prefix filtering
|
706
|
+
- [x] **Comprehensive testing** with real-world scenarios
|
699
707
|
- [ ] Azure Blob Storage provider
|
700
|
-
- [ ] Google Cloud Storage provider
|
708
|
+
- [ ] Google Cloud Storage provider
|
701
709
|
- [ ] Encryption at rest
|
702
710
|
- [ ] Artifact versioning
|
703
711
|
- [ ] Webhook notifications
|
704
712
|
- [ ] Prometheus metrics export
|
713
|
+
- [ ] Federation implementation
|
705
714
|
|
706
715
|
---
|
707
716
|
|
708
|
-
**Made with ❤️
|
717
|
+
**Made with ❤️ for secure, scalable artifact storage**
|
709
718
|
|
710
|
-
*
|
719
|
+
*Production-ready artifact storage with mandatory session security and grid architecture*
|
@@ -1,24 +1,23 @@
|
|
1
1
|
chuk_artifacts/__init__.py,sha256=-4S9FWKVcQSa2ZD3GVbmbpGZPcl0cTQN_TFZLSqV7lQ,3605
|
2
|
-
chuk_artifacts/admin.py,sha256=
|
3
|
-
chuk_artifacts/base.py,sha256=
|
4
|
-
chuk_artifacts/batch.py,sha256=
|
2
|
+
chuk_artifacts/admin.py,sha256=O7jQCMbH-ExmYvJkfjHidagOgTF8o32-xQ7d2Ul9o_I,5727
|
3
|
+
chuk_artifacts/base.py,sha256=BtuVnC9M8QI1znyTdBxjZ6knIKP_k0yUfLfh7inGJUc,2559
|
4
|
+
chuk_artifacts/batch.py,sha256=x8ARrWJ24I9fAXXodzvh31uMxYrvwZCGGJhUCM4vMJ4,5099
|
5
5
|
chuk_artifacts/config.py,sha256=MaUzHzKPoBUyERviEpv8JVvPybMzSksgLyj0b7AO3Sc,7664
|
6
|
-
chuk_artifacts/core.py,sha256=
|
6
|
+
chuk_artifacts/core.py,sha256=hokH7cgGE2ZaEwlV8XMKOov3EMvcLS2HufdApLS6l3M,6699
|
7
7
|
chuk_artifacts/exceptions.py,sha256=f-s7Mg7c8vMXsbgqO2B6lMHdXcJQNvsESAY4GhJaV4g,814
|
8
|
-
chuk_artifacts/metadata.py,sha256=
|
8
|
+
chuk_artifacts/metadata.py,sha256=KinpOF-b8qOYffXx9Ixbv-Ms9MjD7wMtAP03ZVofCsU,7731
|
9
9
|
chuk_artifacts/models.py,sha256=_foXlkr0DprqgztDw5WtlDc-s1OouLgYNp4XM1Ghp-g,837
|
10
|
-
chuk_artifacts/presigned.py,sha256
|
10
|
+
chuk_artifacts/presigned.py,sha256=-GE8r0CfUZuPNA_jnSGTfX7kuws6kYCPe7C4y6FItdo,11491
|
11
11
|
chuk_artifacts/provider_factory.py,sha256=T0IXx1C8gygJzp417oB44_DxEaZoZR7jcdwQy8FghRE,3398
|
12
|
-
chuk_artifacts/
|
13
|
-
chuk_artifacts/store.py,sha256=0RKSAkSfTM1v-qg3ERv3-8VaRiBVMxdGy2qxjFVz9MY,19749
|
12
|
+
chuk_artifacts/store.py,sha256=3E_eh7JcgyW7-ikLSn_fFMUV4AwN5A0phkEmF0cMaxw,24779
|
14
13
|
chuk_artifacts/providers/__init__.py,sha256=3lN1lAy1ETT1mQslJo1f22PPR1W4CyxmsqJBclzH4NE,317
|
15
14
|
chuk_artifacts/providers/filesystem.py,sha256=F4EjE-_ItPg0RWe7CqameVpOMjU-b7AigEBkm_ZoNrc,15280
|
16
15
|
chuk_artifacts/providers/ibm_cos.py,sha256=K1-VAX4UVV9tA161MOeDXOKloQ0hB77jdw1-p46FwmU,4445
|
17
16
|
chuk_artifacts/providers/ibm_cos_iam.py,sha256=VtwvCi9rMMcZx6i9l21ob6wM8jXseqvjzgCnAA82RkY,3186
|
18
17
|
chuk_artifacts/providers/memory.py,sha256=B1C-tR1PcNz-UuDfGm1bhjPz3oITVATIMPekVbE7nm4,10487
|
19
18
|
chuk_artifacts/providers/s3.py,sha256=eWhBhFSaobpRbazn7ySfU_7D8rm_xCfdSVqRtzXzXRY,2858
|
20
|
-
chuk_artifacts-0.1.
|
21
|
-
chuk_artifacts-0.1.
|
22
|
-
chuk_artifacts-0.1.
|
23
|
-
chuk_artifacts-0.1.
|
24
|
-
chuk_artifacts-0.1.
|
19
|
+
chuk_artifacts-0.1.4.dist-info/licenses/LICENSE,sha256=SG9BmgtPBagPV0d-Fep-msdAGl-E1CeoBL7-EDRH2qA,1066
|
20
|
+
chuk_artifacts-0.1.4.dist-info/METADATA,sha256=qtT0mnVKLwYjOhtRaFCY1GDmyrv9eOCC9bjKYDnmYD0,21188
|
21
|
+
chuk_artifacts-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
22
|
+
chuk_artifacts-0.1.4.dist-info/top_level.txt,sha256=1_PVMtWXR0A-ZmeH6apF9mPaMtU0i23JE6wmN4GBRDI,15
|
23
|
+
chuk_artifacts-0.1.4.dist-info/RECORD,,
|