@sudobility/screenwriter_types 0.1.1

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.
Files changed (65) hide show
  1. package/CLAUDE.md +50 -0
  2. package/README.md +34 -0
  3. package/dist/account/index.d.ts +440 -0
  4. package/dist/account/index.js +274 -0
  5. package/dist/admin/index.d.ts +95 -0
  6. package/dist/admin/index.js +20 -0
  7. package/dist/ai/index.d.ts +564 -0
  8. package/dist/ai/index.js +179 -0
  9. package/dist/api/envelope.d.ts +33 -0
  10. package/dist/api/envelope.js +140 -0
  11. package/dist/api/pagination.d.ts +7 -0
  12. package/dist/api/pagination.js +9 -0
  13. package/dist/api/routes.d.ts +273 -0
  14. package/dist/api/routes.js +306 -0
  15. package/dist/assets/index.d.ts +722 -0
  16. package/dist/assets/index.js +452 -0
  17. package/dist/collab/index.d.ts +214 -0
  18. package/dist/collab/index.js +211 -0
  19. package/dist/commands/index.d.ts +92 -0
  20. package/dist/commands/index.js +20 -0
  21. package/dist/credits/index.d.ts +26 -0
  22. package/dist/credits/index.js +7 -0
  23. package/dist/formats/index.d.ts +87 -0
  24. package/dist/formats/index.js +26 -0
  25. package/dist/ids/index.d.ts +2 -0
  26. package/dist/ids/index.js +2 -0
  27. package/dist/index.d.ts +33 -0
  28. package/dist/index.js +33 -0
  29. package/dist/io/index.d.ts +395 -0
  30. package/dist/io/index.js +161 -0
  31. package/dist/jobs/index.d.ts +278 -0
  32. package/dist/jobs/index.js +138 -0
  33. package/dist/keys/index.d.ts +53 -0
  34. package/dist/keys/index.js +22 -0
  35. package/dist/lifecycle/index.d.ts +263 -0
  36. package/dist/lifecycle/index.js +148 -0
  37. package/dist/me/index.d.ts +35 -0
  38. package/dist/me/index.js +18 -0
  39. package/dist/packets/index.d.ts +887 -0
  40. package/dist/packets/index.js +312 -0
  41. package/dist/projects/index.d.ts +201 -0
  42. package/dist/projects/index.js +75 -0
  43. package/dist/public/index.d.ts +95 -0
  44. package/dist/public/index.js +25 -0
  45. package/dist/reads/index.d.ts +387 -0
  46. package/dist/reads/index.js +118 -0
  47. package/dist/reports/index.d.ts +168 -0
  48. package/dist/reports/index.js +466 -0
  49. package/dist/sharing/index.d.ts +256 -0
  50. package/dist/sharing/index.js +91 -0
  51. package/dist/sync/codec.d.ts +7 -0
  52. package/dist/sync/codec.js +91 -0
  53. package/dist/sync/index.d.ts +382 -0
  54. package/dist/sync/index.js +262 -0
  55. package/dist/sync/permissions.d.ts +22 -0
  56. package/dist/sync/permissions.js +11 -0
  57. package/dist/templates/index.d.ts +1699 -0
  58. package/dist/templates/index.js +70 -0
  59. package/dist/tenancy/index.d.ts +116 -0
  60. package/dist/tenancy/index.js +102 -0
  61. package/dist/test/index.d.ts +8 -0
  62. package/dist/test/index.js +88 -0
  63. package/dist/versions/index.d.ts +335 -0
  64. package/dist/versions/index.js +107 -0
  65. package/package.json +62 -0
