@yargote/artifacts-contracts 0.1.0-beta.7 → 0.1.0-beta.8

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
@@ -3,11 +3,15 @@
3
3
  `@yargote/artifacts-contracts` contains strict domain schemas, types, `ArtifactError`, snapshot serialization, and pure retained-edit helpers. It has no database, ZIP, server, or CLI dependency. Node 24 or later is required.
4
4
 
5
5
  ```sh
6
- npm install @yargote/artifacts-contracts@0.1.0-beta.7
6
+ npm install @yargote/artifacts-contracts@0.1.0-beta.8
7
7
  ```
8
8
 
9
9
  The root export contains domain schemas and types. `/workflow` contains `prepareArtifactEdit`, revision comparison, and compact projections. `/serialization` contains canonical JSON and SHA-256. `/http` contains HTTP response schemas, identity, canonical resource validation, and route URL helpers.
10
10
 
11
+ `protectedResourceMetadataSchema` accepts standard protected-resource metadata and an optional `artifacts_rest_resource`. The relation names the exact absolute canonical REST OAuth resource URL. It may name the resource itself or one distinct REST resource. Metadata for the distinct resource may omit the relation or name itself, but cannot name another resource.
12
+
13
+ `slugSchema` validates page slugs such as `concepts/rag` without normalizing them. `readSchema` takes exactly one of `artifactId` or a `{ project, slug }` locator, and `readByIdSchema` takes only an ID. `ArtifactRead` and the HTTP summary schema include `slug`, and `ArtifactErrorCode` includes `slug_conflict`.
14
+
11
15
  The existing `@artifacts/artifacts` root, `/contracts`, and `/workflow` exports re-export these implementations. Store and REST packages share one `ArtifactError` runtime.
12
16
 
13
17
  This package is MIT licensed. The license applies to this package and does not license the private Artifacts application repository.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yargote/artifacts-contracts",
