@sudobility/screenwriter_types 0.1.1 → 0.1.2

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.
@@ -1,140 +0,0 @@
1
- /**
2
- * Response envelope, error vocabulary (spec 05 §12) and pagination shape.
3
- * Platform-free: no clock is read here, so the envelope carries no timestamp.
4
- */
5
- /** Every REST error code and its fixed HTTP status (spec 05 §12). */
6
- const ERROR_TABLE = [
7
- ['UNAUTHORIZED', 401],
8
- ['REAUTH_REQUIRED', 401],
9
- ['API_KEY_FORBIDDEN', 403],
10
- ['FORBIDDEN', 403],
11
- ['ROLE_ESCALATION', 403],
12
- ['NOT_FOUND', 404],
13
- ['PROJECT_NOT_FOUND', 404],
14
- ['DOCUMENT_NOT_FOUND', 404],
15
- ['SNAPSHOT_NOT_FOUND', 404],
16
- ['TEMPLATE_NOT_FOUND', 404],
17
- ['ITEM_NOT_FOUND', 404],
18
- ['ANCHOR_NOT_FOUND', 404],
19
- ['TARGET_NOT_FOUND', 404],
20
- ['VALIDATION', 400],
21
- ['COMMAND_INVALID', 422],
22
- ['TEMPLATE_INVALID', 422],
23
- ['CONFIRMATION_MISMATCH', 400],
24
- ['EPOCH_MISMATCH', 409],
25
- ['DOCUMENT_LOCKED', 423],
26
- ['DOCUMENT_BUSY', 409],
27
- ['JOB_ALREADY_RUNNING', 409],
28
- ['JOB_FINISHED', 409],
29
- ['JOB_NOT_FINISHED', 409],
30
- ['LAST_OWNER', 409],
31
- ['ALREADY_MEMBER', 409],
32
- ['NOT_A_MEMBER', 409],
33
- ['PERSONAL_WORKSPACE_IMMUTABLE', 409],
34
- ['OWNS_TEAM_WORKSPACE', 409],
35
- ['NOT_IN_TRASH', 409],
36
- ['PARENT_IN_TRASH', 409],
37
- ['FOLDER_DEPTH', 409],
38
- ['FOLDER_CYCLE', 409],
39
- ['MOVE_FORBIDDEN', 403],
40
- ['BUILTIN_IMMUTABLE', 409],
41
- ['LOCATOR_AMBIGUOUS', 409],
42
- ['INVITATION_INVALID', 410],
43
- ['INVITATION_EXPIRED', 410],
44
- ['INVITATION_CLOSED', 410],
45
- ['EMAIL_MISMATCH', 403],
46
- ['SHARE_LINK_INVALID', 404],
47
- ['SHARE_LINK_PASSWORD_REQUIRED', 401],
48
- ['WATERMARK_REQUIRED', 403],
49
- ['EDIT_WINDOW_CLOSED', 409],
50
- ['ASSET_TOO_LARGE', 413],
51
- ['IMPORT_TOO_LARGE', 413],
52
- ['UNSUPPORTED_FORMAT', 400],
53
- ['IMPORT_FAILED', 400],
54
- ['IMPORT_INVALID', 422],
55
- ['ASSET_TYPE_REJECTED', 415],
56
- ['ASSET_CHECKSUM_MISMATCH', 422],
57
- ['ASSET_NOT_READY', 409],
58
- ['ASSET_IN_USE', 409],
59
- ['UPLOAD_INCOMPLETE', 409],
60
- ['UPLOAD_EXPIRED', 410],
61
- ['STORAGE_QUOTA_EXCEEDED', 507],
62
- ['STORAGE_UNAVAILABLE', 503],
63
- ['IMPORT_FORMAT_UNSUPPORTED', 415],
64
- ['EXPORT_FORMAT_UNSUPPORTED', 415],
65
- ['COMPARE_TOO_LARGE', 413],
66
- ['LIMIT_EXCEEDED', 409],
67
- ['RATE_LIMITED', 429],
68
- ['QUOTA_EXCEEDED', 429],
69
- ['INSUFFICIENT_CREDITS', 402],
70
- ['AI_UNAVAILABLE', 503],
71
- ['AI_INPUT_TOO_LARGE', 413],
72
- ['AI_GENERATION_FAILED', 502],
73
- ['AI_OUTPUT_INVALID', 502],
74
- ['CONFIG_MISSING', 503],
75
- ['CLIENT_TOO_OLD', 426],
76
- ['CONTENT_CHANGED', 409],
77
- ['STYLE_NOT_IN_TEMPLATE', 422],
78
- ['NOT_CONTIGUOUS', 422],
79
- ['LOCKED_CONTENT', 409],
80
- ['NAME_COLLISION', 409],
81
- ['KIND_MISMATCH', 422],
82
- ['OVERLAPPING_SHOTS', 422],
83
- ['OVERLAPPING_NODE', 422],
84
- ['SCENES_LOCKED', 409],
85
- ['NOT_LOCKED', 409],
86
- ['RANGE_OUT_OF_BOUNDS', 422],
87
- ['INVALID_TARGET', 422],
88
- ['INVALID_DUAL_DIALOGUE', 422],
89
- ['FOUNTAIN_PARSE_ERROR', 422],
90
- ['UNMAPPED_STYLES', 422],
91
- ['RANGE_TOO_LARGE', 413],
92
- ['PAYLOAD_TOO_LARGE', 413],
93
- ['INVALID_REGEX', 400],
94
- ['REPORT_OPTIONS_INVALID', 400],
95
- ['REPORT_KIND_UNAVAILABLE', 501],
96
- ['ENTITY_IN_USE', 409],
97
- ['VARIANT_IN_USE', 409],
98
- ['SNAPSHOT_NOT_IN_DOCUMENT', 404],
99
- ['ITEM_NOT_IN_SNAPSHOT', 404],
100
- ['INVALID_LOCATOR', 400],
101
- ['LOCATOR_NOT_FOUND', 404],
102
- ['ROLE_NOT_ALLOWED_FOR_TARGET', 422],
103
- ['ID_CONFLICT', 409],
104
- ['IDEMPOTENCY_KEY_REUSED', 409],
105
- ['IDEMPOTENCY_IN_PROGRESS', 409],
106
- ['DEVICE_REVOKED', 403],
107
- ['MACRO_TRIGGER_TAKEN', 409],
108
- ['STALE_WRITE', 409],
109
- ['HANDOFF_INVALID', 410],
110
- ['WATERMARK_NOT_FOUND', 404],
111
- ['OCR_UNAVAILABLE', 503],
112
- ['GRAMMAR_UNAVAILABLE', 503],
113
- ['AI_CONSENT_REQUIRED', 403],
114
- ['AI_DISABLED_FOR_WORKSPACE', 403],
115
- ['AI_EXCLUDED_DOCUMENT', 403],
116
- ['AI_KEY_NOT_PERMITTED', 403],
117
- ['QUOTE_EXCEEDS_MAX', 402],
118
- ['AI_CONTENT_REFUSED', 422],
119
- ['SCOPE_TOO_LARGE', 413],
120
- ['SUGGESTION_UNAVAILABLE', 409],
121
- ['JOB_KIND_DISABLED', 501],
122
- ['JOB_KIND_NOT_GENERIC', 400],
123
- ['JOB_FAILED', 409],
124
- ['JOB_TIMEOUT', 504],
125
- ['LIKENESS_CONSENT_REQUIRED', 422],
126
- ['CONTENT_REJECTED', 422],
127
- ['INTERNAL', 500],
128
- ];
129
- export const API_ERROR_CODES = Object.fromEntries(ERROR_TABLE.map(([code]) => [code, code]));
130
- /** HTTP status per error code. */
131
- export const ERROR_STATUS = Object.fromEntries(ERROR_TABLE);
132
- export function successResponse(data) {
133
- return { success: true, data };
134
- }
135
- /** The only constructor for failure envelopes. */
136
- export function errorResponse(message, code, details) {
137
- return details === undefined
138
- ? { success: false, error: message, code }
139
- : { success: false, error: message, code, details };
140
- }
@@ -1,9 +0,0 @@
1
- import { z } from 'zod';
2
- /** `limit` 1-200 (default 50); `cursor` is an opaque base64url string. */
3
- export const cursorQuerySchema = z.object({
4
- limit: z.coerce.number().int().min(1).max(200).default(50),
5
- cursor: z
6
- .string()
7
- .regex(/^[A-Za-z0-9_-]+$/)
8
- .optional(),
9
- });
@@ -1,306 +0,0 @@
1
- /**
2
- * Route table for slices B1-B5 (spec 05 §6). Paths are relative to API_BASE_PATH.
3
- * `auth` uses the spec legend: U user, K key (r/rw scope), L link, P public.
4
- * `permission` is the spec 05 §5.2 permission checked on the resolved object.
5
- */
6
- export const API_BASE_PATH = '/api/v1';
7
- const r = (method, path, auth, permission = null) => ({ method, path, auth, permission });
8
- export const API_ROUTES = {
9
- // B1
10
- health: r('GET', '/health', 'P'),
11
- meGet: r('GET', '/me', 'U,Kr'),
12
- mePatch: r('PATCH', '/me', 'U'),
13
- // B2 workspaces
14
- workspacesList: r('GET', '/workspaces', 'U,Kr'),
15
- workspaceGet: r('GET', '/workspaces/:wid', 'U,Kr', 'workspace.read'),
16
- // B2 projects
17
- projectsList: r('GET', '/workspaces/:wid/projects', 'U,Kr', 'project.read'),
18
- projectCreate: r('POST', '/workspaces/:wid/projects', 'U,Krw', 'project.create'),
19
- projectGet: r('GET', '/projects/:pid', 'U,Kr,L', 'project.read'),
20
- projectUpdate: r('PATCH', '/projects/:pid', 'U,Krw', 'project.update'),
21
- projectTrash: r('POST', '/projects/:pid/trash', 'U,Krw', 'project.trash'),
22
- projectRestore: r('POST', '/projects/:pid/restore', 'U,Krw', 'project.restore'),
23
- // B2 documents
24
- documentsList: r('GET', '/projects/:pid/documents', 'U,Kr,L', 'document.read'),
25
- documentCreate: r('POST', '/projects/:pid/documents', 'U,Krw', 'document.create'),
26
- documentGet: r('GET', '/documents/:did', 'U,Kr,L', 'document.read'),
27
- documentUpdate: r('PATCH', '/documents/:did', 'U,Krw', 'document.edit'),
28
- documentTrash: r('POST', '/documents/:did/trash', 'U,Krw', 'document.trash'),
29
- documentRestore: r('POST', '/documents/:did/restore', 'U,Krw', 'document.restore'),
30
- documentState: r('GET', '/documents/:did/state', 'U,Kr,L', 'document.read'),
31
- documentContent: r('GET', '/documents/:did/content', 'U,Kr,L', 'document.read'),
32
- // B2 templates
33
- templatesList: r('GET', '/templates', 'U,Kr'),
34
- templateGet: r('GET', '/templates/:tid', 'U,Kr'),
35
- // B3 sync (WebSocket upgrade, credentials travel in the first `auth` frame)
36
- sync: r('GET', '/sync', 'P'),
37
- // B4 versions and snapshots
38
- versionsList: r('GET', '/documents/:did/versions', 'U,Kr,L', 'document.read'),
39
- versionState: r('GET', '/documents/:did/versions/:vid/state', 'U,Kr,L', 'document.read'),
40
- versionRestore: r('POST', '/documents/:did/versions/:vid/restore', 'U,Krw', 'document.restore'),
41
- versionSnapshot: r('POST', '/documents/:did/versions/:vid/snapshot', 'U,Krw', 'snapshot.create'),
42
- snapshotsList: r('GET', '/documents/:did/snapshots', 'U,Kr,L', 'snapshot.read'),
43
- snapshotCreate: r('POST', '/documents/:did/snapshots', 'U,Krw', 'snapshot.create'),
44
- snapshotGet: r('GET', '/snapshots/:sid', 'U,Kr,L', 'snapshot.read'),
45
- snapshotState: r('GET', '/snapshots/:sid/state', 'U,Kr,L', 'snapshot.read'),
46
- snapshotContent: r('GET', '/snapshots/:sid/content', 'U,Kr,L', 'snapshot.read'),
47
- snapshotOpen: r('POST', '/snapshots/:sid/open', 'U,Krw', 'snapshot.open'),
48
- snapshotFork: r('POST', '/snapshots/:sid/fork', 'U,Krw', 'snapshot.read'),
49
- // B15 versions, snapshots and sync completion (spec 05 §6.7.1, §6.9-6.11)
50
- elementHistory: r('GET', '/documents/:did/elements/:elementId/history', 'U,Kr', 'document.read'),
51
- documentPresence: r('GET', '/documents/:did/presence', 'U,Kr', 'document.read'),
52
- versionRestoreAsCopy: r('POST', '/documents/:did/versions/:vid/restore-as-copy', 'U,Krw', 'version.restoreAsCopy'),
53
- snapshotPrefs: r('PUT', '/snapshots/:sid/prefs', 'U', 'snapshot.hideForSelf'),
54
- snapshotNotesList: r('GET', '/snapshots/:sid/notes', 'U,Kr,L', 'snapshot.read'),
55
- snapshotNoteCreate: r('POST', '/snapshots/:sid/notes', 'U,Krw', 'snapshot.appendNote'),
56
- snapshotCommentsList: r('GET', '/snapshots/:sid/comments', 'U,Kr,L', 'snapshot.read'),
57
- snapshotCommentCreate: r('POST', '/snapshots/:sid/comments', 'U,L', 'document.comment'),
58
- snapshotCommentCopyToLive: r('POST', '/snapshot-comments/:cid/copy-to-live', 'U', 'document.edit'),
59
- snapshotCommentResolve: r('POST', '/snapshot-comments/:cid/resolve', 'U', 'document.comment'),
60
- documentCompare: r('POST', '/documents/:did/compare', 'U,Kr,L', 'snapshot.read'),
61
- // Import and export (synchronous, no jobs)
62
- documentImport: r('POST', '/projects/:pid/documents/import', 'U,Krw', 'document.create'),
63
- documentExport: r('POST', '/documents/:did/export', 'U,Kr', 'document.read'),
64
- formatsList: r('GET', '/formats', 'U,Kr'),
65
- // B5 commands and reads
66
- commands: r('POST', '/documents/:did/commands', 'U,Krw', 'document.edit'),
67
- outline: r('GET', '/documents/:did/outline', 'U,Kr,L', 'document.read'),
68
- scene: r('GET', '/documents/:did/scenes/:sceneId', 'U,Kr,L', 'document.read'),
69
- scenesBatch: r('POST', '/documents/:did/scenes/batch', 'U,Kr,L', 'document.read'),
70
- elementsBatch: r('POST', '/documents/:did/elements/batch', 'U,Kr,L', 'document.read'),
71
- // B6 personal API keys (user principals only; a key gets 403 API_KEY_FORBIDDEN)
72
- apiKeysList: r('GET', '/api-keys', 'U'),
73
- apiKeyCreate: r('POST', '/api-keys', 'U', 'apiKeys.use'),
74
- apiKeyUpdate: r('PATCH', '/api-keys/:kid', 'U'),
75
- apiKeyRevoke: r('DELETE', '/api-keys/:kid', 'U'),
76
- // B7 AI: script review and polish. Keys need the `ai` flag (403 AI_KEY_NOT_PERMITTED) and, to start
77
- // jobs or decide suggestions, read_write scope.
78
- aiStatus: r('GET', '/ai/status', 'U,Kr'),
79
- aiJobCreate: r('POST', '/documents/:did/ai/jobs', 'U,Krw', 'ai.run'),
80
- aiJobsList: r('GET', '/documents/:did/ai/jobs', 'U,Kr', 'document.read'),
81
- aiJobGet: r('GET', '/ai/jobs/:jobId', 'U,Kr', 'document.read'),
82
- aiJobCancel: r('POST', '/ai/jobs/:jobId/cancel', 'U,Krw', 'ai.review'),
83
- aiSuggestionSetsList: r('GET', '/documents/:did/ai/suggestion-sets', 'U,Kr', 'document.read'),
84
- aiSuggestionSetGet: r('GET', '/ai/suggestion-sets/:ssid', 'U,Kr', 'document.read'),
85
- aiSuggestionSetAccept: r('POST', '/ai/suggestion-sets/:ssid/accept', 'U,Krw', 'document.edit'),
86
- aiSuggestionSetReject: r('POST', '/ai/suggestion-sets/:ssid/reject', 'U,Krw', 'document.edit'),
87
- // B8 tenancy, roles, sharing. Keys (K) only read members and /me/shared; everything else is user-only (403 API_KEY_FORBIDDEN).
88
- workspaceCreate: r('POST', '/workspaces', 'U'),
89
- workspaceUpdate: r('PATCH', '/workspaces/:wid', 'U', 'workspace.update'),
90
- workspaceDelete: r('DELETE', '/workspaces/:wid', 'U', 'workspace.delete'),
91
- workspaceTransfer: r('POST', '/workspaces/:wid/transfer', 'U', 'workspace.transfer'),
92
- workspaceLeave: r('POST', '/workspaces/:wid/leave', 'U', 'workspace.leave'),
93
- workspaceUsage: r('GET', '/workspaces/:wid/usage', 'U', 'workspace.read'),
94
- workspaceAudit: r('GET', '/workspaces/:wid/audit.csv', 'U', 'workspace.audit'),
95
- membersList: r('GET', '/workspaces/:wid/members', 'U,Kr', 'members.read'),
96
- memberUpdate: r('PATCH', '/workspaces/:wid/members/:uid', 'U', 'members.updateRole'),
97
- memberRemove: r('DELETE', '/workspaces/:wid/members/:uid', 'U', 'members.remove'),
98
- invitationCreateWorkspace: r('POST', '/workspaces/:wid/invitations', 'U', 'members.invite'),
99
- invitationCreateProject: r('POST', '/projects/:pid/invitations', 'U', 'share.manage'),
100
- invitationCreateDocument: r('POST', '/documents/:did/invitations', 'U', 'share.manage'),
101
- workspaceInvitationsList: r('GET', '/workspaces/:wid/invitations', 'U', 'members.invite'),
102
- myInvitations: r('GET', '/me/invitations', 'U'),
103
- invitationRenew: r('POST', '/invitations/:iid/renew', 'U'),
104
- invitationCancel: r('DELETE', '/invitations/:iid', 'U'),
105
- invitationAccept: r('POST', '/invitations/accept', 'U'),
106
- invitationDecline: r('POST', '/invitations/:iid/decline', 'U'),
107
- sharedWithMe: r('GET', '/me/shared', 'U,Kr'),
108
- documentLock: r('POST', '/documents/:did/lock', 'U', 'document.lock'),
109
- documentUnlock: r('DELETE', '/documents/:did/lock', 'U', 'document.lock'),
110
- documentUnlockSession: r('POST', '/documents/:did/unlock-session', 'U', 'document.read'),
111
- shareLinkCreateDocument: r('POST', '/documents/:did/share-links', 'U', 'share.manage'),
112
- shareLinkCreateProject: r('POST', '/projects/:pid/share-links', 'U', 'share.manage'),
113
- shareLinkCreateSnapshot: r('POST', '/snapshots/:sid/share-links', 'U', 'share.manage'),
114
- shareLinksListDocument: r('GET', '/documents/:did/share-links', 'U', 'share.manage'),
115
- shareLinksListProject: r('GET', '/projects/:pid/share-links', 'U', 'share.manage'),
116
- shareLinkUpdate: r('PATCH', '/share-links/:lid', 'U', 'share.manage'),
117
- shareLinkRevoke: r('DELETE', '/share-links/:lid', 'U', 'share.manage'),
118
- grantsListDocument: r('GET', '/documents/:did/grants', 'U', 'share.manage'),
119
- grantsListProject: r('GET', '/projects/:pid/grants', 'U', 'share.manage'),
120
- grantUpdate: r('PATCH', '/grants/:gid', 'U', 'share.manage'),
121
- grantRemove: r('DELETE', '/grants/:gid', 'U', 'share.manage'),
122
- // B8 public link routes: the token in the path is the credential; an optional Bearer is a user or a link session (`fls_`).
123
- publicShareResolve: r('GET', '/public/share/:token', 'P'),
124
- shareUnlock: r('POST', '/share/:token/unlock', 'P'),
125
- shareState: r('GET', '/share/:token/state', 'P,L', 'document.read'),
126
- // B9 generic jobs (spec 05 §6.19). Jobs are visible to their owner, or to anyone who can read the job's document;
127
- // cancel, outputs and recipients are owner-only. `/ai/jobs*` stays as the AI facade over the same rows.
128
- jobsList: r('GET', '/jobs', 'U,Kr', 'document.read'),
129
- jobGet: r('GET', '/jobs/:jobId', 'U,Kr,L', 'document.read'),
130
- jobCreate: r('POST', '/jobs', 'U,Krw', 'document.read'),
131
- jobCancel: r('POST', '/jobs/:jobId/cancel', 'U,Krw', 'document.read'),
132
- jobOutputs: r('GET', '/jobs/:jobId/outputs', 'U,K,L', 'document.export'),
133
- jobRecipients: r('GET', '/jobs/:jobId/recipients', 'U', 'document.export'),
134
- // Provider webhook: unauthenticated, HMAC-signed with JOB_WEBHOOK_SECRET_<ADAPTER> (fails closed: 401 when unset).
135
- jobWebhook: r('POST', '/webhooks/jobs/:adapterId', 'W'),
136
- // B10 projection-backed reads, search, reports, packets (spec 05 §6.7.1, §6.7.2, §6.12, §6.14, §6.15, §6.17, §6.18, §6.22).
137
- // `?source=live|snapshot:<id>|version:<id>` selects the state a read answers from. Keys (K) read all of these; the report
138
- // and resolve POSTs are reads, so a read-only key may send them.
139
- entitiesList: r('GET', '/documents/:did/entities', 'U,Kr,L', 'document.read'),
140
- entityGet: r('GET', '/documents/:did/entities/:eid', 'U,Kr,L', 'document.read'),
141
- entityUsage: r('GET', '/documents/:did/entities/:eid/usage', 'U,Kr,L', 'document.read'),
142
- entityDialogue: r('GET', '/documents/:did/entities/:eid/dialogue', 'U,Kr,L', 'document.read'),
143
- tagCategoriesList: r('GET', '/documents/:did/tag-categories', 'U,Kr,L', 'document.read'),
144
- tagsList: r('GET', '/documents/:did/tags', 'U,Kr,L', 'document.read'),
145
- notesList: r('GET', '/documents/:did/notes', 'U,Kr,L', 'document.read'),
146
- beatsList: r('GET', '/documents/:did/beats', 'U,Kr,L', 'document.read'),
147
- binList: r('GET', '/documents/:did/bin', 'U,Kr,L', 'document.read'),
148
- revisionsGet: r('GET', '/documents/:did/revisions', 'U,Kr,L', 'document.read'),
149
- changesList: r('GET', '/documents/:did/changes', 'U,Kr,L', 'document.read'),
150
- alternatesGet: r('GET', '/documents/:did/alternates/:elementId', 'U,Kr,L', 'document.read'),
151
- titlePageGet: r('GET', '/documents/:did/title-page', 'U,Kr,L', 'document.read'),
152
- statsGet: r('GET', '/documents/:did/stats', 'U,Kr,L', 'document.read'),
153
- fountainGet: r('GET', '/documents/:did/fountain', 'U,Kr,L', 'document.read'),
154
- sceneShotsList: r('GET', '/documents/:did/scenes/:sceneId/shots', 'U,Kr,L', 'document.read'),
155
- resolveBatch: r('POST', '/documents/:did/resolve', 'U,Kr,L', 'document.read'),
156
- resolveOne: r('GET', '/documents/:did/resolve', 'U,Kr,L', 'document.read'),
157
- documentSearch: r('GET', '/documents/:did/search', 'U,Kr,L', 'document.read'),
158
- workspaceSearch: r('GET', '/workspaces/:wid/search', 'U,Kr', 'workspace.read'),
159
- search: r('GET', '/search', 'U,Kr'),
160
- reportKinds: r('GET', '/reports/kinds', 'U,Kr'),
161
- reportGet: r('GET', '/documents/:did/reports/:kind', 'U,Kr,L', 'reports.run'),
162
- reportCreate: r('POST', '/documents/:did/reports', 'U,Kr,L', 'reports.run'),
163
- packetScene: r('GET', '/documents/:did/packets/scene/:locator', 'U,Kr', 'document.read'),
164
- packetCharacter: r('GET', '/documents/:did/packets/character/:locator', 'U,Kr', 'document.read'),
165
- packetLocation: r('GET', '/documents/:did/packets/location/:locator', 'U,Kr', 'document.read'),
166
- packetShot: r('GET', '/documents/:did/packets/shot/:locator', 'U,Kr', 'document.read'),
167
- // B13 account and per-user data (spec 05 §6.1, §6.1.1, §6.26). User-only (a key gets 403 API_KEY_FORBIDDEN) except the macro list (Kr).
168
- meDictionaryGet: r('GET', '/me/dictionary', 'U'),
169
- meDictionaryUpdate: r('PUT', '/me/dictionary', 'U'),
170
- mePreferencesGet: r('GET', '/me/preferences', 'U'),
171
- mePreferencesSet: r('PUT', '/me/preferences', 'U'),
172
- meMacrosList: r('GET', '/me/macros', 'U,Kr'),
173
- meMacroCreate: r('POST', '/me/macros', 'U'),
174
- meMacroUpdate: r('PATCH', '/me/macros/:mid', 'U'),
175
- meMacroDelete: r('DELETE', '/me/macros/:mid', 'U'),
176
- meWritingStats: r('GET', '/me/writing-stats', 'U'),
177
- meWritingSessionCreate: r('POST', '/me/writing-sessions', 'U'),
178
- meWritingGoalsGet: r('GET', '/me/writing-goals', 'U'),
179
- meWritingGoalsSet: r('PUT', '/me/writing-goals', 'U'),
180
- meExport: r('POST', '/me/export', 'U'),
181
- meDelete: r('DELETE', '/me', 'U'),
182
- meRestore: r('POST', '/me/restore', 'U'),
183
- documentMyStateGet: r('GET', '/documents/:did/my-state', 'U', 'document.read'),
184
- documentMyStateSet: r('PUT', '/documents/:did/my-state', 'U', 'document.read'),
185
- documentStar: r('PUT', '/documents/:did/star', 'U', 'document.read'),
186
- documentUnstar: r('DELETE', '/documents/:did/star', 'U', 'document.read'),
187
- // B14 project, document and template lifecycle, workspace settings (spec 05 §6.2, §6.6-§6.8, §6.26). Writes are `Krw`; purge,
188
- // trash-empty, workspace defaults and contacts are user-only (a key gets 403 API_KEY_FORBIDDEN).
189
- workspaceDocuments: r('GET', '/workspaces/:wid/documents', 'U,Kr', 'project.read'),
190
- workspaceTrash: r('GET', '/workspaces/:wid/trash', 'U,Kr', 'project.read'),
191
- workspaceTrashEmpty: r('POST', '/workspaces/:wid/trash/empty', 'U', 'project.purge'),
192
- projectPurge: r('DELETE', '/projects/:pid', 'U', 'project.purge'),
193
- projectDuplicate: r('POST', '/projects/:pid/duplicate', 'U,Krw', 'project.create'),
194
- projectFolderCreate: r('POST', '/projects/:pid/folders', 'U,Krw', 'project.update'),
195
- projectFolderUpdate: r('PATCH', '/project-folders/:fid', 'U,Krw', 'project.update'),
196
- projectFolderDelete: r('DELETE', '/project-folders/:fid', 'U,Krw', 'project.update'),
197
- documentMove: r('POST', '/documents/:did/move', 'U,Krw', 'document.move'),
198
- documentPurge: r('DELETE', '/documents/:did', 'U', 'project.purge'),
199
- documentDuplicate: r('POST', '/documents/:did/duplicate', 'U,Krw', 'document.create'),
200
- documentApplyTemplate: r('POST', '/documents/:did/template', 'U,Krw', 'document.lock'),
201
- templateCreate: r('POST', '/templates', 'U,Krw', 'templates.manage'),
202
- templateVersionCreate: r('POST', '/templates/:tid/versions', 'U,Krw', 'templates.manage'),
203
- templateUpdate: r('PATCH', '/templates/:tid', 'U,Krw', 'templates.manage'),
204
- templateDelete: r('DELETE', '/templates/:tid', 'U,Krw', 'templates.manage'),
205
- templateImport: r('POST', '/templates/import', 'U,Krw', 'templates.manage'),
206
- templateExport: r('GET', '/templates/:tid/export', 'U,Kr'),
207
- projectBinList: r('GET', '/projects/:pid/bin', 'U,Kr', 'project.read'),
208
- projectBinCreate: r('POST', '/projects/:pid/bin', 'U,Krw', 'document.edit'),
209
- projectBinDelete: r('DELETE', '/project-bin-items/:id', 'U,Krw', 'document.edit'),
210
- workspaceDefaultsGet: r('GET', '/workspaces/:wid/defaults', 'U,Kr', 'workspace.read'),
211
- workspaceDefaultsSet: r('PUT', '/workspaces/:wid/defaults', 'U', 'workspace.update'),
212
- workspaceContactsList: r('GET', '/workspaces/:wid/contacts', 'U', 'workspace.read'),
213
- workspaceContactsCreate: r('POST', '/workspaces/:wid/contacts', 'U', 'workspace.update'),
214
- workspaceContactUpdate: r('PATCH', '/workspace-contacts/:cid', 'U', 'workspace.update'),
215
- workspaceContactDelete: r('DELETE', '/workspace-contacts/:cid', 'U', 'workspace.update'),
216
- // B16 imports, exports and watermark as jobs (spec 05 §6.18). `POST /imports*` and `/uploads/state` are `Krw`; exports are `Kr` (a read key may
217
- // export what it can read); the watermark lookup is user-only (403 API_KEY_FORBIDDEN for a key). The synchronous
218
- // `documentImport`/`documentExport`/`formatsList` stay until the app moves to these (see the plan's B16 "Deferred" list).
219
- uploadState: r('POST', '/uploads/state', 'U,Krw'),
220
- importCreate: r('POST', '/imports', 'U,Krw', 'document.create'),
221
- importStart: r('POST', '/imports/:importId/start', 'U,Krw'),
222
- documentImportOver: r('POST', '/documents/:did/import-over', 'U,Krw', 'document.edit'),
223
- documentExportCreate: r('POST', '/documents/:did/exports', 'U,Kr', 'document.export'),
224
- documentExportCombined: r('POST', '/documents/export-combined', 'U,Kr', 'document.export'),
225
- watermarkLookup: r('POST', '/workspaces/:wid/watermark-lookup', 'U', 'workspace.audit'),
226
- // B11 assets and R2 (spec 05 §6.13). Bytes go to object storage through presigned URLs, never through the API. Writes are `Krw`, reads `Kr`;
227
- // share-link readers (`L`) are not built (no `/share/:token/assets` route yet). The uploader routes check the caller is the uploader.
228
- assetUploadCreate: r('POST', '/workspaces/:wid/assets/uploads', 'U,Krw', 'assets.upload'),
229
- assetUploadGet: r('GET', '/assets/uploads/:uploadId', 'U,Krw'),
230
- assetUploadParts: r('POST', '/assets/uploads/:uploadId/parts', 'U,Krw'),
231
- assetUploadComplete: r('POST', '/assets/uploads/:uploadId/complete', 'U,Krw'),
232
- assetUploadAbort: r('DELETE', '/assets/uploads/:uploadId', 'U,Krw'),
233
- assetsList: r('GET', '/assets', 'U,Kr', 'assets.read'),
234
- assetGet: r('GET', '/assets/:aid', 'U,Kr', 'assets.read'),
235
- assetUrl: r('GET', '/assets/:aid/versions/:vid/url', 'U,Kr', 'assets.read'),
236
- assetUpdate: r('PATCH', '/assets/:aid', 'U,Krw', 'assets.upload'),
237
- assetDelete: r('DELETE', '/assets/:aid', 'U,Krw', 'assets.upload'),
238
- assetRestore: r('POST', '/assets/:aid/restore', 'U,Krw', 'assets.upload'),
239
- assetLinkCreate: r('POST', '/asset-links', 'U,Krw', 'assets.link'),
240
- documentAssetLinks: r('GET', '/documents/:did/asset-links', 'U,Kr', 'assets.read'),
241
- assetLinkUpdate: r('PATCH', '/asset-links/:lid', 'U,Krw', 'assets.link'),
242
- assetLinkDelete: r('DELETE', '/asset-links/:lid', 'U,Krw', 'assets.link'),
243
- documentStaleness: r('GET', '/documents/:did/staleness', 'U,Kr', 'document.read'),
244
- assetLinkStaleness: r('GET', '/asset-links/:lid/staleness', 'U,Kr', 'assets.read'),
245
- // B12 collaboration, notifications, devices, email (spec 05 §6.15, §6.16, §6.24, §6.26). Most of this slice is
246
- // user-only (a key gets 403 API_KEY_FORBIDDEN): personal notifications and devices, and chat/activity writes are
247
- // never for a key. `documentChatList` and `documentActivity` are the two exceptions (`Kr`, a read key may read them).
248
- meNotificationPrefsGet: r('GET', '/me/notification-prefs', 'U'),
249
- meNotificationPrefsSet: r('PUT', '/me/notification-prefs', 'U'),
250
- documentMentionsWithoutAccess: r('GET', '/documents/:did/mentions-without-access', 'U', 'share.manage'),
251
- documentChatList: r('GET', '/documents/:did/chat', 'U,Kr,L', 'document.chat'),
252
- documentChatCreate: r('POST', '/documents/:did/chat', 'U,L', 'document.chat'),
253
- chatMessageUpdate: r('PATCH', '/chat-messages/:mid', 'U', 'document.chat'),
254
- chatMessageDelete: r('DELETE', '/chat-messages/:mid', 'U', 'document.chat'),
255
- documentActivity: r('GET', '/documents/:did/activity', 'U,Kr', 'document.activity'),
256
- workspaceActivity: r('GET', '/workspaces/:wid/activity', 'U', 'workspace.read'),
257
- notificationsList: r('GET', '/notifications', 'U'),
258
- notificationsRead: r('POST', '/notifications/read', 'U'),
259
- notificationDelete: r('DELETE', '/notifications/:nid', 'U'),
260
- notificationsStream: r('GET', '/notifications/stream', 'U'),
261
- devicesList: r('GET', '/devices', 'U'),
262
- deviceCreate: r('POST', '/devices', 'U'),
263
- deviceUpdate: r('PATCH', '/devices/:devid', 'U'),
264
- deviceRevoke: r('POST', '/devices/:devid/revoke', 'U'),
265
- devicePushTokenSet: r('PUT', '/devices/:devid/push-token', 'U'),
266
- devicePushTokenDelete: r('DELETE', '/devices/:devid/push-token', 'U'),
267
- // B17 AI completion and credits (spec 05 §6.3, §6.19, §6.20, §6.21; spec 06 §9-10). AI routes need the key's `ai`
268
- // flag (403 AI_KEY_NOT_PERMITTED); `decide` needs read_write. Consent, activity and credits are user-only except
269
- // the balance/products reads (Kr; a key spends its own workspace's credits so it may read them) — `consumables/products`
270
- // is also public (unauthenticated pricing display). `GET .../suggestion-sets` and `GET /suggestion-sets/:ssid` are
271
- // already built (B7, under `/ai/` — kept as-is rather than duplicated at the bare path spec 05 Appendix A also lists).
272
- meAiConsentGet: r('GET', '/me/ai-consents', 'U'),
273
- meAiConsentAccept: r('POST', '/me/ai-consents', 'U'),
274
- meAiActivity: r('GET', '/me/ai-activity', 'U'),
275
- workspaceAiActivity: r('GET', '/workspaces/:wid/ai-activity', 'U', 'workspace.audit'),
276
- aiEstimate: r('POST', '/documents/:did/ai/estimate', 'U,Kr', 'document.read'),
277
- aiReportsList: r('GET', '/documents/:did/ai/reports', 'U,Kr', 'document.read'),
278
- aiReportGet: r('GET', '/documents/:did/ai/reports/:jobId', 'U,Kr', 'document.read'),
279
- aiReportNoteConvert: r('POST', '/documents/:did/ai/reports/:jobId/notes/:noteId/convert', 'U,Krw', 'document.comment'),
280
- aiSuggestionSetDecide: r('POST', '/ai/suggestion-sets/:ssid/decide', 'U,Krw', 'document.edit'),
281
- consumablesBalance: r('GET', '/consumables/balance', 'U,Kr'),
282
- consumablesPurchases: r('GET', '/consumables/purchases', 'U'),
283
- consumablesUsages: r('GET', '/consumables/usages', 'U'),
284
- consumablesProducts: r('GET', '/consumables/products', 'U,Kr,P'),
285
- consumablesWebhook: r('POST', '/consumables/webhook', 'W'),
286
- purchaseHandoffCreate: r('POST', '/purchases/handoff', 'U'),
287
- // B18 public, admin, telemetry (spec 05 §6.21, §6.23, §6.24; `/language/*` skipped by decision, see the plan's
288
- // B18 note). Public routes need no session at all. Admin needs `siteAdmin` on a USER principal specifically —
289
- // never an API key, whatever its scope — enforced in the handler (there is no per-object permission to check).
290
- publicTemplatesList: r('GET', '/public/templates', 'P'),
291
- publicTemplateGet: r('GET', '/public/templates/:builtinKey', 'P'),
292
- publicConfig: r('GET', '/public/config', 'P'),
293
- publicNamesDb: r('GET', '/public/names-db/:version', 'P'),
294
- publicHealthDeep: r('GET', '/public/health/deep', 'P'),
295
- publicWatermarkedGet: r('GET', '/public/watermarked/:exportId/:token', 'P'),
296
- purchaseHandoffRedeem: r('POST', '/public/purchases/handoff/redeem', 'P'),
297
- telemetryCreate: r('POST', '/telemetry', 'U,P'),
298
- adminUsersLookup: r('GET', '/admin/users', 'U'),
299
- adminUserRestore: r('POST', '/admin/users/:uid/restore', 'U'),
300
- adminUserPurge: r('DELETE', '/admin/users/:uid', 'U'),
301
- adminJobsList: r('GET', '/admin/jobs', 'U'),
302
- adminJobRetry: r('POST', '/admin/jobs/:id/retry', 'U'),
303
- adminJobRefund: r('POST', '/admin/jobs/:id/refund', 'U'),
304
- adminJobKindUpdate: r('PATCH', '/admin/job-kinds/:kind', 'U'),
305
- adminDocumentMeta: r('GET', '/admin/documents/:did/meta', 'U'),
306
- };