@@ -0,0 +1,395 @@
1
+ import { z } from 'zod';
2
+ import type { ConversionReport } from '../formats/index.js';
3
+ /**
4
+ * Imports, exports and batch watermark as jobs, plus the upload port they share (slice B16; spec 05 §6.18, §6.1 `uploads`,
5
+ * §13). The synchronous `POST /projects/:pid/documents/import`, `POST /documents/:did/export` and `GET /formats` (see
6
+ * `formats/`) stay until the app migrates.
7
+ *
8
+ * Formats are exactly what `writing_formats` has today: import Fountain, FDX and Fade In; export Fountain, FDX and the plain
9
+ * JSON backup. PDF, DOCX, Celtx, Scrivener and OCR answer `IMPORT_FORMAT_UNSUPPORTED` / `EXPORT_FORMAT_UNSUPPORTED` /
10
+ * `OCR_UNAVAILABLE`; nothing fakes them.
11
+ */
12
+ /** Formats `POST /imports` accepts (a job kind `import.<format>` exists for each). */
13
+ export declare const JOB_IMPORT_FORMATS: readonly ["fountain", "fdx", "fadein"];
14
+ export type JobImportFormat = (typeof JOB_IMPORT_FORMATS)[number];
15
+ /** Formats an export job produces (`export.<format>`). */
16
+ export declare const JOB_EXPORT_FORMATS: readonly ["fountain", "fdx", "json"];
17
+ export type JobExportFormat = (typeof JOB_EXPORT_FORMATS)[number];
18
+ /** `POST /documents/export-combined` takes these (spec 05: pdf, fdx, fountain; pdf is not built). */
19
+ export declare const COMBINED_EXPORT_FORMATS: readonly ["fdx", "fountain"];
20
+ /** At most this many documents in one combined export (the job's `sources` cap). */
21
+ export declare const COMBINED_EXPORT_MAX_DOCUMENTS = 20;
22
+ /** At most this many recipients in one batch watermark (spec 05 §6.18). */
23
+ export declare const BATCH_WATERMARK_MAX_RECIPIENTS = 500;
24
+ export declare const UPLOAD_PURPOSES: readonly ["state", "watermark_lookup", "import"];
25
+ export type UploadPurpose = (typeof UPLOAD_PURPOSES)[number];
26
+ /**
27
+ * `POST /uploads/state`. `purpose` defaults to `state` (a Yjs state blob); `watermark_lookup` is a leaked file for
28
+ * `POST /workspaces/:wid/watermark-lookup`. `import` uploads are created by `POST /imports`, never here.
29
+ */
30
+ export declare const uploadStateRequestSchema: z.ZodObject<{
31
+ sizeBytes: z.ZodNumber;
32
+ sha256Hex: z.ZodString;
33
+ purpose: z.ZodDefault<z.ZodEnum<{
34
+ state: "state";
35
+ watermark_lookup: "watermark_lookup";
36
+ }>>;
37
+ }, z.core.$strip>;
38
+ export type UploadStateRequest = z.input<typeof uploadStateRequestSchema>;
39
+ /** A presigned PUT: send the bytes with `PUT url` (no `Authorization`), then use `uploadKey`. */
40
+ export interface UploadStateResponse {
41
+ uploadKey: string;
42
+ url: string;
43
+ /** When the PUT url stops working (`SIGNED_URL_TTL_S`). */
44
+ expiresAt: string;
45
+ }
46
+ export declare const importOptionsSchema: z.ZodObject<{
47
+ templateId: z.ZodOptional<z.ZodString>;
48
+ ocr: z.ZodDefault<z.ZodEnum<{
49
+ auto: "auto";
50
+ force: "force";
51
+ off: "off";
52
+ }>>;
53
+ ocrLanguage: z.ZodOptional<z.ZodString>;
54
+ title: z.ZodOptional<z.ZodString>;
55
+ kind: z.ZodOptional<z.ZodEnum<{
56
+ outline: "outline";
57
+ script: "script";
58
+ bible: "bible";
59
+ treatment: "treatment";
60
+ other: "other";
61
+ }>>;
62
+ language: z.ZodOptional<z.ZodString>;
63
+ }, z.core.$strip>;
64
+ export type ImportOptions = z.input<typeof importOptionsSchema>;
65
+ /** `POST /imports`: one of `targetProjectId` (import as a new document) or `templateTarget` (a template file, `POST /templates/import {importId}`). */
66
+ export declare const importCreateSchema: z.ZodObject<{
67
+ filename: z.ZodString;
68
+ sizeBytes: z.ZodNumber;
69
+ sha256Hex: z.ZodString;
70
+ format: z.ZodOptional<z.ZodString>;
71
+ options: z.ZodOptional<z.ZodObject<{
72
+ templateId: z.ZodOptional<z.ZodString>;
73
+ ocr: z.ZodDefault<z.ZodEnum<{
74
+ auto: "auto";
75
+ force: "force";
76
+ off: "off";
77
+ }>>;
78
+ ocrLanguage: z.ZodOptional<z.ZodString>;
79
+ title: z.ZodOptional<z.ZodString>;
80
+ kind: z.ZodOptional<z.ZodEnum<{
81
+ outline: "outline";
82
+ script: "script";
83
+ bible: "bible";
84
+ treatment: "treatment";
85
+ other: "other";
86
+ }>>;
87
+ language: z.ZodOptional<z.ZodString>;
88
+ }, z.core.$strip>>;
89
+ targetProjectId: z.ZodOptional<z.ZodString>;
90
+ templateTarget: z.ZodOptional<z.ZodObject<{
91
+ scope: z.ZodEnum<{
92
+ workspace: "workspace";
93
+ user: "user";
94
+ }>;
95
+ workspaceId: z.ZodOptional<z.ZodString>;
96
+ }, z.core.$strip>>;
97
+ }, z.core.$strip>;
98
+ export type ImportCreateRequest = z.input<typeof importCreateSchema>;
99
+ /** `POST /documents/:did/import-over`: the document is the route's. */
100
+ export declare const importOverSchema: z.ZodObject<{
101
+ filename: z.ZodString;
102
+ sizeBytes: z.ZodNumber;
103
+ sha256Hex: z.ZodString;
104
+ format: z.ZodOptional<z.ZodString>;
105
+ options: z.ZodOptional<z.ZodObject<{
106
+ templateId: z.ZodOptional<z.ZodString>;
107
+ ocr: z.ZodDefault<z.ZodEnum<{
108
+ auto: "auto";
109
+ force: "force";
110
+ off: "off";
111
+ }>>;
112
+ ocrLanguage: z.ZodOptional<z.ZodString>;
113
+ title: z.ZodOptional<z.ZodString>;
114
+ kind: z.ZodOptional<z.ZodEnum<{
115
+ outline: "outline";
116
+ script: "script";
117
+ bible: "bible";
118
+ treatment: "treatment";
119
+ other: "other";
120
+ }>>;
121
+ language: z.ZodOptional<z.ZodString>;
122
+ }, z.core.$strip>>;
123
+ }, z.core.$strip>;
124
+ export type ImportOverRequest = z.input<typeof importOverSchema>;
125
+ /** Both answer this: PUT the file to `upload.url`, then `POST /imports/:importId/start`. No job exists yet. */
126
+ export interface ImportCreateResponse {
127
+ importId: string;
128
+ upload: {
129
+ url: string;
130
+ expiresAt: string;
131
+ };
132
+ }
133
+ /** Input stored on `import.<format>` jobs (spec 05 §13). `newDocumentId` is minted at start so a retried run cannot make two documents. */
134
+ export declare const importJobInputSchema: z.ZodObject<{
135
+ importId: z.ZodString;
136
+ targetProjectId: z.ZodString;
137
+ newDocumentId: z.ZodString;
138
+ filename: z.ZodString;
139
+ options: z.ZodOptional<z.ZodObject<{
140
+ templateId: z.ZodOptional<z.ZodString>;
141
+ ocr: z.ZodDefault<z.ZodEnum<{
142
+ auto: "auto";
143
+ force: "force";
144
+ off: "off";
145
+ }>>;
146
+ ocrLanguage: z.ZodOptional<z.ZodString>;
147
+ title: z.ZodOptional<z.ZodString>;
148
+ kind: z.ZodOptional<z.ZodEnum<{
149
+ outline: "outline";
150
+ script: "script";
151
+ bible: "bible";
152
+ treatment: "treatment";
153
+ other: "other";
154
+ }>>;
155
+ language: z.ZodOptional<z.ZodString>;
156
+ }, z.core.$strip>>;
157
+ }, z.core.$strip>;
158
+ export type ImportJobInput = z.infer<typeof importJobInputSchema>;
159
+ /** Input stored on `doc.importOver` jobs. */
160
+ export declare const importOverJobInputSchema: z.ZodObject<{
161
+ importId: z.ZodString;
162
+ documentId: z.ZodString;
163
+ filename: z.ZodString;
164
+ options: z.ZodOptional<z.ZodObject<{
165
+ templateId: z.ZodOptional<z.ZodString>;
166
+ ocr: z.ZodDefault<z.ZodEnum<{
167
+ auto: "auto";
168
+ force: "force";
169
+ off: "off";
170
+ }>>;
171
+ ocrLanguage: z.ZodOptional<z.ZodString>;
172
+ title: z.ZodOptional<z.ZodString>;
173
+ kind: z.ZodOptional<z.ZodEnum<{
174
+ outline: "outline";
175
+ script: "script";
176
+ bible: "bible";
177
+ treatment: "treatment";
178
+ other: "other";
179
+ }>>;
180
+ language: z.ZodOptional<z.ZodString>;
181
+ }, z.core.$strip>>;
182
+ }, z.core.$strip>;
183
+ export type ImportOverJobInput = z.infer<typeof importOverJobInputSchema>;
184
+ /** One document an import made; the job's outputs carry one `conversion-report.json` per document (`output.documentId`). */
185
+ export interface ImportedDocumentRef {
186
+ documentId: string;
187
+ title: string;
188
+ format: string;
189
+ }
190
+ /** What a finished `import.*` job stores as `result` (also readable from the outputs). */
191
+ export interface ImportJobResult {
192
+ documents: ImportedDocumentRef[];
193
+ report: ConversionReport;
194
+ }
195
+ /** What a finished `doc.importOver` job stores as `result`. */
196
+ export interface ImportOverJobResult {
197
+ documentId: string;
198
+ epoch: number;
199
+ preImportSnapshotId: string;
200
+ format: string;
201
+ report: ConversionReport;
202
+ }
203
+ /** Name of the per-document (import) or per-file (export) conversion report output. */
204
+ export declare const CONVERSION_REPORT_OUTPUT = "conversion-report.json";
205
+ /** Visible watermark. `text` tokens: `{recipient}`, `{email}`, `{company}`, `{title}`, `{date}`. */
206
+ export declare const watermarkStyleSchema: z.ZodObject<{
207
+ text: z.ZodDefault<z.ZodString>;
208
+ opacity: z.ZodOptional<z.ZodNumber>;
209
+ position: z.ZodOptional<z.ZodEnum<{
210
+ diagonalAscending: "diagonalAscending";
211
+ diagonalDescending: "diagonalDescending";
212
+ horizontal: "horizontal";
213
+ }>>;
214
+ }, z.core.$strip>;
215
+ export type WatermarkStyle = z.input<typeof watermarkStyleSchema>;
216
+ export declare const batchWatermarkSchema: z.ZodObject<{
217
+ recipients: z.ZodArray<z.ZodObject<{
218
+ name: z.ZodString;
219
+ email: z.ZodOptional<z.ZodString>;
220
+ company: z.ZodOptional<z.ZodString>;
221
+ }, z.core.$strip>>;
222
+ visible: z.ZodOptional<z.ZodObject<{
223
+ text: z.ZodDefault<z.ZodString>;
224
+ opacity: z.ZodOptional<z.ZodNumber>;
225
+ position: z.ZodOptional<z.ZodEnum<{
226
+ diagonalAscending: "diagonalAscending";
227
+ diagonalDescending: "diagonalDescending";
228
+ horizontal: "horizontal";
229
+ }>>;
230
+ }, z.core.$strip>>;
231
+ invisible: z.ZodDefault<z.ZodBoolean>;
232
+ deliver: z.ZodDefault<z.ZodEnum<{
233
+ email: "email";
234
+ download: "download";
235
+ }>>;
236
+ emailMessage: z.ZodOptional<z.ZodString>;
237
+ }, z.core.$strip>;
238
+ export type BatchWatermark = z.input<typeof batchWatermarkSchema>;
239
+ export declare const exportOptionsSchema: z.ZodObject<{
240
+ filename: z.ZodOptional<z.ZodString>;
241
+ batchWatermark: z.ZodOptional<z.ZodObject<{
242
+ recipients: z.ZodArray<z.ZodObject<{
243
+ name: z.ZodString;
244
+ email: z.ZodOptional<z.ZodString>;
245
+ company: z.ZodOptional<z.ZodString>;
246
+ }, z.core.$strip>>;
247
+ visible: z.ZodOptional<z.ZodObject<{
248
+ text: z.ZodDefault<z.ZodString>;
249
+ opacity: z.ZodOptional<z.ZodNumber>;
250
+ position: z.ZodOptional<z.ZodEnum<{
251
+ diagonalAscending: "diagonalAscending";
252
+ diagonalDescending: "diagonalDescending";
253
+ horizontal: "horizontal";
254
+ }>>;
255
+ }, z.core.$strip>>;
256
+ invisible: z.ZodDefault<z.ZodBoolean>;
257
+ deliver: z.ZodDefault<z.ZodEnum<{
258
+ email: "email";
259
+ download: "download";
260
+ }>>;
261
+ emailMessage: z.ZodOptional<z.ZodString>;
262
+ }, z.core.$strip>>;
263
+ }, z.core.$strip>;
264
+ export type ExportOptions = z.input<typeof exportOptionsSchema>;
265
+ /** `POST /documents/:did/exports`. `format` is validated by the server (`EXPORT_FORMAT_UNSUPPORTED` for anything but fountain, fdx, json). */
266
+ export declare const exportCreateSchema: z.ZodObject<{
267
+ format: z.ZodString;
268
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
269
+ kind: z.ZodLiteral<"live">;
270
+ }, z.core.$strip>, z.ZodObject<{
271
+ kind: z.ZodLiteral<"snapshot">;
272
+ snapshotId: z.ZodString;
273
+ }, z.core.$strip>, z.ZodObject<{
274
+ kind: z.ZodLiteral<"version">;
275
+ versionId: z.ZodString;
276
+ }, z.core.$strip>], "kind">>;
277
+ options: z.ZodOptional<z.ZodObject<{
278
+ filename: z.ZodOptional<z.ZodString>;
279
+ batchWatermark: z.ZodOptional<z.ZodObject<{
280
+ recipients: z.ZodArray<z.ZodObject<{
281
+ name: z.ZodString;
282
+ email: z.ZodOptional<z.ZodString>;
283
+ company: z.ZodOptional<z.ZodString>;
284
+ }, z.core.$strip>>;
285
+ visible: z.ZodOptional<z.ZodObject<{
286
+ text: z.ZodDefault<z.ZodString>;
287
+ opacity: z.ZodOptional<z.ZodNumber>;
288
+ position: z.ZodOptional<z.ZodEnum<{
289
+ diagonalAscending: "diagonalAscending";
290
+ diagonalDescending: "diagonalDescending";
291
+ horizontal: "horizontal";
292
+ }>>;
293
+ }, z.core.$strip>>;
294
+ invisible: z.ZodDefault<z.ZodBoolean>;
295
+ deliver: z.ZodDefault<z.ZodEnum<{
296
+ email: "email";
297
+ download: "download";
298
+ }>>;
299
+ emailMessage: z.ZodOptional<z.ZodString>;
300
+ }, z.core.$strip>>;
301
+ }, z.core.$strip>>;
302
+ }, z.core.$strip>;
303
+ export type ExportCreateRequest = z.input<typeof exportCreateSchema>;
304
+ /** `POST /documents/export-combined`: the first document's title page and template, bodies concatenated in the order given. */
305
+ export declare const exportCombinedSchema: z.ZodObject<{
306
+ documentIds: z.ZodArray<z.ZodString>;
307
+ format: z.ZodString;
308
+ options: z.ZodOptional<z.ZodObject<{
309
+ filename: z.ZodOptional<z.ZodString>;
310
+ }, z.core.$strip>>;
311
+ }, z.core.$strip>;
312
+ export type ExportCombinedRequest = z.input<typeof exportCombinedSchema>;
313
+ /** Input stored on `export.<format>` and `watermark.batch` jobs. */
314
+ export declare const exportJobInputSchema: z.ZodObject<{
315
+ format: z.ZodEnum<{
316
+ json: "json";
317
+ fountain: "fountain";
318
+ fdx: "fdx";
319
+ }>;
320
+ documentIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
321
+ source: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
322
+ kind: z.ZodLiteral<"live">;
323
+ }, z.core.$strip>, z.ZodObject<{
324
+ kind: z.ZodLiteral<"snapshot">;
325
+ snapshotId: z.ZodString;
326
+ }, z.core.$strip>, z.ZodObject<{
327
+ kind: z.ZodLiteral<"version">;
328
+ versionId: z.ZodString;
329
+ }, z.core.$strip>], "kind">>;
330
+ options: z.ZodOptional<z.ZodObject<{
331
+ filename: z.ZodOptional<z.ZodString>;
332
+ batchWatermark: z.ZodOptional<z.ZodObject<{
333
+ recipients: z.ZodArray<z.ZodObject<{
334
+ name: z.ZodString;
335
+ email: z.ZodOptional<z.ZodString>;
336
+ company: z.ZodOptional<z.ZodString>;
337
+ }, z.core.$strip>>;
338
+ visible: z.ZodOptional<z.ZodObject<{
339
+ text: z.ZodDefault<z.ZodString>;
340
+ opacity: z.ZodOptional<z.ZodNumber>;
341
+ position: z.ZodOptional<z.ZodEnum<{
342
+ diagonalAscending: "diagonalAscending";
343
+ diagonalDescending: "diagonalDescending";
344
+ horizontal: "horizontal";
345
+ }>>;
346
+ }, z.core.$strip>>;
347
+ invisible: z.ZodDefault<z.ZodBoolean>;
348
+ deliver: z.ZodDefault<z.ZodEnum<{
349
+ email: "email";
350
+ download: "download";
351
+ }>>;
352
+ emailMessage: z.ZodOptional<z.ZodString>;
353
+ }, z.core.$strip>>;
354
+ }, z.core.$strip>>;
355
+ }, z.core.$strip>;
356
+ export type ExportJobInput = z.infer<typeof exportJobInputSchema>;
357
+ /** What a finished `watermark.batch` job stores as `result`. `invisibleApplied` is false for every text format. */
358
+ export interface WatermarkBatchResult {
359
+ recipients: number;
360
+ format: JobExportFormat;
361
+ visibleApplied: boolean;
362
+ invisibleApplied: boolean;
363
+ /** How the export code travels in the file. */
364
+ codeCarrier: 'fountain-note' | 'fdx-comment' | 'json-field';
365
+ }
366
+ /** Prefix of an export code as printed in a file: `FWX-` + 26 base32 characters (128 random bits). */
367
+ export declare const EXPORT_CODE_PREFIX = "FWX-";
368
+ /** `{exportId}` or `{pdfUploadKey}` (a leaked file uploaded through `/uploads/state` with `purpose: "watermark_lookup"`). */
369
+ export declare const watermarkLookupSchema: z.ZodObject<{
370
+ exportId: z.ZodOptional<z.ZodString>;
371
+ pdfUploadKey: z.ZodOptional<z.ZodString>;
372
+ }, z.core.$strip>;
373
+ export type WatermarkLookupRequest = z.input<typeof watermarkLookupSchema>;
374
+ export interface WatermarkMatch {
375
+ exportId: string;
376
+ recipient: {
377
+ name: string;
378
+ email: string | null;
379
+ company: string | null;
380
+ };
381
+ documentId: string | null;
382
+ documentTitle: string | null;
383
+ /** Display name (else email) of who ran the export. */
384
+ exportedBy: string | null;
385
+ exportedAt: string;
386
+ source: {
387
+ documentId: string | null;
388
+ kind: 'live' | 'snapshot' | 'version';
389
+ snapshotId?: string;
390
+ versionId?: string;
391
+ };
392
+ }
393
+ export interface WatermarkLookupResponse {
394
+ matches: WatermarkMatch[];
395
+ }
@@ -0,0 +1,161 @@
1
+ import { z } from 'zod';
2
+ import { documentKindSchema } from '../projects/index.js';
3
+ import { docSourceSchema } from '../reads/index.js';
4
+ /**
5
+ * Imports, exports and batch watermark as jobs, plus the upload port they share (slice B16; spec 05 §6.18, §6.1 `uploads`,
6
+ * §13). The synchronous `POST /projects/:pid/documents/import`, `POST /documents/:did/export` and `GET /formats` (see
7
+ * `formats/`) stay until the app migrates.
8
+ *
9
+ * Formats are exactly what `writing_formats` has today: import Fountain, FDX and Fade In; export Fountain, FDX and the plain
10
+ * JSON backup. PDF, DOCX, Celtx, Scrivener and OCR answer `IMPORT_FORMAT_UNSUPPORTED` / `EXPORT_FORMAT_UNSUPPORTED` /
11
+ * `OCR_UNAVAILABLE`; nothing fakes them.
12
+ */
13
+ /** Formats `POST /imports` accepts (a job kind `import.<format>` exists for each). */
14
+ export const JOB_IMPORT_FORMATS = ['fountain', 'fdx', 'fadein'];
15
+ /** Formats an export job produces (`export.<format>`). */
16
+ export const JOB_EXPORT_FORMATS = ['fountain', 'fdx', 'json'];
17
+ /** `POST /documents/export-combined` takes these (spec 05: pdf, fdx, fountain; pdf is not built). */
18
+ export const COMBINED_EXPORT_FORMATS = ['fdx', 'fountain'];
19
+ /** At most this many documents in one combined export (the job's `sources` cap). */
20
+ export const COMBINED_EXPORT_MAX_DOCUMENTS = 20;
21
+ /** At most this many recipients in one batch watermark (spec 05 §6.18). */
22
+ export const BATCH_WATERMARK_MAX_RECIPIENTS = 500;
23
+ // ─── uploads (spec 05 §6.1 `uploads`, §8) ─────────────────────────────────────
24
+ export const UPLOAD_PURPOSES = ['state', 'watermark_lookup', 'import'];
25
+ const sha256HexSchema = z
26
+ .string()
27
+ .regex(/^[0-9a-fA-F]{64}$/, 'sha256Hex must be 64 hex characters');
28
+ /**
29
+ * `POST /uploads/state`. `purpose` defaults to `state` (a Yjs state blob); `watermark_lookup` is a leaked file for
30
+ * `POST /workspaces/:wid/watermark-lookup`. `import` uploads are created by `POST /imports`, never here.
31
+ */
32
+ export const uploadStateRequestSchema = z.object({
33
+ sizeBytes: z.number().int().min(1),
34
+ sha256Hex: sha256HexSchema,
35
+ purpose: z.enum(['state', 'watermark_lookup']).default('state'),
36
+ });
37
+ // ─── imports ─────────────────────────────────────────────────────────────────
38
+ export const importOptionsSchema = z.object({
39
+ templateId: z.string().min(1).optional(),
40
+ /** `auto`: OCR a PDF without a text layer; `force`; `off`. No OCR exists yet: `force` is `OCR_UNAVAILABLE`. */
41
+ ocr: z.enum(['auto', 'force', 'off']).default('auto'),
42
+ ocrLanguage: z.string().min(2).max(16).optional(),
43
+ title: z.string().trim().min(1).max(200).optional(),
44
+ kind: documentKindSchema.optional(),
45
+ language: z.string().max(16).optional(),
46
+ });
47
+ const importFileFields = {
48
+ filename: z.string().min(1).max(500),
49
+ sizeBytes: z.number().int().min(1),
50
+ sha256Hex: sha256HexSchema,
51
+ /** Auto-detected from the uploaded bytes when omitted. */
52
+ format: z.string().min(1).max(32).optional(),
53
+ options: importOptionsSchema.optional(),
54
+ };
55
+ /** `POST /imports`: one of `targetProjectId` (import as a new document) or `templateTarget` (a template file, `POST /templates/import {importId}`). */
56
+ export const importCreateSchema = z
57
+ .object({
58
+ targetProjectId: z.string().min(1).optional(),
59
+ templateTarget: z
60
+ .object({
61
+ scope: z.enum(['user', 'workspace']),
62
+ workspaceId: z.string().min(1).optional(),
63
+ })
64
+ .refine((v) => v.scope !== 'workspace' || !!v.workspaceId, {
65
+ message: 'workspaceId is required for a workspace template',
66
+ path: ['workspaceId'],
67
+ })
68
+ .optional(),
69
+ ...importFileFields,
70
+ })
71
+ .refine((v) => (v.targetProjectId ? 1 : 0) + (v.templateTarget ? 1 : 0) === 1, {
72
+ message: 'Send exactly one of targetProjectId and templateTarget',
73
+ path: ['targetProjectId'],
74
+ });
75
+ /** `POST /documents/:did/import-over`: the document is the route's. */
76
+ export const importOverSchema = z.object(importFileFields);
77
+ /** Input stored on `import.<format>` jobs (spec 05 §13). `newDocumentId` is minted at start so a retried run cannot make two documents. */
78
+ export const importJobInputSchema = z.object({
79
+ importId: z.string().min(1),
80
+ targetProjectId: z.string().min(1),
81
+ newDocumentId: z.string().min(1),
82
+ filename: z.string().min(1).max(500),
83
+ options: importOptionsSchema.optional(),
84
+ });
85
+ /** Input stored on `doc.importOver` jobs. */
86
+ export const importOverJobInputSchema = z.object({
87
+ importId: z.string().min(1),
88
+ documentId: z.string().min(1),
89
+ filename: z.string().min(1).max(500),
90
+ options: importOptionsSchema.optional(),
91
+ });
92
+ /** Name of the per-document (import) or per-file (export) conversion report output. */
93
+ export const CONVERSION_REPORT_OUTPUT = 'conversion-report.json';
94
+ // ─── exports ─────────────────────────────────────────────────────────────────
95
+ /** Visible watermark. `text` tokens: `{recipient}`, `{email}`, `{company}`, `{title}`, `{date}`. */
96
+ export const watermarkStyleSchema = z.object({
97
+ text: z.string().min(1).max(200).default('{recipient}'),
98
+ opacity: z.number().min(0.05).max(1).optional(),
99
+ position: z
100
+ .enum(['diagonalAscending', 'diagonalDescending', 'horizontal'])
101
+ .optional(),
102
+ });
103
+ export const batchWatermarkSchema = z.object({
104
+ recipients: z
105
+ .array(z.object({
106
+ name: z.string().trim().min(1).max(200),
107
+ email: z.string().trim().min(1).max(320).optional(),
108
+ company: z.string().trim().min(1).max(200).optional(),
109
+ }))
110
+ .min(1)
111
+ .max(BATCH_WATERMARK_MAX_RECIPIENTS),
112
+ visible: watermarkStyleSchema.optional(),
113
+ /** Forensic mark. Only a PDF writer can embed one; text formats carry the export code as a visible note (see the API notes). */
114
+ invisible: z.boolean().default(false),
115
+ /** `email` needs the notification slice (B12): refused with `VALIDATION` until then. */
116
+ deliver: z.enum(['download', 'email']).default('download'),
117
+ emailMessage: z.string().max(2000).optional(),
118
+ });
119
+ export const exportOptionsSchema = z.object({
120
+ /** Download name without extension (default: the document title). */
121
+ filename: z.string().trim().min(1).max(120).optional(),
122
+ batchWatermark: batchWatermarkSchema.optional(),
123
+ });
124
+ /** `POST /documents/:did/exports`. `format` is validated by the server (`EXPORT_FORMAT_UNSUPPORTED` for anything but fountain, fdx, json). */
125
+ export const exportCreateSchema = z.object({
126
+ format: z.string().min(1).max(32),
127
+ source: docSourceSchema.optional(),
128
+ options: exportOptionsSchema.optional(),
129
+ });
130
+ /** `POST /documents/export-combined`: the first document's title page and template, bodies concatenated in the order given. */
131
+ export const exportCombinedSchema = z.object({
132
+ documentIds: z
133
+ .array(z.string().min(1))
134
+ .min(1)
135
+ .max(COMBINED_EXPORT_MAX_DOCUMENTS),
136
+ format: z.string().min(1).max(32),
137
+ options: exportOptionsSchema.omit({ batchWatermark: true }).optional(),
138
+ });
139
+ /** Input stored on `export.<format>` and `watermark.batch` jobs. */
140
+ export const exportJobInputSchema = z.object({
141
+ format: z.enum(JOB_EXPORT_FORMATS),
142
+ documentIds: z
143
+ .array(z.string().min(1))
144
+ .max(COMBINED_EXPORT_MAX_DOCUMENTS)
145
+ .optional(),
146
+ source: docSourceSchema.optional(),
147
+ options: exportOptionsSchema.optional(),
148
+ });
149
+ // ─── watermark lookup ────────────────────────────────────────────────────────
150
+ /** Prefix of an export code as printed in a file: `FWX-` + 26 base32 characters (128 random bits). */
151
+ export const EXPORT_CODE_PREFIX = 'FWX-';
152
+ /** `{exportId}` or `{pdfUploadKey}` (a leaked file uploaded through `/uploads/state` with `purpose: "watermark_lookup"`). */
153
+ export const watermarkLookupSchema = z
154
+ .object({
155
+ exportId: z.string().trim().min(8).max(64).optional(),
156
+ pdfUploadKey: z.string().min(1).max(100).optional(),
157
+ })
158
+ .refine((v) => (v.exportId ? 1 : 0) + (v.pdfUploadKey ? 1 : 0) === 1, {
159
+ message: 'Send exactly one of exportId and pdfUploadKey',
160
+ path: ['exportId'],
161
+ });