3
- "version": "0.1.0-beta.7",
3
+ "version": "0.1.0-beta.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Shared schemas and contracts for Artifacts clients.",
package/src/http.d.ts CHANGED
@@ -52,6 +52,7 @@ export declare const compactArtifactReadSchema: z.ZodObject<{
52
52
  ownerId: z.ZodString;
53
53
  headRevisionId: z.ZodString;
54
54
  project: z.ZodNullable<z.ZodString>;
55
+ slug: z.ZodNullable<z.ZodString>;
55
56
  artifactId: z.ZodString;
56
57
  publication: z.ZodNullable<z.ZodObject<{
57
58
  revisionId: z.ZodString;
@@ -97,6 +98,7 @@ export declare const artifactSummarySchema: z.ZodObject<{
97
98
  headRevisionId: z.ZodString;
98
99
  createdAt: z.ZodISODateTime;
99
100
  project: z.ZodNullable<z.ZodString>;
101
+ slug: z.ZodNullable<z.ZodString>;
100
102
  publication: z.ZodNullable<z.ZodObject<{
101
103
  revisionId: z.ZodString;
102
104
  version: z.ZodNumber;
@@ -110,6 +112,7 @@ export declare const listResultSchema: z.ZodObject<{
110
112
  headRevisionId: z.ZodString;
111
113
  createdAt: z.ZodISODateTime;
112
114
  project: z.ZodNullable<z.ZodString>;
115
+ slug: z.ZodNullable<z.ZodString>;
113
116
  publication: z.ZodNullable<z.ZodObject<{
114
117
  revisionId: z.ZodString;
115
118
  version: z.ZodNumber;
@@ -208,5 +211,10 @@ export declare const httpErrorSchema: z.ZodObject<{
208
211
  }, z.core.$strict>;
209
212
  }, z.core.$strict>;
210
213
  export declare function canonicalResource(value: string): string;
214
+ export declare const protectedResourceMetadataSchema: z.ZodObject<{
215
+ resource: z.ZodString;
216
+ authorization_servers: z.ZodArray<z.ZodString>;
217
+ artifacts_rest_resource: z.ZodOptional<z.ZodString>;
218
+ }, z.core.$strip>;
211
219
  export declare function protectedResourceMetadataUrl(resource: string): URL;
212
220
  export declare function restBase(resource: string): string;
package/src/http.js CHANGED
@@ -10,7 +10,7 @@ export const revisionSummarySchema = revisionSchema.omit({ snapshot: true }).ext
10
10
  files: z.array(attachmentSummarySchema).max(32),
11
11
  });
12
12
  export const compactArtifactReadSchema = artifactReadSchema.omit({ revision: true }).extend({ revision: revisionSummarySchema });
13
- export const artifactSummarySchema = z.strictObject({ artifactId: identifier, title: z.string(), headRevisionId: identifier, createdAt: z.iso.datetime(), project: z.string().nullable(), publication: publicationSchema.nullable() });
13
+ export const artifactSummarySchema = z.strictObject({ artifactId: identifier, title: z.string(), headRevisionId: identifier, createdAt: z.iso.datetime(), project: z.string().nullable(), slug: z.string().nullable(), publication: publicationSchema.nullable() });
14
14
  export const listResultSchema = z.strictObject({ items: z.array(artifactSummarySchema).max(100), nextCursor: identifier.nullable() });
15
15
  export const projectSummarySchema = z.strictObject({ name: z.string(), artifactCount: z.number().int().positive() });
16
16
  export const projectsResultSchema = z.strictObject({ items: z.array(projectSummarySchema) });
@@ -26,6 +26,19 @@ export function canonicalResource(value) {
26
26
  throw new TypeError('Use the exact canonical resource URL without a trailing slash');
27
27
  return value;
28
28
  }
29
+ export const protectedResourceMetadataSchema = z.object({
30
+ resource: z.string(),
31
+ authorization_servers: z.array(z.string()).min(1),
32
+ artifacts_rest_resource: z.string().refine((value) => {
33
+ try {
34
+ canonicalResource(value);
35
+ return true;
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }).optional(),
41
+ });
29
42
  export function protectedResourceMetadataUrl(resource) {
30
43
  const url = new URL(canonicalResource(resource));
31
44
  return new URL(`/.well-known/oauth-protected-resource${url.pathname === '/' ? '' : url.pathname}`, url.origin);
package/src/index.d.ts CHANGED
@@ -59,6 +59,7 @@ export type Canvas = {
59
59
  };
60
60
  export declare function parseCanvas(snapshot: Pick<Snapshot, 'content' | 'files'>): Canvas;
61
61
  export declare const projectNameSchema: z.ZodString;
62
+ export declare const slugSchema: z.ZodString;
62
63
  export declare const createSchema: z.ZodObject<{
63
64
  requestId: z.ZodString;
64
65
  snapshot: z.ZodObject<{
@@ -87,12 +88,13 @@ export declare const createSchema: z.ZodObject<{
87
88
  }, z.core.$strict>>;
88
89
  }, z.core.$strict>;
89
90
  project: z.ZodOptional<z.ZodString>;
91
+ slug: z.ZodOptional<z.ZodString>;
90
92
  response: z.ZodOptional<z.ZodEnum<{
91
93
  full: "full";
92
94
  compact: "compact";
93
95
  }>>;
94
96
  }, z.core.$strict>;
95
- export declare const readSchema: z.ZodObject<{
97
+ export declare const readByIdSchema: z.ZodObject<{
96
98
  artifactId: z.ZodString;
97
99
  revisionId: z.ZodOptional<z.ZodString>;
98
100
  response: z.ZodOptional<z.ZodEnum<{
@@ -100,6 +102,16 @@ export declare const readSchema: z.ZodObject<{
100
102
  compact: "compact";
101
103
  }>>;
102
104
  }, z.core.$strict>;
105
+ export declare const readSchema: z.ZodObject<{
106
+ artifactId: z.ZodOptional<z.ZodString>;
107
+ project: z.ZodOptional<z.ZodString>;
108
+ slug: z.ZodOptional<z.ZodString>;
109
+ revisionId: z.ZodOptional<z.ZodString>;
110
+ response: z.ZodOptional<z.ZodEnum<{
111
+ full: "full";
112
+ compact: "compact";
113
+ }>>;
114
+ }, z.core.$strict>;
103
115
  export declare const updateSchema: z.ZodObject<{
104
116
  requestId: z.ZodString;
105
117
  artifactId: z.ZodString;
@@ -304,6 +316,7 @@ export type ArtifactSummary = {
304
316
  headRevisionId: string;
305
317
  createdAt: string;
306
318
  project: string | null;
319
+ slug: string | null;
307
320
  publication: Publication | null;
308
321
  };
309
322
  export type ProjectSummary = {
@@ -327,7 +340,7 @@ export type Archive = {
327
340
  base64: string;
328
341
  sha256: string;
329
342
  };
330
- export type ArtifactErrorCode = 'forbidden' | 'not_found' | 'conflict' | 'request_conflict' | 'invalid_grant';
343
+ export type ArtifactErrorCode = 'forbidden' | 'not_found' | 'conflict' | 'request_conflict' | 'slug_conflict' | 'invalid_grant';
331
344
  export declare class ArtifactError extends Error {
332
345
  readonly code: ArtifactErrorCode;
333
346
  readonly details: Record<string, unknown>;
@@ -381,6 +394,7 @@ export declare const artifactReadSchema: z.ZodObject<{
381
394
  ownerId: z.ZodString;
382
395
  headRevisionId: z.ZodString;
383
396
  project: z.ZodNullable<z.ZodString>;
397
+ slug: z.ZodNullable<z.ZodString>;
384
398
  publication: z.ZodNullable<z.ZodObject<{
385
399
  revisionId: z.ZodString;
386
400
  version: z.ZodNumber;
package/src/index.js CHANGED
@@ -122,8 +122,14 @@ export function parseCanvas(snapshot) {
122
122
  }
123
123
  export const projectNameSchema = z.string().normalize('NFC').trim().min(1).max(80).refine((name) => name.isWellFormed() && !/\p{Cc}/u.test(name), 'Use a project name without control characters');
124
124
  const response = z.enum(['full', 'compact']).optional();
125
- export const createSchema = z.strictObject({ requestId, snapshot: snapshotSchema, project: projectNameSchema.optional(), response });
126
- export const readSchema = z.strictObject({ artifactId: identifier, revisionId: identifier.optional(), response });
125
+ // The .md check aborts so a file-style name gets the suffix hint instead of the generic pattern message.
126
+ export const slugSchema = z.string().min(1).max(160)
127
+ .refine((slug) => !slug.endsWith('.md'), { message: 'Remove the .md suffix: a slug names a page, not a file', abort: true })
128
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*(\/[a-z0-9]+(-[a-z0-9]+)*)*$/, 'Use lowercase kebab-case segments separated by /, such as concepts/rag');
129
+ export const createSchema = z.strictObject({ requestId, snapshot: snapshotSchema, project: projectNameSchema.optional(), slug: slugSchema.optional(), response });
130
+ export const readByIdSchema = z.strictObject({ artifactId: identifier, revisionId: identifier.optional(), response });
131
+ export const readSchema = z.strictObject({ artifactId: identifier.optional(), project: projectNameSchema.optional(), slug: slugSchema.optional(), revisionId: identifier.optional(), response })
132
+ .refine((input) => (input.artifactId === undefined) !== (input.slug === undefined) && (input.project === undefined || input.slug !== undefined), 'Specify exactly one of artifactId or slug; project applies only with slug');
127
133
  export const updateSchema = z.strictObject({ requestId, artifactId: identifier, expectedRevisionId: identifier, snapshot: snapshotSchema, response });
128
134
  export const publishSchema = z.strictObject({ requestId, artifactId: identifier, revisionId: identifier, expectedPublicationVersion: z.number().int().nonnegative() });
129
135
  export const deleteSchema = z.strictObject({ requestId, artifactId: identifier, expectedRevisionId: identifier, expectedPublicationVersion: z.number().int().nonnegative() });
@@ -167,6 +173,6 @@ export function decodeFile(file) {
167
173
  }
168
174
  export const publicationSchema = z.strictObject({ revisionId: identifier, version: z.number().int().positive(), url: z.url() });
169
175
  export const revisionSchema = z.strictObject({ id: identifier, parentRevisionId: identifier.nullable(), sequence: z.number().int().positive(), authorUserId: identifier, authorClientId: identifier, createdAt: z.iso.datetime(), sha256: z.string().regex(/^[a-f0-9]{64}$/), snapshot: snapshotSchema });
170
- export const artifactReadSchema = z.strictObject({ artifactId: identifier, ownerId: identifier, headRevisionId: identifier, project: z.string().nullable(), publication: publicationSchema.nullable(), revision: revisionSchema });
176
+ export const artifactReadSchema = z.strictObject({ artifactId: identifier, ownerId: identifier, headRevisionId: identifier, project: z.string().nullable(), slug: z.string().nullable(), publication: publicationSchema.nullable(), revision: revisionSchema });
171
177
  export const sharedReadSchema = z.strictObject({ artifactId: identifier, ownerName: z.string().default('Usuario de Artifacts'), publication: publicationSchema, revision: revisionSchema.pick({ id: true, createdAt: true, sha256: true, snapshot: true }) });
172
178
  export const publishResultSchema = publicationSchema.extend({ artifactId: identifier });
package/src/workflow.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { ArtifactError, artifactReadSchema, createSchema, decodeFile, readSchema, snapshotSchema, updateSchema } from "./index.js";
2
+ import { ArtifactError, artifactReadSchema, createSchema, decodeFile, readByIdSchema, snapshotSchema, updateSchema } from "./index.js";
3
3
  import { canonicalJson, sha256 } from "./serialization.js";
4
4
  async function summarizeFiles(files) {
5
5
  return Promise.all([...files].sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0).map(async ({ path, mediaType, encoding, data }) => {
@@ -57,7 +57,7 @@ export async function compareRevisions(before, after) {
57
57
  };
58
58
  }
59
59
  const prepareEditSchema = z.strictObject({
60
- artifactId: readSchema.shape.artifactId,
60
+ artifactId: readByIdSchema.shape.artifactId,
61
61
  requestId: createSchema.shape.requestId,
62
62
  changes: z.strictObject({
63
63
  metadata: snapshotSchema.shape.metadata.partial().optional(),