@absolutejs/artifacts 0.0.1 → 0.0.3

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 CHANGED
@@ -14,11 +14,20 @@ routes, authorization, UI, or hosting.
14
14
 
15
15
  - Structured artifact-kind schemas and runtime validation
16
16
  - Draft, published, and archived lifecycle states
17
- - Optimistic revisions that prevent lost edits
18
- - Storage, renderer, and publisher interfaces
19
- - An in-memory store for development and tests
17
+ - Immutable revision history, restoration, and optimistic updates
18
+ - Structured content plus opaque references to generated or source files
19
+ - Artifact, asset, renderer, and publisher storage interfaces
20
+ - In-memory artifact and asset stores for development and tests
20
21
  - Owner-bound lifecycle tools structurally compatible with AI tool maps
21
22
  - Provenance fields for model, tool, trace, and source entities
23
+ - Standard file-backed kinds for documents, presentations, spreadsheets,
24
+ datasets, code, images, audio, video, email, archives, and generic files
25
+ - An optional bridge to `@absolutejs/rag` ingestion
26
+ - Provider-neutral generation registries with atomic multi-file bundles
27
+ - Revision-pinned or explicitly live publications
28
+ - Durable lifecycle events designed for transactional outboxes
29
+ - Per-revision RAG indexing state and an indexing coordinator
30
+ - Artifact/source lineage and history-aware asset garbage collection
22
31
 
23
32
  Your application retains authorization, durable persistence, public tokens,
24
33
  URLs, notifications, analytics, submissions, and product-specific rendering.
@@ -29,6 +38,7 @@ URLs, notifications, analytics, submissions, and product-specific rendering.
29
38
  import { Type } from "@sinclair/typebox";
30
39
  import {
31
40
  createArtifactService,
41
+ createMemoryArtifactAssetStore,
32
42
  createMemoryArtifactStore,
33
43
  defineArtifactRegistry,
34
44
  } from "@absolutejs/artifacts";
@@ -51,6 +61,7 @@ const registry = defineArtifactRegistry({
51
61
  });
52
62
 
53
63
  const artifacts = createArtifactService({
64
+ assetStore: createMemoryArtifactAssetStore(),
54
65
  registry,
55
66
  store: createMemoryArtifactStore(),
56
67
  });
@@ -67,6 +78,126 @@ const page = await artifacts.create("owner-123", {
67
78
  });
68
79
  ```
69
80
 
81
+ Every successful create or lifecycle mutation appends an immutable snapshot.
82
+ Restoring history creates a new private draft instead of rewriting or
83
+ republishing an old revision:
84
+
85
+ ```ts
86
+ const history = await artifacts.listRevisions("owner-123", page.id);
87
+ const restored = await artifacts.restore("owner-123", page.id, 1);
88
+ ```
89
+
90
+ ## File-backed artifact kinds
91
+
92
+ Use the bundled definitions directly or compose them with application-specific
93
+ kinds:
94
+
95
+ ```ts
96
+ import {
97
+ defineArtifactRegistry,
98
+ standardArtifactDefinitions,
99
+ } from "@absolutejs/artifacts";
100
+
101
+ const registry = defineArtifactRegistry({
102
+ ...standardArtifactDefinitions,
103
+ page: myPageDefinition,
104
+ });
105
+ ```
106
+
107
+ File bytes stay in host storage. Artifact records retain opaque references with
108
+ name, media type, size, checksum, role, and storage URI. The URI is not treated
109
+ as a public URL and the package reads it only through the configured asset
110
+ store. Detaching a file does not delete its bytes because older immutable
111
+ revisions may still reference it.
112
+
113
+ ```ts
114
+ const report = await artifacts.create("owner-123", {
115
+ content: { summary: "Quarterly results" },
116
+ createdBy: "agent",
117
+ kind: "document",
118
+ title: "Q3 report",
119
+ });
120
+
121
+ await artifacts.attach("owner-123", report.id, {
122
+ data: pdfBytes,
123
+ mediaType: "application/pdf",
124
+ name: "q3-report.pdf",
125
+ role: "primary",
126
+ });
127
+ ```
128
+
129
+ Multiple generated files should use one staged transaction and therefore one
130
+ artifact revision:
131
+
132
+ ```ts
133
+ const report = await artifacts.createBundle("owner-123", {
134
+ assets: [pdfOutput, docxOutput, thumbnailOutput],
135
+ content: { summary: "Quarterly results" },
136
+ createdBy: "agent",
137
+ kind: "document",
138
+ provenance: {
139
+ lineage: [{ relation: "generated_from", sourceId: "rag-document-123" }],
140
+ tool: "quarterly_report_generator",
141
+ },
142
+ title: "Q3 report",
143
+ });
144
+ ```
145
+
146
+ ## Generation
147
+
148
+ Generators are provider-neutral. They return validated structured content and
149
+ zero or more file writes; the registry commits those outputs through the same
150
+ artifact bundle lifecycle:
151
+
152
+ ```ts
153
+ const generators = createArtifactGeneratorRegistry([
154
+ {
155
+ kind: "presentation",
156
+ name: "company-deck",
157
+ generate: async ({ prompt }) => buildPresentation(prompt),
158
+ },
159
+ ]);
160
+
161
+ const deck = await generators.generate(artifacts, {
162
+ createdBy: "agent",
163
+ kind: "presentation",
164
+ ownerId: member.id,
165
+ prompt: "Build the partner launch deck",
166
+ });
167
+ ```
168
+
169
+ ## RAG ingestion
170
+
171
+ The optional `@absolutejs/artifacts/rag` entry point resolves one current or
172
+ historical artifact record into the upload contract already accepted by
173
+ `@absolutejs/rag`. Structured content is included as JSON and every attached
174
+ file is included without exposing its storage URI:
175
+
176
+ ```ts
177
+ import { artifactToRAGUploads } from "@absolutejs/artifacts/rag";
178
+ import { buildRAGUpsertInputFromUploads } from "@absolutejs/rag";
179
+
180
+ const revision = await artifacts.getRevision("owner-123", report.id, 2);
181
+ const uploads = await artifactToRAGUploads(revision, assetStore);
182
+ const upsert = await buildRAGUpsertInputFromUploads({ uploads });
183
+ ```
184
+
185
+ `createArtifactRAGIndexCoordinator` wraps that conversion with durable
186
+ `pending`, `indexed`, and `failed` state. It removes document IDs from the
187
+ previous indexed revision after the replacement succeeds.
188
+
189
+ ## Events and retention
190
+
191
+ Every lifecycle mutation supplies its event to the artifact store in the same
192
+ call that writes the current record and immutable revision. Durable adapters
193
+ should commit those rows in one database transaction, then workers can consume
194
+ unprocessed events for RAG indexing, previews, notifications, scanning, or
195
+ conversion.
196
+
197
+ Asset collection compares storage candidates with references across every
198
+ retained revision. `collectAssetGarbage({ dryRun: true })` previews deletion;
199
+ only unreferenced objects older than the configured minimum age are eligible.
200
+
70
201
  ## Compose publishing and rendering
71
202
 
72
203
  Publishing is an adapter because public access is a host policy:
@@ -84,6 +215,10 @@ const artifacts = createArtifactService({
84
215
  });
85
216
  ```
86
217
 
218
+ Publishing defaults to `pinned`: the public record names the exact immutable
219
+ revision. `mode: "live"` is an explicit alternative whose revision advances
220
+ with later edits.
221
+
87
222
  Renderers are independently registered by artifact kind and output format:
88
223
 
89
224
  ```ts