artifact-cafe 0.0.11 → 0.0.12
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/dist/index.js +599 -459
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -100,10 +100,22 @@ var workspaceAvatarResponseSchema = z2.object({
|
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
// ../shared/src/comments.ts
|
|
103
|
-
import { z as
|
|
103
|
+
import { z as z5 } from "zod";
|
|
104
104
|
|
|
105
105
|
// ../shared/src/publish.ts
|
|
106
|
+
import { z as z4 } from "zod";
|
|
107
|
+
|
|
108
|
+
// ../shared/src/review-mode.ts
|
|
106
109
|
import { z as z3 } from "zod";
|
|
110
|
+
var reviewModeSchema = z3.enum(["open", "readonly", "off"]);
|
|
111
|
+
var setReviewModeSchema = z3.object({
|
|
112
|
+
mode: reviewModeSchema
|
|
113
|
+
});
|
|
114
|
+
var reviewModeResponseSchema = z3.object({
|
|
115
|
+
mode: reviewModeSchema
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ../shared/src/publish.ts
|
|
107
119
|
function isSafeArtifactPath(p) {
|
|
108
120
|
if (p.length === 0 || p.length > 1024) {
|
|
109
121
|
return false;
|
|
@@ -116,140 +128,142 @@ function isSafeArtifactPath(p) {
|
|
|
116
128
|
}
|
|
117
129
|
return p.split("/").every((seg) => seg.length > 0 && seg !== "." && seg !== "..");
|
|
118
130
|
}
|
|
119
|
-
var manifestFileSchema =
|
|
120
|
-
hash:
|
|
121
|
-
mimeType:
|
|
122
|
-
path:
|
|
131
|
+
var manifestFileSchema = z4.object({
|
|
132
|
+
hash: z4.string().regex(/^sha256_[a-f0-9]{64}$/),
|
|
133
|
+
mimeType: z4.string().regex(/^[-\w.+]+\/[-\w.+]+$/, { message: "invalid MIME type" }),
|
|
134
|
+
path: z4.string().min(1).max(1024).refine(isSafeArtifactPath, {
|
|
123
135
|
message: "path must be a safe relative path"
|
|
124
136
|
}),
|
|
125
|
-
size:
|
|
137
|
+
size: z4.number().int().positive()
|
|
126
138
|
});
|
|
127
|
-
var publishSourceSchema =
|
|
128
|
-
agent:
|
|
129
|
-
runId:
|
|
130
|
-
type:
|
|
139
|
+
var publishSourceSchema = z4.object({
|
|
140
|
+
agent: z4.string().optional(),
|
|
141
|
+
runId: z4.string().optional(),
|
|
142
|
+
type: z4.literal("cli")
|
|
131
143
|
});
|
|
132
|
-
var createPublishSessionSchema =
|
|
133
|
-
artifactId:
|
|
134
|
-
entryPath:
|
|
135
|
-
files:
|
|
144
|
+
var createPublishSessionSchema = z4.object({
|
|
145
|
+
artifactId: z4.string().nullable(),
|
|
146
|
+
entryPath: z4.string().optional(),
|
|
147
|
+
files: z4.array(manifestFileSchema).min(1).max(1e3),
|
|
136
148
|
// SPEC-2 §6.4 — workspace placement is available only to authenticated
|
|
137
149
|
// members; the API enforces membership and folder ownership. folderId
|
|
138
150
|
// without workspaceId resolves against the account's personal workspace.
|
|
139
|
-
folderId:
|
|
151
|
+
folderId: z4.string().min(1).optional(),
|
|
140
152
|
// Bullet-point changelog for this version, authored by the publisher.
|
|
141
153
|
// Optional on every publish (incl. v1); stored immutably on the version.
|
|
142
|
-
notes:
|
|
154
|
+
notes: z4.string().max(4e3).optional(),
|
|
143
155
|
source: publishSourceSchema,
|
|
144
|
-
title:
|
|
145
|
-
workspaceId:
|
|
146
|
-
});
|
|
147
|
-
var publishSessionResponseSchema =
|
|
148
|
-
artifactId:
|
|
149
|
-
expiresAt:
|
|
150
|
-
filesToUpload:
|
|
151
|
-
|
|
152
|
-
method:
|
|
153
|
-
path:
|
|
154
|
-
uploadUrl:
|
|
156
|
+
title: z4.string().max(200).optional(),
|
|
157
|
+
workspaceId: z4.string().min(1).optional()
|
|
158
|
+
});
|
|
159
|
+
var publishSessionResponseSchema = z4.object({
|
|
160
|
+
artifactId: z4.string(),
|
|
161
|
+
expiresAt: z4.string(),
|
|
162
|
+
filesToUpload: z4.array(
|
|
163
|
+
z4.object({
|
|
164
|
+
method: z4.literal("PUT"),
|
|
165
|
+
path: z4.string(),
|
|
166
|
+
uploadUrl: z4.string().url()
|
|
155
167
|
})
|
|
156
168
|
),
|
|
157
|
-
publishSessionId:
|
|
158
|
-
skippedFiles:
|
|
159
|
-
versionId:
|
|
169
|
+
publishSessionId: z4.string(),
|
|
170
|
+
skippedFiles: z4.array(z4.string()),
|
|
171
|
+
versionId: z4.string()
|
|
160
172
|
});
|
|
161
|
-
var finalizeResponseSchema =
|
|
162
|
-
artifactId:
|
|
173
|
+
var finalizeResponseSchema = z4.object({
|
|
174
|
+
artifactId: z4.string(),
|
|
163
175
|
// API-key publishes create the artifact already claimed (SPEC §5.4) —
|
|
164
176
|
// the CLI uses this to tell "claim URL pending" from "already yours".
|
|
165
|
-
claimed:
|
|
177
|
+
claimed: z4.boolean(),
|
|
166
178
|
// Returned only on first publish of a new artifact (one-time).
|
|
167
|
-
claimUrl:
|
|
168
|
-
publishToken:
|
|
169
|
-
url:
|
|
170
|
-
versionId:
|
|
171
|
-
versionNumber:
|
|
172
|
-
});
|
|
173
|
-
var artifactResponseSchema =
|
|
174
|
-
claimed:
|
|
175
|
-
currentVersion:
|
|
176
|
-
entryUrl:
|
|
177
|
-
id:
|
|
178
|
-
versionNumber:
|
|
179
|
+
claimUrl: z4.string().url().optional(),
|
|
180
|
+
publishToken: z4.string().optional(),
|
|
181
|
+
url: z4.string().url(),
|
|
182
|
+
versionId: z4.string(),
|
|
183
|
+
versionNumber: z4.number().int().positive()
|
|
184
|
+
});
|
|
185
|
+
var artifactResponseSchema = z4.object({
|
|
186
|
+
claimed: z4.boolean(),
|
|
187
|
+
currentVersion: z4.object({
|
|
188
|
+
entryUrl: z4.string().url(),
|
|
189
|
+
id: z4.string(),
|
|
190
|
+
versionNumber: z4.number().int().positive()
|
|
179
191
|
}).nullable(),
|
|
180
192
|
// SPEC-2 §6.4 — placement + visibility surface on the artifact.
|
|
181
|
-
folderId:
|
|
182
|
-
id:
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
193
|
+
folderId: z4.string().nullable(),
|
|
194
|
+
id: z4.string(),
|
|
195
|
+
// SPEC-2 §5.8 — what a viewer may do once in (open / readonly / off).
|
|
196
|
+
reviewMode: reviewModeSchema,
|
|
197
|
+
slug: z4.string(),
|
|
198
|
+
title: z4.string(),
|
|
199
|
+
visibility: z4.enum(["public", "unlisted", "workspace", "private"]),
|
|
200
|
+
workspaceId: z4.string().nullable()
|
|
187
201
|
});
|
|
188
202
|
|
|
189
203
|
// ../shared/src/comments.ts
|
|
190
|
-
var anchorPageSchema =
|
|
204
|
+
var anchorPageSchema = z5.string().max(1024).refine(isSafeArtifactPath, {
|
|
191
205
|
message: "page must be a safe relative path"
|
|
192
206
|
}).optional();
|
|
193
|
-
var elementSnapshotSchema =
|
|
194
|
-
classes:
|
|
195
|
-
id:
|
|
196
|
-
tag:
|
|
197
|
-
text:
|
|
207
|
+
var elementSnapshotSchema = z5.object({
|
|
208
|
+
classes: z5.string().max(256).optional(),
|
|
209
|
+
id: z5.string().max(256).optional(),
|
|
210
|
+
tag: z5.string().min(1).max(128),
|
|
211
|
+
text: z5.string().max(200).optional()
|
|
198
212
|
});
|
|
199
|
-
var pointAnchorSchema =
|
|
213
|
+
var pointAnchorSchema = z5.object({
|
|
200
214
|
element: elementSnapshotSchema.optional(),
|
|
201
215
|
// elementPath is the primary anchor; x/y are offsets within the
|
|
202
216
|
// element's box, normalized 0..1 (SPEC.md §8.1).
|
|
203
|
-
elementPath:
|
|
217
|
+
elementPath: z5.string().max(2048),
|
|
204
218
|
page: anchorPageSchema,
|
|
205
|
-
type:
|
|
206
|
-
viewportHeight:
|
|
207
|
-
viewportWidth:
|
|
208
|
-
x:
|
|
209
|
-
y:
|
|
210
|
-
});
|
|
211
|
-
var textAnchorSchema =
|
|
212
|
-
elementPath:
|
|
213
|
-
endOffset:
|
|
219
|
+
type: z5.literal("point"),
|
|
220
|
+
viewportHeight: z5.number().int().positive().max(1e5),
|
|
221
|
+
viewportWidth: z5.number().int().positive().max(1e5),
|
|
222
|
+
x: z5.number().min(0).max(1),
|
|
223
|
+
y: z5.number().min(0).max(1)
|
|
224
|
+
});
|
|
225
|
+
var textAnchorSchema = z5.object({
|
|
226
|
+
elementPath: z5.string().max(2048),
|
|
227
|
+
endOffset: z5.number().int().nonnegative().max(1e8),
|
|
214
228
|
page: anchorPageSchema,
|
|
215
|
-
prefix:
|
|
216
|
-
quote:
|
|
217
|
-
startOffset:
|
|
218
|
-
suffix:
|
|
219
|
-
type:
|
|
229
|
+
prefix: z5.string().max(200).optional(),
|
|
230
|
+
quote: z5.string().min(1).max(1e3),
|
|
231
|
+
startOffset: z5.number().int().nonnegative().max(1e8),
|
|
232
|
+
suffix: z5.string().max(200).optional(),
|
|
233
|
+
type: z5.literal("text")
|
|
220
234
|
});
|
|
221
|
-
var pageAnchorSchema =
|
|
235
|
+
var pageAnchorSchema = z5.object({
|
|
222
236
|
page: anchorPageSchema,
|
|
223
|
-
type:
|
|
237
|
+
type: z5.literal("page")
|
|
224
238
|
});
|
|
225
|
-
var anchorSchema =
|
|
239
|
+
var anchorSchema = z5.discriminatedUnion("type", [
|
|
226
240
|
pointAnchorSchema,
|
|
227
241
|
textAnchorSchema,
|
|
228
242
|
pageAnchorSchema
|
|
229
243
|
]);
|
|
230
|
-
var displayNameSchema =
|
|
231
|
-
var guestSchema =
|
|
244
|
+
var displayNameSchema = z5.string().trim().min(1).max(64);
|
|
245
|
+
var guestSchema = z5.object({
|
|
232
246
|
displayName: displayNameSchema,
|
|
233
|
-
guestId:
|
|
247
|
+
guestId: z5.string().min(16)
|
|
234
248
|
});
|
|
235
|
-
var viaLabelSchema =
|
|
236
|
-
var createCommentThreadSchema =
|
|
249
|
+
var viaLabelSchema = z5.string().trim().min(1).max(64);
|
|
250
|
+
var createCommentThreadSchema = z5.object({
|
|
237
251
|
anchor: anchorSchema,
|
|
238
|
-
body:
|
|
252
|
+
body: z5.string().min(1).max(1e4),
|
|
239
253
|
guest: guestSchema.optional(),
|
|
240
|
-
versionId:
|
|
254
|
+
versionId: z5.string(),
|
|
241
255
|
via: viaLabelSchema.optional()
|
|
242
256
|
});
|
|
243
|
-
var createCommentMessageSchema =
|
|
244
|
-
body:
|
|
257
|
+
var createCommentMessageSchema = z5.object({
|
|
258
|
+
body: z5.string().min(1).max(1e4),
|
|
245
259
|
guest: guestSchema.optional(),
|
|
246
260
|
via: viaLabelSchema.optional()
|
|
247
261
|
});
|
|
248
|
-
var editCommentMessageSchema =
|
|
249
|
-
body:
|
|
262
|
+
var editCommentMessageSchema = z5.object({
|
|
263
|
+
body: z5.string().min(1).max(1e4),
|
|
250
264
|
guest: guestSchema.optional()
|
|
251
265
|
});
|
|
252
|
-
var threadActionSchema =
|
|
266
|
+
var threadActionSchema = z5.object({
|
|
253
267
|
guest: guestSchema.optional()
|
|
254
268
|
});
|
|
255
269
|
var SINGLE_EMOJI = new RegExp("^\\p{RGI_Emoji}$", "v");
|
|
@@ -257,117 +271,117 @@ var REDUNDANT_VS16 = new RegExp("(\\p{Emoji_Presentation})\\uFE0F", "gu");
|
|
|
257
271
|
function canonicalizeEmoji(s) {
|
|
258
272
|
return s.replace(REDUNDANT_VS16, "$1");
|
|
259
273
|
}
|
|
260
|
-
var reactionEmojiSchema =
|
|
261
|
-
var toggleReactionSchema =
|
|
274
|
+
var reactionEmojiSchema = z5.string().max(64).transform(canonicalizeEmoji).refine((s) => SINGLE_EMOJI.test(s), { message: "Must be a single emoji." }).describe("A single emoji, e.g. \u{1F44D}");
|
|
275
|
+
var toggleReactionSchema = z5.object({
|
|
262
276
|
emoji: reactionEmojiSchema,
|
|
263
277
|
guest: guestSchema.optional()
|
|
264
278
|
});
|
|
265
|
-
var commentAuthorSchema =
|
|
266
|
-
avatarUrl:
|
|
267
|
-
displayName:
|
|
268
|
-
guestId:
|
|
269
|
-
isViewer:
|
|
270
|
-
kind:
|
|
279
|
+
var commentAuthorSchema = z5.object({
|
|
280
|
+
avatarUrl: z5.string().nullable(),
|
|
281
|
+
displayName: z5.string(),
|
|
282
|
+
guestId: z5.string().nullable(),
|
|
283
|
+
isViewer: z5.boolean(),
|
|
284
|
+
kind: z5.enum(["member", "guest"]),
|
|
271
285
|
// Optional "via" attribution (§6.4). Null for plain comments; a bounded
|
|
272
286
|
// label the shell appends after the display name.
|
|
273
|
-
via:
|
|
287
|
+
via: z5.string().nullable()
|
|
274
288
|
});
|
|
275
|
-
var messageReactionSchema =
|
|
276
|
-
emoji:
|
|
277
|
-
reactors:
|
|
289
|
+
var messageReactionSchema = z5.object({
|
|
290
|
+
emoji: z5.string(),
|
|
291
|
+
reactors: z5.array(commentAuthorSchema)
|
|
278
292
|
});
|
|
279
|
-
var commentMessageSchema =
|
|
293
|
+
var commentMessageSchema = z5.object({
|
|
280
294
|
author: commentAuthorSchema,
|
|
281
295
|
// Empty string for a deleted message — the body is stripped server-side
|
|
282
296
|
// (§6.7.1 tombstone), never sent to the client and hidden there.
|
|
283
|
-
body:
|
|
284
|
-
createdAt:
|
|
297
|
+
body: z5.string(),
|
|
298
|
+
createdAt: z5.string(),
|
|
285
299
|
// Soft-deleted (§6.7.1). A tombstone keeps thread structure and replies;
|
|
286
300
|
// the shell renders "Comment deleted" instead of the (absent) body.
|
|
287
|
-
deleted:
|
|
301
|
+
deleted: z5.boolean(),
|
|
288
302
|
// Last edit time (§6.7.1), or null if never edited — drives the "edited"
|
|
289
303
|
// badge. No edit history is kept.
|
|
290
|
-
editedAt:
|
|
291
|
-
id:
|
|
304
|
+
editedAt: z5.string().nullable(),
|
|
305
|
+
id: z5.string(),
|
|
292
306
|
// Defaulted, not required: a new CLI parsing an older server's
|
|
293
307
|
// response must not fail on the missing key.
|
|
294
|
-
reactions:
|
|
308
|
+
reactions: z5.array(messageReactionSchema).default([])
|
|
295
309
|
});
|
|
296
|
-
var threadActorSchema =
|
|
297
|
-
displayName:
|
|
298
|
-
kind:
|
|
310
|
+
var threadActorSchema = z5.object({
|
|
311
|
+
displayName: z5.string(),
|
|
312
|
+
kind: z5.enum(["member", "guest", "agent"])
|
|
299
313
|
});
|
|
300
|
-
var commentThreadSchema =
|
|
314
|
+
var commentThreadSchema = z5.object({
|
|
301
315
|
// §6.6.1 — set while open to signal "seen, working on it"; cleared on
|
|
302
316
|
// reopen, kept (but superseded in display) once resolved. Defaulted so
|
|
303
317
|
// clients parsing an older server's response don't fail.
|
|
304
|
-
acknowledgedAt:
|
|
318
|
+
acknowledgedAt: z5.string().nullable().default(null),
|
|
305
319
|
acknowledgedBy: threadActorSchema.nullable().default(null),
|
|
306
320
|
anchor: anchorSchema,
|
|
307
|
-
artifactId:
|
|
308
|
-
createdAt:
|
|
321
|
+
artifactId: z5.string(),
|
|
322
|
+
createdAt: z5.string(),
|
|
309
323
|
createdBy: commentAuthorSchema,
|
|
310
|
-
id:
|
|
311
|
-
messages:
|
|
324
|
+
id: z5.string(),
|
|
325
|
+
messages: z5.array(commentMessageSchema),
|
|
312
326
|
// Null on threads resolved before actor recording existed, and always
|
|
313
327
|
// null while open.
|
|
314
328
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
315
|
-
status:
|
|
316
|
-
versionId:
|
|
329
|
+
status: z5.enum(["open", "resolved"]),
|
|
330
|
+
versionId: z5.string()
|
|
317
331
|
});
|
|
318
|
-
var commentThreadListSchema =
|
|
319
|
-
threads:
|
|
332
|
+
var commentThreadListSchema = z5.object({
|
|
333
|
+
threads: z5.array(commentThreadSchema)
|
|
320
334
|
});
|
|
321
|
-
var commentExportQuerySchema =
|
|
322
|
-
status:
|
|
323
|
-
version:
|
|
335
|
+
var commentExportQuerySchema = z5.object({
|
|
336
|
+
status: z5.enum(["open", "resolved", "all"]).default("open"),
|
|
337
|
+
version: z5.enum(["current", "all"]).default("current")
|
|
324
338
|
});
|
|
325
|
-
var exportReactionSchema =
|
|
326
|
-
count:
|
|
327
|
-
emoji:
|
|
339
|
+
var exportReactionSchema = z5.object({
|
|
340
|
+
count: z5.number().int().positive(),
|
|
341
|
+
emoji: z5.string()
|
|
328
342
|
});
|
|
329
|
-
var commentExportReplySchema =
|
|
330
|
-
author:
|
|
331
|
-
authorKind:
|
|
332
|
-
body:
|
|
333
|
-
createdAt:
|
|
343
|
+
var commentExportReplySchema = z5.object({
|
|
344
|
+
author: z5.string(),
|
|
345
|
+
authorKind: z5.enum(["member", "guest"]),
|
|
346
|
+
body: z5.string(),
|
|
347
|
+
createdAt: z5.string(),
|
|
334
348
|
// Soft-delete tombstone (§6.7.1): body is "" when true.
|
|
335
|
-
deleted:
|
|
336
|
-
editedAt:
|
|
349
|
+
deleted: z5.boolean(),
|
|
350
|
+
editedAt: z5.string().nullable(),
|
|
337
351
|
// The message id — what `edit`/`delete` target (§5.1).
|
|
338
|
-
id:
|
|
339
|
-
reactions:
|
|
352
|
+
id: z5.string(),
|
|
353
|
+
reactions: z5.array(exportReactionSchema).optional()
|
|
340
354
|
});
|
|
341
|
-
var commentExportThreadSchema =
|
|
355
|
+
var commentExportThreadSchema = z5.object({
|
|
342
356
|
// §6.6.1 — lets a polling agent skip threads it already acknowledged
|
|
343
357
|
// (acknowledged threads stay in status=open exports on purpose).
|
|
344
|
-
acknowledgedAt:
|
|
358
|
+
acknowledgedAt: z5.string().nullable().default(null),
|
|
345
359
|
anchor: anchorSchema,
|
|
346
|
-
author:
|
|
347
|
-
authorKind:
|
|
348
|
-
body:
|
|
349
|
-
createdAt:
|
|
350
|
-
deleted:
|
|
351
|
-
editedAt:
|
|
352
|
-
id:
|
|
360
|
+
author: z5.string(),
|
|
361
|
+
authorKind: z5.enum(["member", "guest"]),
|
|
362
|
+
body: z5.string(),
|
|
363
|
+
createdAt: z5.string(),
|
|
364
|
+
deleted: z5.boolean(),
|
|
365
|
+
editedAt: z5.string().nullable(),
|
|
366
|
+
id: z5.string(),
|
|
353
367
|
// The opening message's id (distinct from the thread `id`) — `edit`/
|
|
354
368
|
// `delete` operate on messages, so the CLI needs it to target the first
|
|
355
369
|
// comment, not just the replies.
|
|
356
|
-
messageId:
|
|
357
|
-
reactions:
|
|
358
|
-
replies:
|
|
370
|
+
messageId: z5.string(),
|
|
371
|
+
reactions: z5.array(exportReactionSchema).optional(),
|
|
372
|
+
replies: z5.array(commentExportReplySchema),
|
|
359
373
|
resolvedBy: threadActorSchema.nullable().default(null),
|
|
360
|
-
status:
|
|
361
|
-
versionNumber:
|
|
374
|
+
status: z5.enum(["open", "resolved"]),
|
|
375
|
+
versionNumber: z5.number().int().positive()
|
|
362
376
|
});
|
|
363
|
-
var commentExportSchema =
|
|
364
|
-
artifactId:
|
|
365
|
-
comments:
|
|
377
|
+
var commentExportSchema = z5.object({
|
|
378
|
+
artifactId: z5.string(),
|
|
379
|
+
comments: z5.array(commentExportThreadSchema),
|
|
366
380
|
// The artifact's current version (null before the first finalize).
|
|
367
|
-
versionNumber:
|
|
381
|
+
versionNumber: z5.number().int().positive().nullable()
|
|
368
382
|
});
|
|
369
|
-
var commentReadResponseSchema =
|
|
370
|
-
lastSeenAt:
|
|
383
|
+
var commentReadResponseSchema = z5.object({
|
|
384
|
+
lastSeenAt: z5.string()
|
|
371
385
|
});
|
|
372
386
|
function elementLabel(el) {
|
|
373
387
|
if (el.id) {
|
|
@@ -378,228 +392,228 @@ function elementLabel(el) {
|
|
|
378
392
|
}
|
|
379
393
|
|
|
380
394
|
// ../shared/src/errors.ts
|
|
381
|
-
import { z as
|
|
382
|
-
var apiErrorSchema =
|
|
383
|
-
code:
|
|
384
|
-
docsUrl:
|
|
385
|
-
message:
|
|
386
|
-
retryAfter:
|
|
395
|
+
import { z as z6 } from "zod";
|
|
396
|
+
var apiErrorSchema = z6.object({
|
|
397
|
+
code: z6.string(),
|
|
398
|
+
docsUrl: z6.string().url(),
|
|
399
|
+
message: z6.string(),
|
|
400
|
+
retryAfter: z6.number().int().positive().optional()
|
|
387
401
|
});
|
|
388
402
|
|
|
389
403
|
// ../shared/src/feedback.ts
|
|
390
|
-
import { z as
|
|
391
|
-
var feedbackRequestSchema =
|
|
392
|
-
email:
|
|
393
|
-
message:
|
|
404
|
+
import { z as z7 } from "zod";
|
|
405
|
+
var feedbackRequestSchema = z7.object({
|
|
406
|
+
email: z7.string().trim().toLowerCase().email().optional().or(z7.literal("")),
|
|
407
|
+
message: z7.string().trim().min(1).max(4e3)
|
|
394
408
|
});
|
|
395
|
-
var feedbackResponseSchema =
|
|
396
|
-
sent:
|
|
409
|
+
var feedbackResponseSchema = z7.object({
|
|
410
|
+
sent: z7.literal(true)
|
|
397
411
|
});
|
|
398
412
|
|
|
399
413
|
// ../shared/src/grants.ts
|
|
400
|
-
import { z as
|
|
401
|
-
var grantRoleSchema =
|
|
402
|
-
var createGrantSchema =
|
|
403
|
-
email:
|
|
414
|
+
import { z as z8 } from "zod";
|
|
415
|
+
var grantRoleSchema = z8.enum(["viewer"]);
|
|
416
|
+
var createGrantSchema = z8.object({
|
|
417
|
+
email: z8.string().trim().toLowerCase().email().optional(),
|
|
404
418
|
role: grantRoleSchema.default("viewer"),
|
|
405
|
-
userId:
|
|
419
|
+
userId: z8.string().min(1).optional()
|
|
406
420
|
}).refine((body) => Boolean(body.email) !== Boolean(body.userId), {
|
|
407
421
|
message: "provide exactly one of email or userId"
|
|
408
422
|
});
|
|
409
|
-
var grantSchema =
|
|
410
|
-
createdAt:
|
|
411
|
-
email:
|
|
412
|
-
expiresAt:
|
|
413
|
-
id:
|
|
423
|
+
var grantSchema = z8.object({
|
|
424
|
+
createdAt: z8.string(),
|
|
425
|
+
email: z8.string().email().nullable(),
|
|
426
|
+
expiresAt: z8.string().nullable(),
|
|
427
|
+
id: z8.string(),
|
|
414
428
|
// The subject's avatar once they have an account; null otherwise.
|
|
415
|
-
image:
|
|
429
|
+
image: z8.string().nullable(),
|
|
416
430
|
// Present on the invited account after redemption / when granting an
|
|
417
431
|
// existing user; null for a still-pending email invite.
|
|
418
|
-
name:
|
|
419
|
-
redeemedAt:
|
|
432
|
+
name: z8.string().nullable(),
|
|
433
|
+
redeemedAt: z8.string().nullable(),
|
|
420
434
|
role: grantRoleSchema,
|
|
421
435
|
// Shown as "· pending" beside the role until the link is redeemed.
|
|
422
|
-
status:
|
|
436
|
+
status: z8.enum(["pending", "active"]),
|
|
423
437
|
// Display fragment of the live invitation token, or null once redeemed.
|
|
424
|
-
tokenPrefix:
|
|
425
|
-
userId:
|
|
438
|
+
tokenPrefix: z8.string().nullable(),
|
|
439
|
+
userId: z8.string().nullable()
|
|
426
440
|
});
|
|
427
441
|
var createdGrantSchema = grantSchema.extend({
|
|
428
|
-
url:
|
|
442
|
+
url: z8.string().url()
|
|
429
443
|
});
|
|
430
|
-
var grantListResponseSchema =
|
|
431
|
-
grants:
|
|
444
|
+
var grantListResponseSchema = z8.object({
|
|
445
|
+
grants: z8.array(grantSchema),
|
|
432
446
|
// The artifact's current general-access value, so the share surface can
|
|
433
447
|
// render the "General access" line without a second read.
|
|
434
|
-
visibility:
|
|
448
|
+
visibility: z8.enum(["public", "unlisted", "workspace", "private"])
|
|
435
449
|
});
|
|
436
|
-
var revokeGrantResponseSchema =
|
|
437
|
-
revoked:
|
|
450
|
+
var revokeGrantResponseSchema = z8.object({
|
|
451
|
+
revoked: z8.literal(true)
|
|
438
452
|
});
|
|
439
|
-
var acceptGrantSchema =
|
|
440
|
-
token:
|
|
453
|
+
var acceptGrantSchema = z8.object({
|
|
454
|
+
token: z8.string().min(1)
|
|
441
455
|
});
|
|
442
|
-
var acceptGrantResponseSchema =
|
|
443
|
-
artifactId:
|
|
456
|
+
var acceptGrantResponseSchema = z8.object({
|
|
457
|
+
artifactId: z8.string(),
|
|
444
458
|
// The review shell URL to land on, carrying ?invited=1 for the banner.
|
|
445
|
-
artifactUrl:
|
|
446
|
-
slug:
|
|
447
|
-
title:
|
|
448
|
-
});
|
|
449
|
-
var workspaceGuestSchema =
|
|
450
|
-
artifacts:
|
|
451
|
-
|
|
452
|
-
artifactId:
|
|
453
|
-
grantId:
|
|
454
|
-
slug:
|
|
455
|
-
status:
|
|
456
|
-
title:
|
|
459
|
+
artifactUrl: z8.string().url(),
|
|
460
|
+
slug: z8.string(),
|
|
461
|
+
title: z8.string()
|
|
462
|
+
});
|
|
463
|
+
var workspaceGuestSchema = z8.object({
|
|
464
|
+
artifacts: z8.array(
|
|
465
|
+
z8.object({
|
|
466
|
+
artifactId: z8.string(),
|
|
467
|
+
grantId: z8.string(),
|
|
468
|
+
slug: z8.string(),
|
|
469
|
+
status: z8.enum(["pending", "active"]),
|
|
470
|
+
title: z8.string()
|
|
457
471
|
})
|
|
458
472
|
),
|
|
459
|
-
email:
|
|
460
|
-
image:
|
|
461
|
-
name:
|
|
462
|
-
userId:
|
|
463
|
-
});
|
|
464
|
-
var workspaceGuestListResponseSchema =
|
|
465
|
-
guests:
|
|
466
|
-
});
|
|
467
|
-
var sharedWithMeArtifactSchema =
|
|
468
|
-
artifactId:
|
|
469
|
-
slug:
|
|
470
|
-
title:
|
|
471
|
-
url:
|
|
473
|
+
email: z8.string().nullable(),
|
|
474
|
+
image: z8.string().nullable(),
|
|
475
|
+
name: z8.string().nullable(),
|
|
476
|
+
userId: z8.string().nullable()
|
|
477
|
+
});
|
|
478
|
+
var workspaceGuestListResponseSchema = z8.object({
|
|
479
|
+
guests: z8.array(workspaceGuestSchema)
|
|
480
|
+
});
|
|
481
|
+
var sharedWithMeArtifactSchema = z8.object({
|
|
482
|
+
artifactId: z8.string(),
|
|
483
|
+
slug: z8.string(),
|
|
484
|
+
title: z8.string(),
|
|
485
|
+
url: z8.string().url(),
|
|
472
486
|
// Who shared it, for the "Shared with me" list.
|
|
473
|
-
workspaceName:
|
|
487
|
+
workspaceName: z8.string()
|
|
474
488
|
});
|
|
475
|
-
var sharedWithMeListResponseSchema =
|
|
476
|
-
artifacts:
|
|
489
|
+
var sharedWithMeListResponseSchema = z8.object({
|
|
490
|
+
artifacts: z8.array(sharedWithMeArtifactSchema)
|
|
477
491
|
});
|
|
478
492
|
|
|
479
493
|
// ../shared/src/me.ts
|
|
480
|
-
import { z as
|
|
494
|
+
import { z as z10 } from "zod";
|
|
481
495
|
|
|
482
496
|
// ../shared/src/workspaces.ts
|
|
483
|
-
import { z as
|
|
497
|
+
import { z as z9 } from "zod";
|
|
484
498
|
var WORKSPACE_HANDLE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])$/;
|
|
485
|
-
var workspaceHandleUnavailableReasonSchema =
|
|
499
|
+
var workspaceHandleUnavailableReasonSchema = z9.enum([
|
|
486
500
|
"held",
|
|
487
501
|
"invalid",
|
|
488
502
|
"reserved",
|
|
489
503
|
"taken"
|
|
490
504
|
]);
|
|
491
|
-
var workspaceHandleAvailabilitySchema =
|
|
492
|
-
available:
|
|
493
|
-
handle:
|
|
505
|
+
var workspaceHandleAvailabilitySchema = z9.object({
|
|
506
|
+
available: z9.boolean(),
|
|
507
|
+
handle: z9.string(),
|
|
494
508
|
// Human-readable sentence for the field hint; null when available.
|
|
495
|
-
message:
|
|
509
|
+
message: z9.string().nullable(),
|
|
496
510
|
reason: workspaceHandleUnavailableReasonSchema.nullable()
|
|
497
511
|
});
|
|
498
|
-
var workspaceRoleSchema =
|
|
499
|
-
var workspaceInviteRoleSchema =
|
|
500
|
-
var workspaceHandleSchema =
|
|
512
|
+
var workspaceRoleSchema = z9.enum(["owner", "admin", "member"]);
|
|
513
|
+
var workspaceInviteRoleSchema = z9.enum(["admin", "member"]);
|
|
514
|
+
var workspaceHandleSchema = z9.string().min(3).max(32).regex(WORKSPACE_HANDLE_PATTERN, {
|
|
501
515
|
message: "handle must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
502
516
|
});
|
|
503
|
-
var createWorkspaceSchema =
|
|
517
|
+
var createWorkspaceSchema = z9.object({
|
|
504
518
|
handle: workspaceHandleSchema.optional(),
|
|
505
|
-
name:
|
|
519
|
+
name: z9.string().trim().min(1).max(100)
|
|
506
520
|
});
|
|
507
|
-
var updateWorkspaceSchema =
|
|
521
|
+
var updateWorkspaceSchema = z9.object({
|
|
508
522
|
handle: workspaceHandleSchema.optional(),
|
|
509
|
-
name:
|
|
523
|
+
name: z9.string().trim().min(1).max(100).optional()
|
|
510
524
|
}).refine((body) => body.handle !== void 0 || body.name !== void 0, {
|
|
511
525
|
message: "provide at least one of name or handle"
|
|
512
526
|
});
|
|
513
|
-
var workspaceSchema =
|
|
514
|
-
createdAt:
|
|
515
|
-
handle:
|
|
527
|
+
var workspaceSchema = z9.object({
|
|
528
|
+
createdAt: z9.string(),
|
|
529
|
+
handle: z9.string(),
|
|
516
530
|
// ISO timestamp when `{handle}.artifact.cafe` was provisioned, or null.
|
|
517
531
|
// Set by the one-time, self-serve enable flow (§4.4); never auto at
|
|
518
532
|
// create, and always null for personal workspaces.
|
|
519
|
-
hostnameProvisionedAt:
|
|
520
|
-
id:
|
|
533
|
+
hostnameProvisionedAt: z9.string().nullable(),
|
|
534
|
+
id: z9.string(),
|
|
521
535
|
// Auto-provisioned solo workspace, one per user: non-deletable, takes
|
|
522
536
|
// no members, renameable like any workspace.
|
|
523
|
-
isPersonal:
|
|
537
|
+
isPersonal: z9.boolean(),
|
|
524
538
|
// Uploaded logo URL, or null for the initials fallback. Set through the
|
|
525
539
|
// dedicated /workspaces/:id/avatar route, never the generic update.
|
|
526
|
-
logo:
|
|
527
|
-
name:
|
|
540
|
+
logo: z9.string().nullable(),
|
|
541
|
+
name: z9.string(),
|
|
528
542
|
role: workspaceRoleSchema.nullable(),
|
|
529
|
-
updatedAt:
|
|
543
|
+
updatedAt: z9.string()
|
|
530
544
|
});
|
|
531
|
-
var workspaceListResponseSchema =
|
|
532
|
-
workspaces:
|
|
545
|
+
var workspaceListResponseSchema = z9.object({
|
|
546
|
+
workspaces: z9.array(workspaceSchema)
|
|
533
547
|
});
|
|
534
|
-
var deleteWorkspaceResponseSchema =
|
|
535
|
-
deleted:
|
|
548
|
+
var deleteWorkspaceResponseSchema = z9.object({
|
|
549
|
+
deleted: z9.literal(true)
|
|
536
550
|
});
|
|
537
|
-
var workspaceMemberSchema =
|
|
538
|
-
createdAt:
|
|
539
|
-
email:
|
|
540
|
-
image:
|
|
541
|
-
name:
|
|
551
|
+
var workspaceMemberSchema = z9.object({
|
|
552
|
+
createdAt: z9.string(),
|
|
553
|
+
email: z9.string().email(),
|
|
554
|
+
image: z9.string().nullable(),
|
|
555
|
+
name: z9.string(),
|
|
542
556
|
role: workspaceRoleSchema,
|
|
543
|
-
userId:
|
|
557
|
+
userId: z9.string()
|
|
544
558
|
});
|
|
545
|
-
var workspaceMemberListResponseSchema =
|
|
546
|
-
members:
|
|
559
|
+
var workspaceMemberListResponseSchema = z9.object({
|
|
560
|
+
members: z9.array(workspaceMemberSchema)
|
|
547
561
|
});
|
|
548
|
-
var updateWorkspaceMemberSchema =
|
|
562
|
+
var updateWorkspaceMemberSchema = z9.object({
|
|
549
563
|
role: workspaceRoleSchema
|
|
550
564
|
});
|
|
551
|
-
var removeWorkspaceMemberResponseSchema =
|
|
552
|
-
removed:
|
|
565
|
+
var removeWorkspaceMemberResponseSchema = z9.object({
|
|
566
|
+
removed: z9.literal(true)
|
|
553
567
|
});
|
|
554
|
-
var createWorkspaceInviteSchema =
|
|
555
|
-
email:
|
|
556
|
-
expiresAt:
|
|
557
|
-
maxUses:
|
|
568
|
+
var createWorkspaceInviteSchema = z9.object({
|
|
569
|
+
email: z9.string().trim().toLowerCase().email().optional(),
|
|
570
|
+
expiresAt: z9.string().datetime(),
|
|
571
|
+
maxUses: z9.number().int().positive().optional(),
|
|
558
572
|
role: workspaceInviteRoleSchema
|
|
559
573
|
});
|
|
560
|
-
var workspaceInviteSchema =
|
|
561
|
-
createdAt:
|
|
562
|
-
email:
|
|
563
|
-
expiresAt:
|
|
564
|
-
id:
|
|
565
|
-
maxUses:
|
|
574
|
+
var workspaceInviteSchema = z9.object({
|
|
575
|
+
createdAt: z9.string(),
|
|
576
|
+
email: z9.string().email().nullable(),
|
|
577
|
+
expiresAt: z9.string(),
|
|
578
|
+
id: z9.string(),
|
|
579
|
+
maxUses: z9.number().int().positive().nullable(),
|
|
566
580
|
role: workspaceInviteRoleSchema,
|
|
567
|
-
tokenPrefix:
|
|
568
|
-
useCount:
|
|
581
|
+
tokenPrefix: z9.string(),
|
|
582
|
+
useCount: z9.number().int().nonnegative()
|
|
569
583
|
});
|
|
570
584
|
var createdWorkspaceInviteSchema = workspaceInviteSchema.extend({
|
|
571
|
-
url:
|
|
585
|
+
url: z9.string().url()
|
|
572
586
|
});
|
|
573
|
-
var workspaceInviteListResponseSchema =
|
|
574
|
-
invites:
|
|
587
|
+
var workspaceInviteListResponseSchema = z9.object({
|
|
588
|
+
invites: z9.array(workspaceInviteSchema)
|
|
575
589
|
});
|
|
576
|
-
var revokeWorkspaceInviteResponseSchema =
|
|
577
|
-
revoked:
|
|
590
|
+
var revokeWorkspaceInviteResponseSchema = z9.object({
|
|
591
|
+
revoked: z9.literal(true)
|
|
578
592
|
});
|
|
579
|
-
var acceptWorkspaceInviteSchema =
|
|
580
|
-
token:
|
|
593
|
+
var acceptWorkspaceInviteSchema = z9.object({
|
|
594
|
+
token: z9.string().min(1)
|
|
581
595
|
});
|
|
582
|
-
var acceptWorkspaceInviteResponseSchema =
|
|
596
|
+
var acceptWorkspaceInviteResponseSchema = z9.object({
|
|
583
597
|
role: workspaceRoleSchema,
|
|
584
598
|
workspace: workspaceSchema
|
|
585
599
|
});
|
|
586
|
-
var folderVisibilitySchema =
|
|
587
|
-
var artifactVisibilitySchema =
|
|
600
|
+
var folderVisibilitySchema = z9.enum(["public", "workspace"]);
|
|
601
|
+
var artifactVisibilitySchema = z9.enum([
|
|
588
602
|
"public",
|
|
589
603
|
"unlisted",
|
|
590
604
|
"workspace",
|
|
591
605
|
"private"
|
|
592
606
|
]);
|
|
593
|
-
var createFolderSchema =
|
|
594
|
-
name:
|
|
607
|
+
var createFolderSchema = z9.object({
|
|
608
|
+
name: z9.string().trim().min(1).max(100),
|
|
595
609
|
visibility: folderVisibilitySchema
|
|
596
610
|
});
|
|
597
|
-
var updateFolderSchema =
|
|
611
|
+
var updateFolderSchema = z9.object({
|
|
598
612
|
// With `visibility`: bulk-update the folder's artifacts to match
|
|
599
613
|
// (SPEC-2 §3.4 "Changing a folder's visibility offers a bulk update").
|
|
600
|
-
cascade:
|
|
601
|
-
name:
|
|
602
|
-
sortOrder:
|
|
614
|
+
cascade: z9.boolean().optional(),
|
|
615
|
+
name: z9.string().trim().min(1).max(100).optional(),
|
|
616
|
+
sortOrder: z9.number().int().min(0).optional(),
|
|
603
617
|
visibility: folderVisibilitySchema.optional()
|
|
604
618
|
}).refine(
|
|
605
619
|
(body) => body.name !== void 0 || body.visibility !== void 0 || body.sortOrder !== void 0,
|
|
@@ -607,256 +621,260 @@ var updateFolderSchema = z8.object({
|
|
|
607
621
|
).refine((body) => !body.cascade || body.visibility !== void 0, {
|
|
608
622
|
message: "cascade requires visibility"
|
|
609
623
|
});
|
|
610
|
-
var folderSchema =
|
|
611
|
-
createdAt:
|
|
612
|
-
id:
|
|
613
|
-
name:
|
|
624
|
+
var folderSchema = z9.object({
|
|
625
|
+
createdAt: z9.string(),
|
|
626
|
+
id: z9.string(),
|
|
627
|
+
name: z9.string(),
|
|
614
628
|
// Permalink segment for the public folder page (/w/{handle}/f/{slug}).
|
|
615
629
|
// Server-derived from the name; renames regenerate it.
|
|
616
|
-
slug:
|
|
617
|
-
sortOrder:
|
|
618
|
-
updatedAt:
|
|
630
|
+
slug: z9.string(),
|
|
631
|
+
sortOrder: z9.number().int(),
|
|
632
|
+
updatedAt: z9.string(),
|
|
619
633
|
visibility: folderVisibilitySchema,
|
|
620
|
-
workspaceId:
|
|
634
|
+
workspaceId: z9.string()
|
|
621
635
|
});
|
|
622
|
-
var folderListResponseSchema =
|
|
623
|
-
folders:
|
|
636
|
+
var folderListResponseSchema = z9.object({
|
|
637
|
+
folders: z9.array(folderSchema)
|
|
624
638
|
});
|
|
625
|
-
var deleteFolderResponseSchema =
|
|
626
|
-
deleted:
|
|
639
|
+
var deleteFolderResponseSchema = z9.object({
|
|
640
|
+
deleted: z9.literal(true)
|
|
627
641
|
});
|
|
628
|
-
var workspaceArtifactSchema =
|
|
629
|
-
createdAt:
|
|
630
|
-
currentVersionNumber:
|
|
631
|
-
folderId:
|
|
632
|
-
id:
|
|
633
|
-
openCommentCount:
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
642
|
+
var workspaceArtifactSchema = z9.object({
|
|
643
|
+
createdAt: z9.string(),
|
|
644
|
+
currentVersionNumber: z9.number().int().nullable(),
|
|
645
|
+
folderId: z9.string().nullable(),
|
|
646
|
+
id: z9.string(),
|
|
647
|
+
openCommentCount: z9.number().int().nonnegative(),
|
|
648
|
+
reviewMode: reviewModeSchema,
|
|
649
|
+
slug: z9.string(),
|
|
650
|
+
title: z9.string(),
|
|
651
|
+
updatedAt: z9.string(),
|
|
652
|
+
url: z9.string().url(),
|
|
653
|
+
versionCount: z9.number().int().nonnegative(),
|
|
639
654
|
visibility: artifactVisibilitySchema
|
|
640
655
|
});
|
|
641
|
-
var workspaceArtifactListResponseSchema =
|
|
642
|
-
artifacts:
|
|
656
|
+
var workspaceArtifactListResponseSchema = z9.object({
|
|
657
|
+
artifacts: z9.array(workspaceArtifactSchema)
|
|
643
658
|
});
|
|
644
|
-
var workspaceArtifactSearchResultSchema =
|
|
645
|
-
id:
|
|
646
|
-
slug:
|
|
647
|
-
title:
|
|
659
|
+
var workspaceArtifactSearchResultSchema = z9.object({
|
|
660
|
+
id: z9.string(),
|
|
661
|
+
slug: z9.string(),
|
|
662
|
+
title: z9.string()
|
|
648
663
|
});
|
|
649
|
-
var workspaceArtifactSearchResponseSchema =
|
|
650
|
-
results:
|
|
664
|
+
var workspaceArtifactSearchResponseSchema = z9.object({
|
|
665
|
+
results: z9.array(workspaceArtifactSearchResultSchema)
|
|
651
666
|
});
|
|
652
667
|
|
|
653
668
|
// ../shared/src/me.ts
|
|
654
|
-
var ownArtifactSchema =
|
|
655
|
-
createdAt:
|
|
656
|
-
currentVersionNumber:
|
|
669
|
+
var ownArtifactSchema = z10.object({
|
|
670
|
+
createdAt: z10.string(),
|
|
671
|
+
currentVersionNumber: z10.number().nullable(),
|
|
657
672
|
// Owned artifacts normally never expire; non-null only while an
|
|
658
673
|
// expiry is still set (e.g. an unclaimed publish surfaced here later).
|
|
659
|
-
expiresAt:
|
|
674
|
+
expiresAt: z10.string().nullable(),
|
|
660
675
|
// SPEC-2 §8.4 — the containing folder for workspace-owned artifacts;
|
|
661
676
|
// both null for personal artifacts. `folderId` drives the dashboard's
|
|
662
677
|
// move control and folder filter; `folderName` is the display label.
|
|
663
|
-
folderId:
|
|
664
|
-
folderName:
|
|
678
|
+
folderId: z10.string().nullable(),
|
|
679
|
+
folderName: z10.string().nullable(),
|
|
665
680
|
// Whether a publish token is still active — revocable from the
|
|
666
681
|
// dashboard (§6.18); the token itself is never returned.
|
|
667
|
-
hasPublishToken:
|
|
668
|
-
id:
|
|
669
|
-
openThreads:
|
|
670
|
-
protected:
|
|
682
|
+
hasPublishToken: z10.boolean(),
|
|
683
|
+
id: z10.string(),
|
|
684
|
+
openThreads: z10.number(),
|
|
685
|
+
protected: z10.boolean(),
|
|
671
686
|
// Who published the current version (falling back to the claiming
|
|
672
687
|
// owner) — the dashboard shows a name and avatar per artifact so a
|
|
673
688
|
// shared workspace reads as people's work, not anonymous rows. Null
|
|
674
689
|
// when the publish was token-only and the artifact is unclaimed.
|
|
675
|
-
publishedBy:
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
690
|
+
publishedBy: z10.object({ image: z10.string().nullable(), name: z10.string() }).nullable(),
|
|
691
|
+
// SPEC-2 §5.8 — the review dial, so the dashboard's settings dialog can
|
|
692
|
+
// render current state without a second fetch.
|
|
693
|
+
reviewMode: reviewModeSchema,
|
|
694
|
+
slug: z10.string(),
|
|
695
|
+
title: z10.string(),
|
|
696
|
+
totalViews: z10.number(),
|
|
679
697
|
// SPEC §6.20 — messages by others newer than the viewer's last-seen
|
|
680
698
|
// watermark. 0 for signed-out/API-key-less contexts.
|
|
681
|
-
unreadComments:
|
|
682
|
-
updatedAt:
|
|
683
|
-
url:
|
|
684
|
-
versionCount:
|
|
699
|
+
unreadComments: z10.number(),
|
|
700
|
+
updatedAt: z10.string(),
|
|
701
|
+
url: z10.string(),
|
|
702
|
+
versionCount: z10.number(),
|
|
685
703
|
// SPEC-2 §5.1 — whether the caller clears the manage bar for this
|
|
686
704
|
// artifact (workspace admin, or the person who first published it).
|
|
687
705
|
// Only a manager's folder move inherits the folder's visibility, so the
|
|
688
706
|
// dashboard warns exactly the people the change can actually affect, and
|
|
689
707
|
// only a manager is offered the Share entry (§5.7).
|
|
690
|
-
viewerCanManage:
|
|
708
|
+
viewerCanManage: z10.boolean(),
|
|
691
709
|
// SPEC-2 §5.2 — the artifact's own visibility, the single enforcement
|
|
692
710
|
// source. The dashboard needs it to tell whether a folder move would
|
|
693
711
|
// widen exposure before it sends the PATCH (§3.4), and to render the lock
|
|
694
712
|
// glyph on `private` rows and cards (§5.7).
|
|
695
713
|
visibility: artifactVisibilitySchema
|
|
696
714
|
});
|
|
697
|
-
var ownArtifactsResponseSchema =
|
|
698
|
-
artifacts:
|
|
715
|
+
var ownArtifactsResponseSchema = z10.object({
|
|
716
|
+
artifacts: z10.array(ownArtifactSchema)
|
|
699
717
|
});
|
|
700
|
-
var revokePublishTokenResponseSchema =
|
|
701
|
-
revoked:
|
|
718
|
+
var revokePublishTokenResponseSchema = z10.object({
|
|
719
|
+
revoked: z10.boolean()
|
|
702
720
|
});
|
|
703
721
|
|
|
704
722
|
// ../shared/src/owner.ts
|
|
705
|
-
import { z as
|
|
723
|
+
import { z as z11 } from "zod";
|
|
706
724
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/;
|
|
707
|
-
var claimResponseSchema =
|
|
708
|
-
artifactId:
|
|
709
|
-
slug:
|
|
710
|
-
title:
|
|
711
|
-
url:
|
|
725
|
+
var claimResponseSchema = z11.object({
|
|
726
|
+
artifactId: z11.string(),
|
|
727
|
+
slug: z11.string(),
|
|
728
|
+
title: z11.string(),
|
|
729
|
+
url: z11.string().url()
|
|
712
730
|
});
|
|
713
|
-
var updateArtifactSchema =
|
|
731
|
+
var updateArtifactSchema = z11.object({
|
|
714
732
|
// SPEC-2 §6.4 — placement + visibility. `folderId: null` clears the
|
|
715
733
|
// folder; `workspaceId: null` moves the artifact out of its workspace
|
|
716
734
|
// (§5.5 ownership transfer).
|
|
717
|
-
folderId:
|
|
718
|
-
slug:
|
|
735
|
+
folderId: z11.string().min(1).nullable().optional(),
|
|
736
|
+
slug: z11.string().min(3).max(63).regex(SLUG_PATTERN, {
|
|
719
737
|
message: "slug must be lowercase letters, digits, and hyphens, with no leading/trailing hyphen"
|
|
720
738
|
}).optional(),
|
|
721
|
-
title:
|
|
739
|
+
title: z11.string().min(1).max(200).optional(),
|
|
722
740
|
visibility: artifactVisibilitySchema.optional(),
|
|
723
|
-
workspaceId:
|
|
741
|
+
workspaceId: z11.string().min(1).nullable().optional()
|
|
724
742
|
}).refine(
|
|
725
743
|
(body) => body.title !== void 0 || body.slug !== void 0 || body.visibility !== void 0 || body.folderId !== void 0 || body.workspaceId !== void 0,
|
|
726
744
|
{
|
|
727
745
|
message: "provide at least one of title, slug, visibility, folderId, workspaceId"
|
|
728
746
|
}
|
|
729
747
|
);
|
|
730
|
-
var deleteArtifactResponseSchema =
|
|
731
|
-
deleted:
|
|
748
|
+
var deleteArtifactResponseSchema = z11.object({
|
|
749
|
+
deleted: z11.literal(true)
|
|
732
750
|
});
|
|
733
751
|
|
|
734
752
|
// ../shared/src/presence.ts
|
|
735
|
-
import { z as
|
|
753
|
+
import { z as z12 } from "zod";
|
|
736
754
|
var AGENT_STATES = ["listening", "editing", "publishing"];
|
|
737
|
-
var agentStateSchema =
|
|
755
|
+
var agentStateSchema = z12.enum(AGENT_STATES);
|
|
738
756
|
var AGENT_PRESENCE = {
|
|
739
757
|
editingTtlSeconds: 300,
|
|
740
758
|
heartbeatSeconds: 15,
|
|
741
759
|
shellPollSeconds: 15,
|
|
742
760
|
ttlSeconds: 45
|
|
743
761
|
};
|
|
744
|
-
var agentHeartbeatBodySchema =
|
|
762
|
+
var agentHeartbeatBodySchema = z12.object({
|
|
745
763
|
state: agentStateSchema.optional()
|
|
746
764
|
});
|
|
747
|
-
var agentHeartbeatResponseSchema =
|
|
748
|
-
listening:
|
|
765
|
+
var agentHeartbeatResponseSchema = z12.object({
|
|
766
|
+
listening: z12.literal(true),
|
|
749
767
|
state: agentStateSchema.optional(),
|
|
750
|
-
ttlSeconds:
|
|
768
|
+
ttlSeconds: z12.number().int().positive()
|
|
751
769
|
});
|
|
752
|
-
var agentPresenceSchema =
|
|
753
|
-
listening:
|
|
770
|
+
var agentPresenceSchema = z12.object({
|
|
771
|
+
listening: z12.boolean(),
|
|
754
772
|
state: agentStateSchema.nullable().optional(),
|
|
755
|
-
versionNumber:
|
|
773
|
+
versionNumber: z12.number().int().positive().nullable()
|
|
756
774
|
});
|
|
757
775
|
|
|
758
776
|
// ../shared/src/protection.ts
|
|
759
|
-
import { z as
|
|
777
|
+
import { z as z13 } from "zod";
|
|
760
778
|
var PASSWORD_MIN = 6;
|
|
761
779
|
var PASSWORD_MAX = 128;
|
|
762
|
-
var gatePasswordSchema =
|
|
763
|
-
var setProtectionSchema =
|
|
780
|
+
var gatePasswordSchema = z13.string().min(PASSWORD_MIN, `Password must be at least ${PASSWORD_MIN} characters.`).max(PASSWORD_MAX, `Password must be at most ${PASSWORD_MAX} characters.`);
|
|
781
|
+
var setProtectionSchema = z13.object({
|
|
764
782
|
password: gatePasswordSchema.nullable()
|
|
765
783
|
});
|
|
766
|
-
var protectionResponseSchema =
|
|
767
|
-
protected:
|
|
784
|
+
var protectionResponseSchema = z13.object({
|
|
785
|
+
protected: z13.boolean()
|
|
768
786
|
});
|
|
769
|
-
var unlockSchema =
|
|
770
|
-
password:
|
|
787
|
+
var unlockSchema = z13.object({
|
|
788
|
+
password: z13.string().min(1).max(1024)
|
|
771
789
|
});
|
|
772
|
-
var unlockResponseSchema =
|
|
773
|
-
unlocked:
|
|
790
|
+
var unlockResponseSchema = z13.object({
|
|
791
|
+
unlocked: z13.literal(true)
|
|
774
792
|
});
|
|
775
793
|
|
|
776
794
|
// ../shared/src/report.ts
|
|
777
|
-
import { z as
|
|
778
|
-
var reportRequestSchema =
|
|
779
|
-
reason:
|
|
795
|
+
import { z as z14 } from "zod";
|
|
796
|
+
var reportRequestSchema = z14.object({
|
|
797
|
+
reason: z14.string().max(1e3).optional()
|
|
780
798
|
});
|
|
781
|
-
var reportResponseSchema =
|
|
782
|
-
reported:
|
|
799
|
+
var reportResponseSchema = z14.object({
|
|
800
|
+
reported: z14.literal(true)
|
|
783
801
|
});
|
|
784
802
|
|
|
785
803
|
// ../shared/src/reviewers.ts
|
|
786
|
-
import { z as
|
|
787
|
-
var artifactReviewerSchema =
|
|
788
|
-
avatarUrl:
|
|
789
|
-
displayName:
|
|
804
|
+
import { z as z15 } from "zod";
|
|
805
|
+
var artifactReviewerSchema = z15.object({
|
|
806
|
+
avatarUrl: z15.string().nullable(),
|
|
807
|
+
displayName: z15.string(),
|
|
790
808
|
// Exactly one of userId/guestId is set, per `kind`.
|
|
791
|
-
guestId:
|
|
809
|
+
guestId: z15.string().nullable(),
|
|
792
810
|
// "account", not commentAuthorSchema's "member" — the whole point here is
|
|
793
811
|
// that these people need not be workspace members. A guest can be named in
|
|
794
812
|
// a comment but never notified: guest_identities carries a display name and
|
|
795
813
|
// no email, so there is nowhere to send anything.
|
|
796
|
-
kind:
|
|
797
|
-
userId:
|
|
814
|
+
kind: z15.enum(["account", "guest"]),
|
|
815
|
+
userId: z15.string().nullable()
|
|
798
816
|
});
|
|
799
|
-
var artifactReviewerListResponseSchema =
|
|
800
|
-
reviewers:
|
|
817
|
+
var artifactReviewerListResponseSchema = z15.object({
|
|
818
|
+
reviewers: z15.array(artifactReviewerSchema)
|
|
801
819
|
});
|
|
802
820
|
|
|
803
821
|
// ../shared/src/stats.ts
|
|
804
|
-
import { z as
|
|
805
|
-
var avgViewSecondsSchema =
|
|
806
|
-
var versionViewStatsSchema =
|
|
822
|
+
import { z as z16 } from "zod";
|
|
823
|
+
var avgViewSecondsSchema = z16.number().int().nonnegative().nullable();
|
|
824
|
+
var versionViewStatsSchema = z16.object({
|
|
807
825
|
avgViewSeconds: avgViewSecondsSchema,
|
|
808
826
|
// Views from inside the review shell's iframe vs. direct visits to
|
|
809
827
|
// the render URL. views = embeddedViews + directViews.
|
|
810
|
-
directViews:
|
|
811
|
-
embeddedViews:
|
|
828
|
+
directViews: z16.number().int().nonnegative(),
|
|
829
|
+
embeddedViews: z16.number().int().nonnegative(),
|
|
812
830
|
// Distinct hashed viewer IPs across the version's lifetime.
|
|
813
|
-
uniqueViewers:
|
|
814
|
-
versionNumber:
|
|
815
|
-
views:
|
|
831
|
+
uniqueViewers: z16.number().int().nonnegative(),
|
|
832
|
+
versionNumber: z16.number().int().positive(),
|
|
833
|
+
views: z16.number().int().nonnegative()
|
|
816
834
|
});
|
|
817
|
-
var dailyViewsSchema =
|
|
835
|
+
var dailyViewsSchema = z16.object({
|
|
818
836
|
avgViewSeconds: avgViewSecondsSchema,
|
|
819
837
|
// UTC day, YYYY-MM-DD.
|
|
820
|
-
day:
|
|
821
|
-
uniqueViewers:
|
|
822
|
-
views:
|
|
838
|
+
day: z16.string(),
|
|
839
|
+
uniqueViewers: z16.number().int().nonnegative(),
|
|
840
|
+
views: z16.number().int().nonnegative()
|
|
823
841
|
});
|
|
824
|
-
var artifactStatsResponseSchema =
|
|
842
|
+
var artifactStatsResponseSchema = z16.object({
|
|
825
843
|
avgViewSeconds: avgViewSecondsSchema,
|
|
826
|
-
daily:
|
|
844
|
+
daily: z16.array(dailyViewsSchema),
|
|
827
845
|
// Distinct hashed viewer IPs across all versions and days.
|
|
828
|
-
totalUniqueViewers:
|
|
829
|
-
totalViews:
|
|
830
|
-
versions:
|
|
846
|
+
totalUniqueViewers: z16.number().int().nonnegative(),
|
|
847
|
+
totalViews: z16.number().int().nonnegative(),
|
|
848
|
+
versions: z16.array(versionViewStatsSchema)
|
|
831
849
|
});
|
|
832
850
|
|
|
833
851
|
// ../shared/src/versions.ts
|
|
834
|
-
import { z as
|
|
835
|
-
var versionSourceSchema =
|
|
836
|
-
agentName:
|
|
837
|
-
type:
|
|
852
|
+
import { z as z17 } from "zod";
|
|
853
|
+
var versionSourceSchema = z17.object({
|
|
854
|
+
agentName: z17.string().nullable(),
|
|
855
|
+
type: z17.string()
|
|
838
856
|
});
|
|
839
|
-
var versionChangesSchema =
|
|
840
|
-
added:
|
|
841
|
-
changed:
|
|
842
|
-
removed:
|
|
857
|
+
var versionChangesSchema = z17.object({
|
|
858
|
+
added: z17.array(z17.string()),
|
|
859
|
+
changed: z17.array(z17.string()),
|
|
860
|
+
removed: z17.array(z17.string())
|
|
843
861
|
});
|
|
844
|
-
var versionSummarySchema =
|
|
862
|
+
var versionSummarySchema = z17.object({
|
|
845
863
|
// Absent for the first version — there is no previous version to diff against.
|
|
846
864
|
changes: versionChangesSchema.nullable(),
|
|
847
|
-
createdAt:
|
|
848
|
-
entryUrl:
|
|
849
|
-
fileCount:
|
|
850
|
-
id:
|
|
851
|
-
isCurrent:
|
|
865
|
+
createdAt: z17.string(),
|
|
866
|
+
entryUrl: z17.string().url(),
|
|
867
|
+
fileCount: z17.number().int().nonnegative(),
|
|
868
|
+
id: z17.string(),
|
|
869
|
+
isCurrent: z17.boolean(),
|
|
852
870
|
// Author-supplied bullet-point changelog; null when the publish omitted it.
|
|
853
|
-
notes:
|
|
871
|
+
notes: z17.string().nullable(),
|
|
854
872
|
source: versionSourceSchema,
|
|
855
|
-
totalSizeBytes:
|
|
856
|
-
versionNumber:
|
|
873
|
+
totalSizeBytes: z17.number().int().nonnegative(),
|
|
874
|
+
versionNumber: z17.number().int().positive()
|
|
857
875
|
});
|
|
858
|
-
var versionListResponseSchema =
|
|
859
|
-
versions:
|
|
876
|
+
var versionListResponseSchema = z17.object({
|
|
877
|
+
versions: z17.array(versionSummarySchema)
|
|
860
878
|
});
|
|
861
879
|
|
|
862
880
|
// src/api.ts
|
|
@@ -1091,6 +1109,16 @@ function createApiClient(apiUrl2, publishToken) {
|
|
|
1091
1109
|
{ body: JSON.stringify({ password }), headers, method: "PUT" },
|
|
1092
1110
|
(d) => protectionResponseSchema.parse(d)
|
|
1093
1111
|
);
|
|
1112
|
+
},
|
|
1113
|
+
// SPEC-2 §5.8 — what reviewers may do once they can open it. Same
|
|
1114
|
+
// dual-auth as protection, so the publish token this client holds is
|
|
1115
|
+
// enough (an agent can close review on its own artifact).
|
|
1116
|
+
async setReviewMode(artifactId, mode) {
|
|
1117
|
+
return request(
|
|
1118
|
+
`${base}/api/v1/artifacts/${artifactId}/review-mode`,
|
|
1119
|
+
{ body: JSON.stringify({ mode }), headers, method: "PUT" },
|
|
1120
|
+
(d) => reviewModeResponseSchema.parse(d)
|
|
1121
|
+
);
|
|
1094
1122
|
}
|
|
1095
1123
|
};
|
|
1096
1124
|
}
|
|
@@ -1119,17 +1147,17 @@ import {
|
|
|
1119
1147
|
writeFileSync as writeFileSync2
|
|
1120
1148
|
} from "fs";
|
|
1121
1149
|
import path2 from "path";
|
|
1122
|
-
import { z as
|
|
1150
|
+
import { z as z19 } from "zod";
|
|
1123
1151
|
|
|
1124
1152
|
// src/credentials.ts
|
|
1125
1153
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1126
1154
|
import { homedir } from "os";
|
|
1127
1155
|
import path from "path";
|
|
1128
|
-
import { z as
|
|
1156
|
+
import { z as z18 } from "zod";
|
|
1129
1157
|
var DEFAULT_API_URL = "https://artifact.cafe";
|
|
1130
|
-
var credentialsSchema =
|
|
1131
|
-
keys:
|
|
1132
|
-
version:
|
|
1158
|
+
var credentialsSchema = z18.object({
|
|
1159
|
+
keys: z18.record(z18.string(), z18.string()),
|
|
1160
|
+
version: z18.literal(1)
|
|
1133
1161
|
});
|
|
1134
1162
|
function credentialsPath() {
|
|
1135
1163
|
return path.join(homedir(), ".artifactcafe", "credentials");
|
|
@@ -1179,24 +1207,24 @@ function resolveApiKey(apiUrl2, flag) {
|
|
|
1179
1207
|
}
|
|
1180
1208
|
|
|
1181
1209
|
// src/config.ts
|
|
1182
|
-
var configSchema =
|
|
1183
|
-
apiUrl:
|
|
1184
|
-
artifactId:
|
|
1185
|
-
folder:
|
|
1186
|
-
folderId:
|
|
1210
|
+
var configSchema = z19.object({
|
|
1211
|
+
apiUrl: z19.string(),
|
|
1212
|
+
artifactId: z19.string(),
|
|
1213
|
+
folder: z19.string().optional(),
|
|
1214
|
+
folderId: z19.string().optional(),
|
|
1187
1215
|
// Optional: a folder linked by `link` to an artifact you own carries no
|
|
1188
1216
|
// token — owner actions authorize via your stored login instead. A first
|
|
1189
1217
|
// publish still writes the anonymous-mode token here.
|
|
1190
|
-
publishToken:
|
|
1191
|
-
slug:
|
|
1192
|
-
url:
|
|
1193
|
-
workspace:
|
|
1194
|
-
workspaceId:
|
|
1195
|
-
workspaceKind:
|
|
1196
|
-
});
|
|
1197
|
-
var projectConfigSchema =
|
|
1198
|
-
folder:
|
|
1199
|
-
workspace:
|
|
1218
|
+
publishToken: z19.string().optional(),
|
|
1219
|
+
slug: z19.string(),
|
|
1220
|
+
url: z19.string(),
|
|
1221
|
+
workspace: z19.string().optional(),
|
|
1222
|
+
workspaceId: z19.string().optional(),
|
|
1223
|
+
workspaceKind: z19.enum(["personal", "workspace"]).optional()
|
|
1224
|
+
});
|
|
1225
|
+
var projectConfigSchema = z19.object({
|
|
1226
|
+
folder: z19.string().trim().min(1).optional(),
|
|
1227
|
+
workspace: z19.string().trim().min(1)
|
|
1200
1228
|
}).strict();
|
|
1201
1229
|
var CONFIG_DIR = ".artifactcafe";
|
|
1202
1230
|
var CONFIG_FILE = "config.json";
|
|
@@ -1232,7 +1260,7 @@ function readProjectConfig(dir) {
|
|
|
1232
1260
|
JSON.parse(readFileSync2(file, "utf8"))
|
|
1233
1261
|
);
|
|
1234
1262
|
} catch (error) {
|
|
1235
|
-
const message = error instanceof
|
|
1263
|
+
const message = error instanceof z19.ZodError ? error.issues[0]?.message ?? "invalid project target" : "invalid JSON";
|
|
1236
1264
|
throw new Error(`Invalid ${file}: ${message}.`);
|
|
1237
1265
|
}
|
|
1238
1266
|
}
|
|
@@ -1755,6 +1783,11 @@ function resolveEntry(files, explicit) {
|
|
|
1755
1783
|
|
|
1756
1784
|
// src/publish.ts
|
|
1757
1785
|
var UPLOAD_CONCURRENCY = 6;
|
|
1786
|
+
var REVIEW_LABEL = {
|
|
1787
|
+
off: "off \u2014 plain artifact, no review tools",
|
|
1788
|
+
open: "open \u2014 anyone with the link can comment",
|
|
1789
|
+
readonly: "read-only \u2014 existing comments only"
|
|
1790
|
+
};
|
|
1758
1791
|
async function publish(opts) {
|
|
1759
1792
|
const dir = path6.resolve(opts.dir);
|
|
1760
1793
|
const config = readConfig(dir);
|
|
@@ -1764,6 +1797,14 @@ async function publish(opts) {
|
|
|
1764
1797
|
throw new Error(parsed.error.issues[0]?.message ?? "Invalid password.");
|
|
1765
1798
|
}
|
|
1766
1799
|
}
|
|
1800
|
+
let reviewMode;
|
|
1801
|
+
if (opts.review !== void 0) {
|
|
1802
|
+
const parsed = reviewModeSchema.safeParse(opts.review);
|
|
1803
|
+
if (!parsed.success) {
|
|
1804
|
+
throw new Error("--review must be one of: open, readonly, off.");
|
|
1805
|
+
}
|
|
1806
|
+
reviewMode = parsed.data;
|
|
1807
|
+
}
|
|
1767
1808
|
const artifactId = opts.artifact ?? config?.artifactId ?? null;
|
|
1768
1809
|
const token = (artifactId !== null && artifactId === config?.artifactId ? config.publishToken : void 0) ?? process.env.ARTIFACT_CAFE_TOKEN;
|
|
1769
1810
|
const apiUrl2 = process.env.ARTIFACT_CAFE_URL ?? config?.apiUrl ?? DEFAULT_API_URL;
|
|
@@ -1867,6 +1908,13 @@ async function publish(opts) {
|
|
|
1867
1908
|
);
|
|
1868
1909
|
await protectClient.setProtection(result.artifactId, opts.password);
|
|
1869
1910
|
}
|
|
1911
|
+
if (reviewMode !== void 0) {
|
|
1912
|
+
const reviewClient = createApiClient(
|
|
1913
|
+
apiUrl2,
|
|
1914
|
+
credential ?? result.publishToken
|
|
1915
|
+
);
|
|
1916
|
+
await reviewClient.setReviewMode(result.artifactId, reviewMode);
|
|
1917
|
+
}
|
|
1870
1918
|
if (opts.json) {
|
|
1871
1919
|
console.log(
|
|
1872
1920
|
JSON.stringify(
|
|
@@ -1883,6 +1931,7 @@ async function publish(opts) {
|
|
|
1883
1931
|
workspaceId: placement.workspaceId ?? null,
|
|
1884
1932
|
...result.claimUrl ? { claimUrl: result.claimUrl } : {},
|
|
1885
1933
|
...opts.password === void 0 ? {} : { protected: true },
|
|
1934
|
+
...reviewMode === void 0 ? {} : { reviewMode },
|
|
1886
1935
|
filesUploaded: session.filesToUpload.map((f) => f.path),
|
|
1887
1936
|
ignored: skipped,
|
|
1888
1937
|
skippedFiles: session.skippedFiles
|
|
@@ -1914,6 +1963,10 @@ ${result.claimUrl}
|
|
|
1914
1963
|
if (opts.password !== void 0) {
|
|
1915
1964
|
console.log("Password protection: on\n");
|
|
1916
1965
|
}
|
|
1966
|
+
if (reviewMode !== void 0) {
|
|
1967
|
+
console.log(`Review: ${REVIEW_LABEL[reviewMode]}
|
|
1968
|
+
`);
|
|
1969
|
+
}
|
|
1917
1970
|
} else {
|
|
1918
1971
|
console.log(`
|
|
1919
1972
|
\u2713 Published v${result.versionNumber}
|
|
@@ -1929,6 +1982,10 @@ ${result.claimUrl}
|
|
|
1929
1982
|
if (opts.password !== void 0) {
|
|
1930
1983
|
console.log("Password protection: on\n");
|
|
1931
1984
|
}
|
|
1985
|
+
if (reviewMode !== void 0) {
|
|
1986
|
+
console.log(`Review: ${REVIEW_LABEL[reviewMode]}
|
|
1987
|
+
`);
|
|
1988
|
+
}
|
|
1932
1989
|
}
|
|
1933
1990
|
if (opts.open && !opts.json && process.stdout.isTTY) {
|
|
1934
1991
|
openInBrowser(result.url);
|
|
@@ -2729,11 +2786,47 @@ async function changeThreadStatus(opts) {
|
|
|
2729
2786
|
console.log(`\u2713 ${verb} ${thread.id} \u2014 now ${thread.status}.`);
|
|
2730
2787
|
}
|
|
2731
2788
|
|
|
2732
|
-
// src/
|
|
2789
|
+
// src/review.ts
|
|
2733
2790
|
import path14 from "path";
|
|
2791
|
+
var OUTCOME = {
|
|
2792
|
+
off: "Plain artifact \u2014 the review tools are hidden entirely",
|
|
2793
|
+
open: "Open for review \u2014 anyone who can open it can comment",
|
|
2794
|
+
readonly: "Read-only \u2014 earlier comments stay visible, no new ones"
|
|
2795
|
+
};
|
|
2796
|
+
async function review(opts) {
|
|
2797
|
+
const parsed = reviewModeSchema.safeParse(opts.mode);
|
|
2798
|
+
if (!parsed.success) {
|
|
2799
|
+
throw new Error(
|
|
2800
|
+
"Provide a mode: open, readonly, or off. `readonly` keeps existing comments readable and refuses new ones; `off` hides the review layer entirely."
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
const mode = parsed.data;
|
|
2804
|
+
const dir = path14.resolve(opts.dir);
|
|
2805
|
+
const target = resolveArtifactTarget(dir, {
|
|
2806
|
+
apiKey: opts.apiKey,
|
|
2807
|
+
artifact: opts.artifact
|
|
2808
|
+
});
|
|
2809
|
+
const client = createApiClient(target.apiUrl, target.credential);
|
|
2810
|
+
const res = await client.setReviewMode(target.artifactId, mode);
|
|
2811
|
+
if (opts.json) {
|
|
2812
|
+
console.log(JSON.stringify({ reviewMode: res.mode }, null, 2));
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2815
|
+
const url = target.url ?? reviewUrl(
|
|
2816
|
+
target.apiUrl,
|
|
2817
|
+
(await client.getArtifact(target.artifactId)).slug
|
|
2818
|
+
);
|
|
2819
|
+
console.log(`
|
|
2820
|
+
\u2713 ${OUTCOME[res.mode]}
|
|
2821
|
+
${url}
|
|
2822
|
+
`);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
// src/share.ts
|
|
2826
|
+
import path15 from "path";
|
|
2734
2827
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2735
2828
|
async function share(opts) {
|
|
2736
|
-
const dir =
|
|
2829
|
+
const dir = path15.resolve(opts.dir);
|
|
2737
2830
|
const target = resolveArtifactTarget(dir, {
|
|
2738
2831
|
apiKey: opts.apiKey,
|
|
2739
2832
|
artifact: opts.artifact
|
|
@@ -2788,7 +2881,7 @@ General access: ${visibility}`);
|
|
|
2788
2881
|
console.log("");
|
|
2789
2882
|
}
|
|
2790
2883
|
async function unshare(opts) {
|
|
2791
|
-
const dir =
|
|
2884
|
+
const dir = path15.resolve(opts.dir);
|
|
2792
2885
|
const target = resolveArtifactTarget(dir, {
|
|
2793
2886
|
apiKey: opts.apiKey,
|
|
2794
2887
|
artifact: opts.artifact
|
|
@@ -2811,7 +2904,7 @@ async function unshare(opts) {
|
|
|
2811
2904
|
}
|
|
2812
2905
|
|
|
2813
2906
|
// src/status.ts
|
|
2814
|
-
import
|
|
2907
|
+
import path16 from "path";
|
|
2815
2908
|
async function status(opts) {
|
|
2816
2909
|
if (!AGENT_STATES.includes(opts.state)) {
|
|
2817
2910
|
throw new Error(
|
|
@@ -2819,7 +2912,7 @@ async function status(opts) {
|
|
|
2819
2912
|
);
|
|
2820
2913
|
}
|
|
2821
2914
|
const state = opts.state;
|
|
2822
|
-
const dir =
|
|
2915
|
+
const dir = path16.resolve(opts.dir);
|
|
2823
2916
|
const target = resolveArtifactTarget(dir, {
|
|
2824
2917
|
apiKey: opts.apiKey,
|
|
2825
2918
|
artifact: opts.artifact
|
|
@@ -2848,26 +2941,26 @@ async function status(opts) {
|
|
|
2848
2941
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2849
2942
|
import { createRequire } from "module";
|
|
2850
2943
|
import { homedir as homedir2 } from "os";
|
|
2851
|
-
import
|
|
2852
|
-
import { z as
|
|
2944
|
+
import path17 from "path";
|
|
2945
|
+
import { z as z20 } from "zod";
|
|
2853
2946
|
var REGISTRY_LATEST_URL = "https://registry.npmjs.org/artifact-cafe/latest";
|
|
2854
2947
|
var SKILL_SOURCE_URL = "https://raw.githubusercontent.com/Artifact-Cafe/skill/main/artifact-cafe/SKILL.md";
|
|
2855
2948
|
var SKILL_UPDATE_COMMAND = "npx skills add artifact-cafe/skill --skill artifact-cafe -g";
|
|
2856
2949
|
var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2857
2950
|
var FETCH_TIMEOUT_MS = 2e3;
|
|
2858
2951
|
var SKILL_VERSION_PATTERN = /\*\*Skill version:\s*(\d+\.\d+\.\d+)\*\*/;
|
|
2859
|
-
var cacheSchema =
|
|
2860
|
-
checkedAt:
|
|
2861
|
-
cliLatest:
|
|
2862
|
-
skillLatest:
|
|
2863
|
-
version:
|
|
2952
|
+
var cacheSchema = z20.object({
|
|
2953
|
+
checkedAt: z20.number(),
|
|
2954
|
+
cliLatest: z20.string().nullable(),
|
|
2955
|
+
skillLatest: z20.string().nullable(),
|
|
2956
|
+
version: z20.literal(1)
|
|
2864
2957
|
});
|
|
2865
2958
|
function cliVersion() {
|
|
2866
2959
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
2867
2960
|
return pkg.version;
|
|
2868
2961
|
}
|
|
2869
2962
|
function cachePath() {
|
|
2870
|
-
return
|
|
2963
|
+
return path17.join(homedir2(), ".artifactcafe", "update-check.json");
|
|
2871
2964
|
}
|
|
2872
2965
|
function readCache() {
|
|
2873
2966
|
try {
|
|
@@ -2878,7 +2971,7 @@ function readCache() {
|
|
|
2878
2971
|
}
|
|
2879
2972
|
function writeCache(cache) {
|
|
2880
2973
|
try {
|
|
2881
|
-
mkdirSync3(
|
|
2974
|
+
mkdirSync3(path17.dirname(cachePath()), { mode: 448, recursive: true });
|
|
2882
2975
|
writeFileSync3(cachePath(), `${JSON.stringify(cache, null, 2)}
|
|
2883
2976
|
`);
|
|
2884
2977
|
} catch {
|
|
@@ -2915,7 +3008,7 @@ async function fetchText(url) {
|
|
|
2915
3008
|
}
|
|
2916
3009
|
async function fetchLatestVersions(previous) {
|
|
2917
3010
|
const [cli, skill] = await Promise.all([
|
|
2918
|
-
fetchJson(REGISTRY_LATEST_URL).then((body) =>
|
|
3011
|
+
fetchJson(REGISTRY_LATEST_URL).then((body) => z20.object({ version: z20.string() }).parse(body).version).catch(() => null),
|
|
2919
3012
|
fetchText(SKILL_SOURCE_URL).then((body) => SKILL_VERSION_PATTERN.exec(body)?.[1] ?? null).catch(() => null)
|
|
2920
3013
|
]);
|
|
2921
3014
|
return {
|
|
@@ -2931,7 +3024,7 @@ function installedSkillVersions() {
|
|
|
2931
3024
|
const versions = [];
|
|
2932
3025
|
for (const root of roots) {
|
|
2933
3026
|
for (const dir of dirs) {
|
|
2934
|
-
const file =
|
|
3027
|
+
const file = path17.join(root, dir, "skills", "artifact-cafe", "SKILL.md");
|
|
2935
3028
|
if (!existsSync3(file)) {
|
|
2936
3029
|
continue;
|
|
2937
3030
|
}
|
|
@@ -3072,6 +3165,10 @@ var publish2 = defineCommand({
|
|
|
3072
3165
|
description: "Password-protect the artifact (min 6 chars)",
|
|
3073
3166
|
type: "string"
|
|
3074
3167
|
},
|
|
3168
|
+
review: {
|
|
3169
|
+
description: "Review mode: open (default), readonly, or off (plain artifact)",
|
|
3170
|
+
type: "string"
|
|
3171
|
+
},
|
|
3075
3172
|
title: { description: "Artifact title", type: "string" },
|
|
3076
3173
|
workspace: {
|
|
3077
3174
|
description: "Publish into this workspace handle",
|
|
@@ -3091,6 +3188,7 @@ var publish2 = defineCommand({
|
|
|
3091
3188
|
notes: readNotesArg(process.argv.slice(2)),
|
|
3092
3189
|
open: !args["no-open"],
|
|
3093
3190
|
password: args.password,
|
|
3191
|
+
review: args.review,
|
|
3094
3192
|
title: args.title,
|
|
3095
3193
|
workspace: args.workspace
|
|
3096
3194
|
});
|
|
@@ -3474,6 +3572,47 @@ var protect2 = defineCommand({
|
|
|
3474
3572
|
}
|
|
3475
3573
|
}
|
|
3476
3574
|
});
|
|
3575
|
+
var review2 = defineCommand({
|
|
3576
|
+
args: {
|
|
3577
|
+
"api-key": {
|
|
3578
|
+
description: "Authorize with an account API key (default: stored login)",
|
|
3579
|
+
type: "string"
|
|
3580
|
+
},
|
|
3581
|
+
artifact: {
|
|
3582
|
+
description: "Act on an artifact ID instead of the linked folder",
|
|
3583
|
+
type: "string"
|
|
3584
|
+
},
|
|
3585
|
+
dir: {
|
|
3586
|
+
default: ".",
|
|
3587
|
+
description: "Published directory",
|
|
3588
|
+
type: "string"
|
|
3589
|
+
},
|
|
3590
|
+
json: { description: "Machine-readable output", type: "boolean" },
|
|
3591
|
+
mode: {
|
|
3592
|
+
description: "open, readonly, or off (plain artifact)",
|
|
3593
|
+
required: true,
|
|
3594
|
+
type: "positional"
|
|
3595
|
+
}
|
|
3596
|
+
},
|
|
3597
|
+
meta: {
|
|
3598
|
+
description: "Open, close, or freeze review on the linked artifact",
|
|
3599
|
+
name: "review"
|
|
3600
|
+
},
|
|
3601
|
+
async run({ args }) {
|
|
3602
|
+
try {
|
|
3603
|
+
await review({
|
|
3604
|
+
apiKey: args["api-key"],
|
|
3605
|
+
artifact: args.artifact,
|
|
3606
|
+
dir: args.dir,
|
|
3607
|
+
json: Boolean(args.json),
|
|
3608
|
+
mode: args.mode
|
|
3609
|
+
});
|
|
3610
|
+
} catch (err) {
|
|
3611
|
+
printCliError(err, Boolean(args.json));
|
|
3612
|
+
process.exit(1);
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
});
|
|
3477
3616
|
var threadStatusCommand = (action) => defineCommand({
|
|
3478
3617
|
args: {
|
|
3479
3618
|
"api-key": {
|
|
@@ -3890,6 +4029,7 @@ var main = defineCommand({
|
|
|
3890
4029
|
reopen,
|
|
3891
4030
|
reply,
|
|
3892
4031
|
resolve,
|
|
4032
|
+
review: review2,
|
|
3893
4033
|
share: share2,
|
|
3894
4034
|
status: statusCmd,
|
|
3895
4035
|
unshare: unshare2,
|