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

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,7 +3,7 @@
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.5
6
+ npm install @yargote/artifacts-contracts@0.1.0-beta.7
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.
@@ -11,3 +11,5 @@ The root export contains domain schemas and types. `/workflow` contains `prepare
11
11
  The existing `@artifacts/artifacts` root, `/contracts`, and `/workflow` exports re-export these implementations. Store and REST packages share one `ArtifactError` runtime.
12
12
 
13
13
  This package is MIT licensed. The license applies to this package and does not license the private Artifacts application repository.
14
+
15
+ `shareSchema` accepts optional `notify` and `requireNew: true` without defaults. `shareResultSchema` remains the strict five-field grant shape used by lists. `shareCommandResultSchema` adds an optional immutable notification disposition for commands. Plain and explicit-false requests return the original grant shape. An absent flag and an explicit false remain distinct receipt arguments.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yargote/artifacts-contracts",
3
- "version": "0.1.0-beta.5",
3
+ "version": "0.1.0-beta.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Shared schemas and contracts for Artifacts clients.",
package/src/http.d.ts CHANGED
@@ -33,6 +33,7 @@ export declare const revisionSummarySchema: z.ZodObject<{
33
33
  text: "text";
34
34
  html: "html";
35
35
  markdown: "markdown";
36
+ design: "design";
36
37
  }>;
37
38
  utf8Bytes: z.ZodNumber;
38
39
  }, z.core.$strict>;
@@ -74,6 +75,7 @@ export declare const compactArtifactReadSchema: z.ZodObject<{
74
75
  text: "text";
75
76
  html: "html";
76
77
  markdown: "markdown";
78
+ design: "design";
77
79
  }>;
78
80
  utf8Bytes: z.ZodNumber;
79
81
  }, z.core.$strict>;
@@ -146,6 +148,7 @@ export declare const historyResultSchema: z.ZodObject<{
146
148
  text: "text";
147
149
  html: "html";
148
150
  markdown: "markdown";
151
+ design: "design";
149
152
  }>;
150
153
  text: z.ZodString;
151
154
  }, z.core.$strict>;
@@ -181,6 +184,7 @@ export declare const summaryHistoryResultSchema: z.ZodObject<{
181
184
  text: "text";
182
185
  html: "html";
183
186
  markdown: "markdown";
187
+ design: "design";
184
188
  }>;
185
189
  utf8Bytes: z.ZodNumber;
186
190
  }, z.core.$strict>;
package/src/http.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { z } from 'zod';
2
- import { artifactReadSchema, publicationSchema, revisionSchema, snapshotSchema } from "./index.js";
2
+ import { artifactReadSchema, contentKinds, publicationSchema, revisionSchema, snapshotSchema } from "./index.js";
3
3
  const identifier = z.string().min(1).max(128);
4
4
  const digest = z.string().regex(/^[a-f0-9]{64}$/);
5
5
  export const identitySchema = z.strictObject({ userId: identifier, sessionId: identifier, clientId: identifier, scopes: z.array(z.string()) });
6
6
  export const attachmentSummarySchema = z.strictObject({ path: z.string(), mediaType: z.string(), encoding: z.enum(['utf8', 'base64']), decodedBytes: z.number().int().nonnegative(), sha256: digest });
7
7
  export const revisionSummarySchema = revisionSchema.omit({ snapshot: true }).extend({
8
8
  metadata: snapshotSchema.shape.metadata.pick({ title: true, description: true }),
9
- content: z.strictObject({ kind: snapshotSchema.shape.content.shape.kind, utf8Bytes: z.number().int().nonnegative() }),
9
+ content: z.strictObject({ kind: z.enum(contentKinds), utf8Bytes: z.number().int().nonnegative() }),
10
10
  files: z.array(attachmentSummarySchema).max(32),
11
11
  });
12
12
  export const compactArtifactReadSchema = artifactReadSchema.omit({ revision: true }).extend({ revision: revisionSummarySchema });
package/src/index.d.ts CHANGED
@@ -1,4 +1,28 @@
1
1
  import { z } from 'zod';
2
+ export declare const contentKinds: readonly ["html", "markdown", "text", "design"];
3
+ export declare const canvasIndexSchema: z.ZodObject<{
4
+ v: z.ZodLiteral<1>;
5
+ boards: z.ZodPipe<z.ZodUnknown, z.ZodRecord<z.ZodString, z.ZodObject<{
6
+ x: z.ZodNumber;
7
+ y: z.ZodNumber;
8
+ w: z.ZodNumber;
9
+ h: z.ZodNumber;
10
+ title: z.ZodOptional<z.ZodString>;
11
+ page: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strict>>>;
13
+ order: z.ZodPipe<z.ZodArray<z.ZodUnknown>, z.ZodArray<z.ZodString>>;
14
+ notes: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodRecord<z.ZodString, z.ZodObject<{
15
+ x: z.ZodNumber;
16
+ y: z.ZodNumber;
17
+ text: z.ZodString;
18
+ w: z.ZodOptional<z.ZodNumber>;
19
+ page: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strict>>>>;
21
+ pages: z.ZodOptional<z.ZodPipe<z.ZodArray<z.ZodUnknown>, z.ZodArray<z.ZodObject<{
22
+ id: z.ZodString;
23
+ name: z.ZodString;
24
+ }, z.core.$strict>>>>;
25
+ }, z.core.$strict>;
2
26
  export declare const snapshotSchema: z.ZodObject<{
3
27
  metadata: z.ZodObject<{
4
28
  title: z.ZodString;
@@ -10,6 +34,7 @@ export declare const snapshotSchema: z.ZodObject<{
10
34
  text: "text";
11
35
  html: "html";
12
36
  markdown: "markdown";
37
+ design: "design";
13
38
  }>;
14
39
  text: z.ZodString;
15
40
  }, z.core.$strict>;
@@ -23,6 +48,16 @@ export declare const snapshotSchema: z.ZodObject<{
23
48
  data: z.ZodString;
24
49
  }, z.core.$strict>>;
25
50
  }, z.core.$strict>;
51
+ export type CanvasIndex = z.infer<typeof canvasIndexSchema>;
52
+ export type CanvasBoard = CanvasIndex['boards'][string] & {
53
+ path: string;
54
+ html: string;
55
+ };
56
+ export type Canvas = {
57
+ index: CanvasIndex;
58
+ boards: CanvasBoard[];
59
+ };
60
+ export declare function parseCanvas(snapshot: Pick<Snapshot, 'content' | 'files'>): Canvas;
26
61
  export declare const projectNameSchema: z.ZodString;
27
62
  export declare const createSchema: z.ZodObject<{
28
63
  requestId: z.ZodString;
@@ -37,6 +72,7 @@ export declare const createSchema: z.ZodObject<{
37
72
  text: "text";
38
73
  html: "html";
39
74
  markdown: "markdown";
75
+ design: "design";
40
76
  }>;
41
77
  text: z.ZodString;
42
78
  }, z.core.$strict>;
@@ -79,6 +115,7 @@ export declare const updateSchema: z.ZodObject<{
79
115
  text: "text";
80
116
  html: "html";
81
117
  markdown: "markdown";
118
+ design: "design";
82
119
  }>;
83
120
  text: z.ZodString;
84
121
  }, z.core.$strict>;
@@ -124,6 +161,63 @@ export declare const moveResultSchema: z.ZodObject<{
124
161
  project: z.ZodNullable<z.ZodString>;
125
162
  }, z.core.$strict>;
126
163
  export type MoveResult = z.infer<typeof moveResultSchema>;
164
+ export declare const shareSchema: z.ZodObject<{
165
+ requestId: z.ZodString;
166
+ artifactId: z.ZodString;
167
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
168
+ notify: z.ZodOptional<z.ZodBoolean>;
169
+ requireNew: z.ZodOptional<z.ZodLiteral<true>>;
170
+ }, z.core.$strict>;
171
+ export declare const unshareSchema: z.ZodObject<{
172
+ requestId: z.ZodString;
173
+ artifactId: z.ZodString;
174
+ shareId: z.ZodString;
175
+ }, z.core.$strict>;
176
+ export declare const listSharesSchema: z.ZodObject<{
177
+ artifactId: z.ZodString;
178
+ }, z.core.$strict>;
179
+ export declare const shareResultSchema: z.ZodObject<{
180
+ shareId: z.ZodString;
181
+ artifactId: z.ZodString;
182
+ kind: z.ZodLiteral<"email">;
183
+ value: z.ZodEmail;
184
+ createdAt: z.ZodISODateTime;
185
+ }, z.core.$strict>;
186
+ export declare const notificationSchema: z.ZodUnion<readonly [z.ZodObject<{
187
+ status: z.ZodLiteral<"requested">;
188
+ }, z.core.$strict>, z.ZodObject<{
189
+ status: z.ZodLiteral<"skipped">;
190
+ reason: z.ZodLiteral<"disabled">;
191
+ }, z.core.$strict>, z.ZodObject<{
192
+ status: z.ZodLiteral<"skipped">;
193
+ reason: z.ZodLiteral<"rate_limited">;
194
+ retryAt: z.ZodISODateTime;
195
+ }, z.core.$strict>]>;
196
+ export declare const shareCommandResultSchema: z.ZodObject<{
197
+ shareId: z.ZodString;
198
+ artifactId: z.ZodString;
199
+ kind: z.ZodLiteral<"email">;
200
+ value: z.ZodEmail;
201
+ createdAt: z.ZodISODateTime;
202
+ notification: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
203
+ status: z.ZodLiteral<"requested">;
204
+ }, z.core.$strict>, z.ZodObject<{
205
+ status: z.ZodLiteral<"skipped">;
206
+ reason: z.ZodLiteral<"disabled">;
207
+ }, z.core.$strict>, z.ZodObject<{
208
+ status: z.ZodLiteral<"skipped">;
209
+ reason: z.ZodLiteral<"rate_limited">;
210
+ retryAt: z.ZodISODateTime;
211
+ }, z.core.$strict>]>>;
212
+ }, z.core.$strict>;
213
+ export declare const unshareResultSchema: z.ZodObject<{
214
+ artifactId: z.ZodString;
215
+ shareId: z.ZodString;
216
+ }, z.core.$strict>;
217
+ export type Share = z.infer<typeof shareResultSchema>;
218
+ export type ShareResult = z.infer<typeof shareCommandResultSchema>;
219
+ export type Notification = z.infer<typeof notificationSchema>;
220
+ export type UnshareResult = z.infer<typeof unshareResultSchema>;
127
221
  export declare const exportSchema: z.ZodObject<{
128
222
  artifactId: z.ZodString;
129
223
  revisionId: z.ZodString;
@@ -197,6 +291,13 @@ export type Viewer = z.infer<typeof viewerSchema>;
197
291
  export type Publication = z.infer<typeof publicationSchema>;
198
292
  export type Revision = z.infer<typeof revisionSchema>;
199
293
  export type ArtifactRead = z.infer<typeof artifactReadSchema>;
294
+ export type SharedRead = z.infer<typeof sharedReadSchema>;
295
+ export type SharedArtifactSummary = Readonly<{
296
+ artifactId: string;
297
+ title: string;
298
+ ownerName: string;
299
+ url: string;
300
+ }>;
200
301
  export type ArtifactSummary = {
201
302
  artifactId: string;
202
303
  title: string;
@@ -260,6 +361,7 @@ export declare const revisionSchema: z.ZodObject<{
260
361
  text: "text";
261
362
  html: "html";
262
363
  markdown: "markdown";
364
+ design: "design";
263
365
  }>;
264
366
  text: z.ZodString;
265
367
  }, z.core.$strict>;
@@ -303,6 +405,46 @@ export declare const artifactReadSchema: z.ZodObject<{
303
405
  text: "text";
304
406
  html: "html";
305
407
  markdown: "markdown";
408
+ design: "design";
409
+ }>;
410
+ text: z.ZodString;
411
+ }, z.core.$strict>;
412
+ files: z.ZodArray<z.ZodObject<{
413
+ path: z.ZodString;
414
+ mediaType: z.ZodString;
415
+ encoding: z.ZodEnum<{
416
+ utf8: "utf8";
417
+ base64: "base64";
418
+ }>;
419
+ data: z.ZodString;
420
+ }, z.core.$strict>>;
421
+ }, z.core.$strict>;
422
+ }, z.core.$strict>;
423
+ }, z.core.$strict>;
424
+ export declare const sharedReadSchema: z.ZodObject<{
425
+ artifactId: z.ZodString;
426
+ ownerName: z.ZodDefault<z.ZodString>;
427
+ publication: z.ZodObject<{
428
+ revisionId: z.ZodString;
429
+ version: z.ZodNumber;
430
+ url: z.ZodURL;
431
+ }, z.core.$strict>;
432
+ revision: z.ZodObject<{
433
+ id: z.ZodString;
434
+ createdAt: z.ZodISODateTime;
435
+ sha256: z.ZodString;
436
+ snapshot: z.ZodObject<{
437
+ metadata: z.ZodObject<{
438
+ title: z.ZodString;
439
+ description: z.ZodString;
440
+ custom: z.ZodOptional<z.ZodJSONSchema>;
441
+ }, z.core.$strict>;
442
+ content: z.ZodObject<{
443
+ kind: z.ZodEnum<{
444
+ text: "text";
445
+ html: "html";
446
+ markdown: "markdown";
447
+ design: "design";
306
448
  }>;
307
449
  text: z.ZodString;
308
450
  }, z.core.$strict>;
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  const identifier = z.string().min(1).max(128);
3
3
  const requestId = z.string().min(8).max(128);
4
+ export const contentKinds = ['html', 'markdown', 'text', 'design'];
4
5
  const fileSchema = z.strictObject({
5
6
  path: z.string().min(1).max(240).refine((path) => path === path.normalize('NFC') && !/[:\\%\x00-\x1f\x7f]/.test(path) && path.split('/').every((part) => part !== '' && part !== '.' && part !== '..'), 'Use a normalized relative file path'),
6
7
  mediaType: z.string().max(128).regex(/^[a-zA-Z0-9!#$&^_.+-]+\/[a-zA-Z0-9!#$&^_.+-]+$/),
@@ -10,9 +11,63 @@ const fileSchema = z.strictObject({
10
11
  if (file.encoding === 'base64' && Buffer.from(file.data, 'base64').toString('base64') !== file.data)
11
12
  context.addIssue({ code: 'custom', path: ['data'], message: 'Use canonical padded base64' });
12
13
  });
14
+ const canvasId = z.string().regex(/^[A-Za-z0-9_-]{1,40}$/, 'Use 1 to 40 letters, digits, underscores, or hyphens').refine((id) => id !== '__proto__', 'Use an id other than __proto__');
15
+ const boardPath = z.string().regex(/^boards\/[A-Za-z0-9_][A-Za-z0-9_.-]*\.html$/, 'Use a board path such as boards/Home.html');
16
+ const coordinate = z.number().min(-1_000_000).max(1_000_000);
17
+ const extent = z.number().min(40).max(8000);
18
+ const label = z.string().min(1).max(256);
19
+ // An oversized count or a bad key aborts before any entry is parsed, so an oversized collection reports one issue.
20
+ // Keys are read from the raw object because a zod record skips a __proto__ key without checking it.
21
+ function keyed(key, value, max, noun) {
22
+ return z.unknown().superRefine((input, context) => {
23
+ if (typeof input !== 'object' || input === null || Array.isArray(input))
24
+ return;
25
+ const keys = Object.keys(input);
26
+ if (keys.length > max) {
27
+ context.addIssue({ code: 'too_big', origin: 'object', maximum: max, inclusive: true, input, continue: false, message: `A canvas holds at most ${max} ${noun}` });
28
+ return;
29
+ }
30
+ for (const name of keys) {
31
+ const result = key.safeParse(name);
32
+ if (!result.success)
33
+ context.addIssue({ code: 'invalid_key', origin: 'record', issues: result.error.issues, input: name, path: [name], continue: false, message: result.error.issues[0].message });
34
+ }
35
+ }).pipe(z.record(z.string(), value));
36
+ }
37
+ export const canvasIndexSchema = z.strictObject({
38
+ v: z.literal(1),
39
+ boards: keyed(boardPath, z.strictObject({ x: coordinate, y: coordinate, w: extent, h: extent, title: label.optional(), page: canvasId.optional() }), 32, 'boards'),
40
+ order: z.array(z.unknown()).min(1, 'A canvas needs at least one board').max(32, { message: 'A canvas holds at most 32 boards', abort: true }).pipe(z.array(boardPath)),
41
+ notes: keyed(canvasId, z.strictObject({ x: coordinate, y: coordinate, text: z.string(), w: extent.optional(), page: canvasId.optional() }), 200, 'notes').optional(),
42
+ pages: z.array(z.unknown()).max(32, { message: 'A canvas holds at most 32 pages', abort: true }).pipe(z.array(z.strictObject({ id: canvasId, name: label }))).optional(),
43
+ }).superRefine((index, context) => {
44
+ const ordered = new Set();
45
+ index.order.forEach((path, position) => {
46
+ if (!Object.hasOwn(index.boards, path))
47
+ context.addIssue({ code: 'custom', path: ['order', position], message: `Canvas order names ${path}, which is not a board` });
48
+ else if (ordered.has(path))
49
+ context.addIssue({ code: 'custom', path: ['order', position], message: `Canvas order lists ${path} more than once` });
50
+ ordered.add(path);
51
+ });
52
+ for (const path of Object.keys(index.boards))
53
+ if (!ordered.has(path))
54
+ context.addIssue({ code: 'custom', path: ['order'], message: `Canvas order omits board ${path}` });
55
+ const pages = new Set();
56
+ index.pages?.forEach(({ id }, position) => {
57
+ if (pages.has(id))
58
+ context.addIssue({ code: 'custom', path: ['pages', position, 'id'], message: `Canvas page ${id} is declared more than once` });
59
+ pages.add(id);
60
+ });
61
+ for (const [path, board] of Object.entries(index.boards))
62
+ if (board.page !== undefined && !pages.has(board.page))
63
+ context.addIssue({ code: 'custom', path: ['boards', path, 'page'], message: `Canvas board ${path} names unknown page ${board.page}` });
64
+ for (const [id, note] of Object.entries(index.notes ?? {}))
65
+ if (note.page !== undefined && !pages.has(note.page))
66
+ context.addIssue({ code: 'custom', path: ['notes', id, 'page'], message: `Canvas note ${id} names unknown page ${note.page}` });
67
+ });
13
68
  export const snapshotSchema = z.strictObject({
14
69
  metadata: z.strictObject({ title: z.string().min(1).max(256), description: z.string().max(8192), custom: z.json().optional() }),
15
- content: z.strictObject({ kind: z.enum(['html', 'markdown', 'text']), text: z.string().max(1_048_576).refine((text) => text.isWellFormed(), 'Content must contain well-formed Unicode') }),
70
+ content: z.strictObject({ kind: z.enum(contentKinds), text: z.string().max(1_048_576).refine((text) => text.isWellFormed(), 'Content must contain well-formed Unicode') }),
16
71
  files: z.array(fileSchema).max(32),
17
72
  }).superRefine((snapshot, context) => {
18
73
  const paths = snapshot.files.map((file) => file.path);
@@ -21,7 +76,50 @@ export const snapshotSchema = z.strictObject({
21
76
  const bytes = Buffer.byteLength(JSON.stringify(snapshot.metadata)) + Buffer.byteLength(snapshot.content.text) + snapshot.files.reduce((total, file) => total + Buffer.byteLength(file.path) + Buffer.byteLength(file.mediaType) + decodeFile(file).length, 0);
22
77
  if (bytes > 1_048_576)
23
78
  context.addIssue({ code: 'custom', message: 'A revision must fit within 1 MiB of decoded content and metadata' });
79
+ // A request body can reach 8 MiB, so the index of an oversized design is not parsed.
80
+ if (snapshot.content.kind !== 'design' || bytes > 1_048_576)
81
+ return;
82
+ const canvas = readCanvas(snapshot);
83
+ if (!canvas.success)
84
+ for (const issue of canvas.issues)
85
+ context.addIssue({ ...issue });
24
86
  });
87
+ function readCanvas({ content, files }) {
88
+ let value;
89
+ try {
90
+ value = JSON.parse(content.text);
91
+ }
92
+ catch {
93
+ return { success: false, issues: [{ code: 'custom', path: ['content', 'text'], message: 'Design content must be a canvas index in JSON' }] };
94
+ }
95
+ const index = canvasIndexSchema.safeParse(value);
96
+ if (!index.success)
97
+ return { success: false, issues: index.error.issues.map((issue) => ({ ...issue, path: ['content', 'text', ...issue.path] })) };
98
+ const positions = new Map(files.map((file, position) => [file.path, position]));
99
+ const boards = [];
100
+ const issues = [];
101
+ for (const path of index.data.order) {
102
+ const position = positions.get(path);
103
+ if (position === undefined) {
104
+ issues.push({ code: 'custom', path: ['content', 'text', 'boards', path], message: `Canvas board ${path} has no matching file` });
105
+ continue;
106
+ }
107
+ const file = files[position];
108
+ if (file.mediaType !== 'text/html' || file.encoding !== 'utf8')
109
+ issues.push({ code: 'custom', path: ['files', position], message: `Canvas board ${path} must be a text/html file with utf8 encoding` });
110
+ else
111
+ boards.push({ ...index.data.boards[path], path, html: file.data });
112
+ }
113
+ return issues.length ? { success: false, issues } : { success: true, data: { index: index.data, boards } };
114
+ }
115
+ export function parseCanvas(snapshot) {
116
+ if (snapshot.content.kind !== 'design')
117
+ throw new TypeError('Only a design snapshot has a canvas');
118
+ const canvas = readCanvas(snapshot);
119
+ if (!canvas.success)
120
+ throw new z.ZodError(canvas.issues);
121
+ return canvas.data;
122
+ }
25
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');
26
124
  const response = z.enum(['full', 'compact']).optional();
27
125
  export const createSchema = z.strictObject({ requestId, snapshot: snapshotSchema, project: projectNameSchema.optional(), response });
@@ -32,6 +130,17 @@ export const deleteSchema = z.strictObject({ requestId, artifactId: identifier,
32
130
  export const deleteResultSchema = z.strictObject({ artifactId: identifier });
33
131
  export const moveSchema = z.strictObject({ requestId, artifactId: identifier, project: projectNameSchema.nullable() });
34
132
  export const moveResultSchema = z.strictObject({ artifactId: identifier, project: z.string().nullable() });
133
+ export const shareSchema = z.strictObject({ requestId, artifactId: identifier, email: z.string().trim().toLowerCase().pipe(z.email().max(254)).meta({ format: 'email', description: 'Email address, trimmed and lowercased; at most 254 characters after trimming' }), notify: z.boolean().optional(), requireNew: z.literal(true).optional() });
134
+ export const unshareSchema = z.strictObject({ requestId, artifactId: identifier, shareId: identifier });
135
+ export const listSharesSchema = z.strictObject({ artifactId: identifier });
136
+ export const shareResultSchema = z.strictObject({ shareId: identifier, artifactId: identifier, kind: z.literal('email'), value: z.email(), createdAt: z.iso.datetime() });
137
+ export const notificationSchema = z.union([
138
+ z.strictObject({ status: z.literal('requested') }),
139
+ z.strictObject({ status: z.literal('skipped'), reason: z.literal('disabled') }),
140
+ z.strictObject({ status: z.literal('skipped'), reason: z.literal('rate_limited'), retryAt: z.iso.datetime() }),
141
+ ]);
142
+ export const shareCommandResultSchema = shareResultSchema.extend({ notification: notificationSchema.optional() });
143
+ export const unshareResultSchema = z.strictObject({ artifactId: identifier, shareId: identifier });
35
144
  export const exportSchema = z.strictObject({ artifactId: identifier, revisionId: identifier });
36
145
  export const listSchema = z.strictObject({ limit: z.number().int().min(1).max(100).default(25), cursor: identifier.optional(), project: projectNameSchema.optional() });
37
146
  export const libraryQuerySchema = z.strictObject({
@@ -59,4 +168,5 @@ export function decodeFile(file) {
59
168
  export const publicationSchema = z.strictObject({ revisionId: identifier, version: z.number().int().positive(), url: z.url() });
60
169
  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 });
61
170
  export const artifactReadSchema = z.strictObject({ artifactId: identifier, ownerId: identifier, headRevisionId: identifier, project: z.string().nullable(), publication: publicationSchema.nullable(), revision: revisionSchema });
171
+ 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 }) });
62
172
  export const publishResultSchema = publicationSchema.extend({ artifactId: identifier });