clone

push a directory of html from the terminal and get a four-character url back. a deno cli on cloudflare

main
nzip / cli / mcp / schemas.ts
schemas.ts 4.0K
1import { z } from "zod";2import { isValidName, parseTarget } from "@nzip/shared";34export const vaultName = z.string().regex(/^[a-z0-9][a-z0-9-]{0,31}$/).refine(isValidName);5export const address = z.string().regex(/^[0-9a-f]{4}$/);6export const target = z.string().max(65).describe(7 "Existing four-hex site ID (preferred) or explicit vault:alias. No bare aliases or URLs.",8).refine((value) => {9 try {10 return parseTarget(value).kind !== "alias";11 } catch {12 return false;13 }14}, "Use a four-hex site ID or vault:alias");15export const ttl = z.union([z.number().positive().max(3650), z.literal("forever")]);16const timestamp = z.number().int().nonnegative();17const hash = z.string().regex(/^[0-9a-f]{64}$/);18export const success = { ok: z.literal(true) };19export const site = z.object({20 address,21 vault: vaultName,22 alias: z.string().nullable(),23 manifestHash: hash,24 createdAt: timestamp,25 updatedAt: timestamp,26 expiresAt: timestamp.nullable(),27 url: z.string().url(),28 protected: z.boolean(),29 feedback: z.boolean().optional(),30});31export const detail = site.extend({32 history: z.array(z.object({33 seq: z.number().int().positive(),34 manifestHash: hash,35 pushedAt: timestamp,36 note: z.string().nullable(),37 })),38});39export const vault = z.object({40 slot: z.number().int().min(0).max(15),41 name: vaultName,42 description: z.string().nullable(),43 createdAt: timestamp,44 siteCount: z.number().int().nonnegative(),45 defaultTtl: ttl.nullable(),46 effectiveDefaultTtl: ttl,47 defaultFor: z.array(z.enum(["temporary", "permanent"])),48 maxTtl: z.number().positive().nullable().optional(),49 requirePassword: z.boolean().optional(),50 hasDefaultPassword: z.boolean().optional(),51});52export const publishOutput = z.object({53 ...success,54 address,55 url: z.string().url(),56 alias: z.string().nullable(),57 manifestHash: hash,58 expiresAt: timestamp.nullable(),59 ttl: z.union([z.number().nonnegative(), z.literal("forever")]),60 ttlSource: z.enum(["explicit", "existing-site", "vault", "global"]),61 protected: z.boolean(),62 feedback: z.boolean().optional(),63 seq: z.number().int().positive(),64 files: z.number().int().nonnegative(),65 newBlobs: z.number().int().nonnegative(),66 dedupedBlobs: z.number().int().nonnegative(),67 warnings: z.array(z.string()),68});69export const publishInput = z.object({70 mode: z.enum(["create", "update"]).describe(71 "create always allocates a new site; update requires an existing target and keeps its URL.",72 ),73 vault: vaultName.optional().describe(74 "Required for create. Choose autonomously from nzip_status by purpose/description, sensitivity and retention; obey its password requirement and maxTtl.",75 ),76 target: target.optional().describe("Required for update. Use the address returned by publish."),77 html: z.string().min(1).max(1_000_000).optional().describe(78 "Complete inline HTML to publish as index.html. Supply exactly one of html or path.",79 ),80 path: z.string().min(1).optional().describe(81 "Absolute local file/directory under a server --root. Supply exactly one of path or html.",82 ),83 ttl: ttl.optional().describe(84 "Explicit override in days or forever. Omit to inherit vault TTL on create or preserve expiry on update.",85 ),86 password: z.string().min(4).max(256).nullable().optional().describe(87 "Omit to preserve protection; a string sets it; null explicitly removes it. Never put in notifications.",88 ),89 feedback: z.boolean().optional().describe(90 "true lets visitors who unlocked this password-protected site save notes through /__feedback.js; omit to preserve.",91 ),92}).strict();9394export const feedbackItem = z.object({95 item: z.string(),96 text: z.string(),97 seq: z.number().int().nonnegative(),98 updatedAt: z.number().int().nonnegative(),99});100export const feedback = {101 address,102 url: z.string().url(),103 enabled: z.boolean(),104 seq: z.number().int().nonnegative(),105 requestedAt: z.number().int().nullable(),106 submittedAt: z.number().int().nullable(),107 callbackPending: z.boolean().optional(),108 items: z.array(feedbackItem),109};