@sylphx/contract 0.2.1 → 0.4.0
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/CHANGELOG.md +12 -0
- package/dist/endpoint.d.ts +6 -0
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoints/admin-projects.d.ts +29 -0
- package/dist/endpoints/admin-projects.d.ts.map +1 -1
- package/dist/endpoints/admin-projects.js +30 -1
- package/dist/endpoints/auth.d.ts +47 -0
- package/dist/endpoints/auth.d.ts.map +1 -1
- package/dist/endpoints/auth.js +19 -1
- package/dist/endpoints/branch-databases.d.ts +27 -28
- package/dist/endpoints/branch-databases.d.ts.map +1 -1
- package/dist/endpoints/branch-databases.js +7 -7
- package/dist/endpoints/databases.d.ts +253 -3
- package/dist/endpoints/databases.d.ts.map +1 -1
- package/dist/endpoints/databases.js +19 -12
- package/dist/endpoints/organizations.d.ts +11 -0
- package/dist/endpoints/organizations.d.ts.map +1 -1
- package/dist/endpoints/organizations.js +8 -1
- package/dist/endpoints/project-manifest.d.ts +26 -18
- package/dist/endpoints/project-manifest.d.ts.map +1 -1
- package/dist/endpoints/secrets.d.ts +6 -6
- package/dist/endpoints/secrets.d.ts.map +1 -1
- package/dist/endpoints/secrets.js +6 -5
- package/dist/endpoints/storage.d.ts +183 -125
- package/dist/endpoints/storage.d.ts.map +1 -1
- package/dist/endpoints/storage.js +96 -59
- package/dist/index.d.ts +323 -164
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/schemas/admin-projects.d.ts +20 -0
- package/dist/schemas/admin-projects.d.ts.map +1 -1
- package/dist/schemas/admin-projects.js +17 -0
- package/dist/schemas/auth.d.ts +65 -0
- package/dist/schemas/auth.d.ts.map +1 -1
- package/dist/schemas/auth.js +32 -0
- package/dist/schemas/branch-database.d.ts +20 -19
- package/dist/schemas/branch-database.d.ts.map +1 -1
- package/dist/schemas/branch-database.js +9 -7
- package/dist/schemas/ids.d.ts +2 -0
- package/dist/schemas/ids.d.ts.map +1 -1
- package/dist/schemas/ids.js +1 -0
- package/dist/schemas/organization.d.ts +24 -2
- package/dist/schemas/organization.d.ts.map +1 -1
- package/dist/schemas/organization.js +13 -1
- package/dist/schemas/project-manifest.d.ts +43 -21
- package/dist/schemas/project-manifest.d.ts.map +1 -1
- package/dist/schemas/project-manifest.js +11 -3
- package/dist/schemas/secret.d.ts +1 -1
- package/dist/schemas/secret.js +2 -2
- package/dist/schemas/storage.d.ts +259 -203
- package/dist/schemas/storage.d.ts.map +1 -1
- package/dist/schemas/storage.js +159 -144
- package/package.json +5 -1
package/dist/schemas/storage.js
CHANGED
|
@@ -1,178 +1,193 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Storage — BaaS plane
|
|
3
|
-
* S3 convention. Mirrors `@sylphx/sdk/storage.ts`.
|
|
2
|
+
* Storage — BaaS plane object storage. Per ADR-100.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* Wire is one resource (`uploads`) plus the existing `files` resource. No
|
|
5
|
+
* polymorphic POSTs, no vendor-namespaced wire envelopes, no historical
|
|
6
|
+
* field aliases. Every endpoint has exactly one request and one response
|
|
7
|
+
* schema.
|
|
8
|
+
*
|
|
9
|
+
* Storage backends (B2, R2) are abstracted by `apps/storage-gateway`. The
|
|
10
|
+
* BaaS handler returns presigned URLs against `storage.sylphx.com`; the
|
|
11
|
+
* client uploads bytes there directly. Mid-flow tenant subdomain hops are
|
|
12
|
+
* forbidden (ADR-083.1).
|
|
11
13
|
*/
|
|
12
14
|
import { Schema } from 'effect';
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Branded identifiers
|
|
17
|
+
// ============================================================================
|
|
13
18
|
export const FileId = Schema.String.pipe(Schema.brand('FileId'));
|
|
19
|
+
export const UploadId = Schema.String.pipe(Schema.brand('UploadId'));
|
|
20
|
+
export const FileVersionId = Schema.String.pipe(Schema.brand('FileVersionId'));
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Enumerations
|
|
23
|
+
// ============================================================================
|
|
24
|
+
export const FileVisibility = Schema.Literal('public', 'private');
|
|
25
|
+
export const SignedUrlDisposition = Schema.Literal('attachment', 'inline');
|
|
26
|
+
/** Method discriminator on the upload-create response. */
|
|
27
|
+
export const UploadMethod = Schema.Literal('PUT', 'MULTIPART');
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Core types
|
|
30
|
+
// ============================================================================
|
|
14
31
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - SDK `FileInfo` interface: `{ id, url, name, size, contentType,
|
|
18
|
-
* isPrivate, createdAt }`
|
|
19
|
-
* - Generated OpenAPI `FileInfo` / `GetFileResponse`: `{ id, filename,
|
|
20
|
-
* path, url, mimeType, size, metadata, createdAt }`
|
|
21
|
-
* - Previous contract shape: `{ id, key, size, contentType, url?,
|
|
22
|
-
* uploadedAt }`
|
|
23
|
-
*
|
|
24
|
-
* Every historical field is preserved as optional so older and newer
|
|
25
|
-
* clients can both parse server responses. `id` and `size` are the only
|
|
26
|
-
* guaranteed-present fields across all three shapes.
|
|
32
|
+
* Canonical file metadata. Single shape — no aliases, no nullable hacks
|
|
33
|
+
* for legacy callers. ADR-100 §2.6.
|
|
27
34
|
*/
|
|
28
|
-
export const
|
|
29
|
-
id:
|
|
35
|
+
export const File = Schema.Struct({
|
|
36
|
+
id: FileId,
|
|
37
|
+
filename: Schema.String,
|
|
38
|
+
contentType: Schema.String,
|
|
30
39
|
size: Schema.Number,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
createdAt: Schema.
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
checksumSha256: Schema.String,
|
|
41
|
+
etag: Schema.String,
|
|
42
|
+
visibility: FileVisibility,
|
|
43
|
+
folder: Schema.NullOr(Schema.String),
|
|
44
|
+
metadata: Schema.Record({ key: Schema.String, value: Schema.Unknown }),
|
|
45
|
+
/** Public URL when `visibility === 'public'`; `null` otherwise. Use `:signedUrl` for private files. */
|
|
46
|
+
url: Schema.NullOr(Schema.String),
|
|
47
|
+
isDeleted: Schema.Boolean,
|
|
48
|
+
createdAt: Schema.DateFromString,
|
|
49
|
+
updatedAt: Schema.DateFromString,
|
|
50
|
+
});
|
|
51
|
+
export const FileVersion = Schema.Struct({
|
|
52
|
+
id: FileVersionId,
|
|
53
|
+
fileId: FileId,
|
|
54
|
+
versionNumber: Schema.Number,
|
|
55
|
+
size: Schema.Number,
|
|
56
|
+
contentType: Schema.String,
|
|
57
|
+
checksumSha256: Schema.String,
|
|
58
|
+
etag: Schema.String,
|
|
59
|
+
createdAt: Schema.DateFromString,
|
|
60
|
+
createdBy: Schema.NullOr(Schema.String),
|
|
61
|
+
isCurrent: Schema.Boolean,
|
|
62
|
+
});
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// Upload session — POST /v1/storage/uploads
|
|
65
|
+
// ============================================================================
|
|
66
|
+
export const UploadCreateRequest = Schema.Struct({
|
|
67
|
+
filename: Schema.String.pipe(Schema.minLength(1)),
|
|
68
|
+
contentType: Schema.String.pipe(Schema.minLength(1)),
|
|
69
|
+
size: Schema.Number.pipe(Schema.greaterThanOrEqualTo(0)),
|
|
70
|
+
folder: Schema.optional(Schema.String),
|
|
71
|
+
visibility: Schema.optional(FileVisibility),
|
|
72
|
+
metadata: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),
|
|
73
|
+
/** Pre-computed SHA-256 (hex); verified server-side on `:complete` (multipart) or after PUT (single). */
|
|
74
|
+
checksumSha256: Schema.optional(Schema.String),
|
|
75
|
+
/** S3-style precondition; if `'*'`, fail when a file already exists at (folder, filename). */
|
|
76
|
+
ifNoneMatch: Schema.optional(Schema.Literal('*')),
|
|
77
|
+
});
|
|
78
|
+
export const UploadPart = Schema.Struct({
|
|
79
|
+
partNumber: Schema.Number.pipe(Schema.greaterThanOrEqualTo(1)),
|
|
80
|
+
url: Schema.String,
|
|
81
|
+
expiresAt: Schema.DateFromString,
|
|
53
82
|
});
|
|
54
83
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
84
|
+
* Single-part response — the request body fits in one PUT. Client uploads
|
|
85
|
+
* the whole blob to `url` with the supplied `headers`, captures the `ETag`
|
|
86
|
+
* response header, then calls `:complete` with `parts: [{partNumber: 1,
|
|
87
|
+
* etag}]` to finalise. The `:complete` step is non-optional even for
|
|
88
|
+
* single-part uploads because it is what writes the file row to the
|
|
89
|
+
* database and consumes quota — without it the storage object is
|
|
90
|
+
* orphaned and reclaimed by the multipart-aborts sweeper after
|
|
91
|
+
* `expiresAt`.
|
|
59
92
|
*/
|
|
60
|
-
export const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
type: Schema.optional(Schema.Literal('file', 'avatar')),
|
|
68
|
-
/** User ID (required for `type: 'avatar'`). */
|
|
69
|
-
userId: Schema.optional(Schema.String),
|
|
70
|
-
/** Arbitrary caller-attached metadata persisted alongside the blob. */
|
|
71
|
-
metadata: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),
|
|
93
|
+
export const UploadCreateSinglePartResult = Schema.Struct({
|
|
94
|
+
method: Schema.Literal('PUT'),
|
|
95
|
+
uploadId: UploadId,
|
|
96
|
+
fileId: FileId,
|
|
97
|
+
url: Schema.String,
|
|
98
|
+
headers: Schema.Record({ key: Schema.String, value: Schema.String }),
|
|
99
|
+
expiresAt: Schema.DateFromString,
|
|
72
100
|
});
|
|
73
101
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `{ uploadEndpoint, clientPayload, instructions, ... }` shape.
|
|
102
|
+
* Multipart response — client PUTs each part to its presigned URL, then
|
|
103
|
+
* calls `POST /uploads/{uploadId}:complete` with the per-part etags.
|
|
77
104
|
*/
|
|
78
|
-
export const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
storageKey: Schema.optional(Schema.String),
|
|
87
|
-
tokenPayload: Schema.optional(Schema.String),
|
|
88
|
-
url: Schema.optional(Schema.String),
|
|
89
|
-
// Vercel Blob client-upload flow
|
|
90
|
-
uploadEndpoint: Schema.optional(Schema.String),
|
|
91
|
-
clientPayload: Schema.optional(Schema.String),
|
|
92
|
-
maxSize: Schema.optional(Schema.Number),
|
|
93
|
-
maxMultipartSize: Schema.optional(Schema.Number),
|
|
94
|
-
multipartThreshold: Schema.optional(Schema.Number),
|
|
95
|
-
allowedContentTypes: Schema.optional(Schema.Array(Schema.String)),
|
|
96
|
-
instructions: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),
|
|
97
|
-
});
|
|
98
|
-
export const UploadUrlInput = Schema.Struct({
|
|
99
|
-
filename: Schema.String,
|
|
100
|
-
contentType: Schema.String,
|
|
101
|
-
size: Schema.optional(Schema.Number),
|
|
105
|
+
export const UploadCreateMultipartResult = Schema.Struct({
|
|
106
|
+
method: Schema.Literal('MULTIPART'),
|
|
107
|
+
uploadId: UploadId,
|
|
108
|
+
fileId: FileId,
|
|
109
|
+
partSize: Schema.Number,
|
|
110
|
+
partCount: Schema.Number,
|
|
111
|
+
parts: Schema.Array(UploadPart),
|
|
112
|
+
expiresAt: Schema.DateFromString,
|
|
102
113
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Discriminated union on `method`. SDK narrows via the literal; downstream
|
|
116
|
+
* code never has to inspect optional fields.
|
|
117
|
+
*/
|
|
118
|
+
export const UploadCreateResult = Schema.Union(UploadCreateSinglePartResult, UploadCreateMultipartResult);
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// Multipart support
|
|
121
|
+
// ============================================================================
|
|
122
|
+
/** Refresh a single part presigned URL — used when an upload pauses past `expiresAt`. */
|
|
123
|
+
export const UploadPartPresignResult = Schema.Struct({
|
|
124
|
+
url: Schema.String,
|
|
125
|
+
expiresAt: Schema.DateFromString,
|
|
126
|
+
});
|
|
127
|
+
export const UploadCompletePart = Schema.Struct({
|
|
128
|
+
partNumber: Schema.Number.pipe(Schema.greaterThanOrEqualTo(1)),
|
|
129
|
+
etag: Schema.String.pipe(Schema.minLength(1)),
|
|
130
|
+
});
|
|
131
|
+
export const UploadCompleteRequest = Schema.Struct({
|
|
132
|
+
parts: Schema.Array(UploadCompletePart),
|
|
133
|
+
});
|
|
134
|
+
export const UploadCompleteResult = Schema.Struct({
|
|
135
|
+
fileId: FileId,
|
|
136
|
+
url: Schema.NullOr(Schema.String),
|
|
137
|
+
size: Schema.Number,
|
|
138
|
+
etag: Schema.String,
|
|
139
|
+
checksumSha256: Schema.String,
|
|
107
140
|
});
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Files resource
|
|
143
|
+
// ============================================================================
|
|
108
144
|
export const ListFilesQuery = Schema.Struct({
|
|
109
|
-
|
|
110
|
-
limit: Schema.optional(Schema.String),
|
|
145
|
+
folder: Schema.optional(Schema.String),
|
|
111
146
|
cursor: Schema.optional(Schema.String),
|
|
147
|
+
/** Page size; clamped server-side to [1, 100]; default 25. */
|
|
148
|
+
limit: Schema.optional(Schema.Number),
|
|
149
|
+
includeDeleted: Schema.optional(Schema.Boolean),
|
|
112
150
|
});
|
|
113
151
|
export const ListFilesResult = Schema.Struct({
|
|
114
|
-
files: Schema.Array(
|
|
152
|
+
files: Schema.Array(File),
|
|
115
153
|
nextCursor: Schema.NullOr(Schema.String),
|
|
116
|
-
/** True if there are more files beyond this page. */
|
|
117
|
-
hasMore: Schema.optional(Schema.Boolean),
|
|
118
154
|
});
|
|
119
|
-
export const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
disposition: Schema.optional(
|
|
130
|
-
/** Restrict URL
|
|
155
|
+
export const SoftDeleteFileResult = Schema.Struct({
|
|
156
|
+
id: FileId,
|
|
157
|
+
isDeleted: Schema.Literal(true),
|
|
158
|
+
});
|
|
159
|
+
export const RestoreFileResult = File;
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Signed URLs
|
|
162
|
+
// ============================================================================
|
|
163
|
+
export const SignedUrlRequest = Schema.Struct({
|
|
164
|
+
expiresIn: Schema.optional(Schema.Number.pipe(Schema.greaterThanOrEqualTo(1))),
|
|
165
|
+
disposition: Schema.optional(SignedUrlDisposition),
|
|
166
|
+
/** Restrict the signed URL to a specific authenticated user (claim baked into the signature). */
|
|
131
167
|
userId: Schema.optional(Schema.String),
|
|
132
168
|
});
|
|
133
169
|
export const SignedUrlResult = Schema.Struct({
|
|
134
170
|
url: Schema.String,
|
|
135
|
-
expiresAt: Schema.
|
|
136
|
-
file:
|
|
137
|
-
id: Schema.String,
|
|
138
|
-
filename: Schema.String,
|
|
139
|
-
mimeType: Schema.String,
|
|
140
|
-
sizeBytes: Schema.Number,
|
|
141
|
-
isPrivate: Schema.Boolean,
|
|
142
|
-
}),
|
|
171
|
+
expiresAt: Schema.DateFromString,
|
|
172
|
+
file: File,
|
|
143
173
|
});
|
|
144
174
|
// ============================================================================
|
|
145
|
-
//
|
|
175
|
+
// Copy
|
|
146
176
|
// ============================================================================
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
*/
|
|
153
|
-
export const StorageFileVersion = Schema.Struct({
|
|
154
|
-
id: Schema.String,
|
|
155
|
-
fileId: Schema.String,
|
|
156
|
-
versionNumber: Schema.Number,
|
|
157
|
-
sizeBytes: Schema.Number,
|
|
158
|
-
contentType: Schema.NullOr(Schema.String),
|
|
159
|
-
checksumSha256: Schema.NullOr(Schema.String),
|
|
160
|
-
createdAt: Schema.String,
|
|
161
|
-
createdBy: Schema.NullOr(Schema.String),
|
|
162
|
-
isCurrent: Schema.Boolean,
|
|
177
|
+
export const CopyFileRequest = Schema.Struct({
|
|
178
|
+
folder: Schema.optional(Schema.String),
|
|
179
|
+
filename: Schema.optional(Schema.String),
|
|
180
|
+
visibility: Schema.optional(FileVisibility),
|
|
181
|
+
metadata: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Unknown })),
|
|
163
182
|
});
|
|
183
|
+
export const CopyFileResult = File;
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Versions
|
|
186
|
+
// ============================================================================
|
|
164
187
|
export const ListFileVersionsResult = Schema.Struct({
|
|
165
|
-
versions: Schema.Array(
|
|
188
|
+
versions: Schema.Array(FileVersion),
|
|
166
189
|
});
|
|
167
190
|
export const RestoreVersionResult = Schema.Struct({
|
|
168
|
-
|
|
169
|
-
version:
|
|
170
|
-
});
|
|
171
|
-
export const SoftDeleteFileResult = Schema.Struct({
|
|
172
|
-
success: Schema.Literal(true),
|
|
173
|
-
isDeleted: Schema.Literal(true),
|
|
174
|
-
});
|
|
175
|
-
export const RestoreFileResult = Schema.Struct({
|
|
176
|
-
success: Schema.Literal(true),
|
|
177
|
-
file: FileInfo,
|
|
191
|
+
file: File,
|
|
192
|
+
version: FileVersion,
|
|
178
193
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Sylphx Platform contract — Effect Schema SSOT for every API endpoint (ADR-084).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -115,6 +115,10 @@
|
|
|
115
115
|
"./endpoints/auth": {
|
|
116
116
|
"import": "./dist/endpoints/auth.js",
|
|
117
117
|
"types": "./dist/endpoints/auth.d.ts"
|
|
118
|
+
},
|
|
119
|
+
"./endpoints/oidc": {
|
|
120
|
+
"import": "./dist/endpoints/oidc.js",
|
|
121
|
+
"types": "./dist/endpoints/oidc.d.ts"
|
|
118
122
|
}
|
|
119
123
|
},
|
|
120
124
|
"scripts": {
|