@wtfalch/files 0.5.0 → 0.7.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/README.md +19 -0
- package/dist/client.d.ts +13 -2
- package/dist/client.js +20 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,16 @@ part in order. To resume, ask for fresh URLs for the parts that failed. A
|
|
|
41
41
|
multipart file has `checksum: null`. The R2 backend supports this; the
|
|
42
42
|
local-disk backend does not yet.
|
|
43
43
|
|
|
44
|
+
`getFile(id, version)` and `downloadFile(id, { version })` pin the read to an
|
|
45
|
+
exact file version. A mismatch against the file's current version throws
|
|
46
|
+
`ApiError` with `status: 409` rather than serving the current version's
|
|
47
|
+
bytes -- the backend keeps only the current version's object, so there is no
|
|
48
|
+
older version to fall back to. Every `StoredFile` also carries `sha256`
|
|
49
|
+
(`null` unless the storage backend exposed byte access at confirm time) and
|
|
50
|
+
`principalRef`, the principal whose upload last confirmed it at its current
|
|
51
|
+
version (`null` if that upload is no longer on record, or the file was never
|
|
52
|
+
confirmed).
|
|
53
|
+
|
|
44
54
|
Files can sit in folders inside a collection. Pass `path` (for example
|
|
45
55
|
`reports/2026`) when you reserve an upload. `listFiles(collectionId, { path })`
|
|
46
56
|
lists the files directly in that folder, and `listFolders(collectionId, path)`
|
|
@@ -48,6 +58,15 @@ lists its subfolders. A folder exists while it holds a file, so there are no
|
|
|
48
58
|
empty folders. A replacement keeps the file's path; moving a file is not
|
|
49
59
|
supported yet.
|
|
50
60
|
|
|
61
|
+
Image files can be resized on demand instead of a tenant running its own
|
|
62
|
+
thumbnail pipeline: `getFileVariant(fileId, width, format)` returns a signed
|
|
63
|
+
URL to a resized, re-encoded copy, built with `sharp` on first request and
|
|
64
|
+
served from a stored copy on every one after. `width` must be one of
|
|
65
|
+
`VARIANT_WIDTHS` (64, 256 or 1024); `format` is `'webp'` or `'jpeg'`. Only a
|
|
66
|
+
file whose content type `sharp` can decode (JPEG, PNG, WebP, GIF, AVIF)
|
|
67
|
+
qualifies -- anything else answers `invalid_request`. A variant's bytes count
|
|
68
|
+
against the same byte quota an upload does.
|
|
69
|
+
|
|
51
70
|
The root export provides the client and public request/response types.
|
|
52
71
|
`@wtfalch/files/client` is also supported. There are no server, database,
|
|
53
72
|
migration, provider-adapter or authorization-engine exports. The service
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ClientOptions, type ManagementClientOptions } from './transport.js';
|
|
2
|
-
import type { AuditPage, AuditQuery, BudgetSummary, CreatedShare, FilesRate, OrganisationShare, OrganisationSummary, ProvisionOrganisationInput, ProvisionOrganisationResult, QuotaSummary, SetRateInput, SetWebhookResult, Share, StoredFile, UpdateOrganisationCeilingInput, UploadInput, UploadReservation, UploadedPart, UsageDay, WebhookConfig } from './types.js';
|
|
2
|
+
import type { AuditPage, AuditQuery, BudgetSummary, CreatedShare, FilesRate, OrganisationShare, OrganisationSummary, ProvisionOrganisationInput, ProvisionOrganisationResult, QuotaSummary, SetRateInput, SetWebhookResult, Share, StoredFile, UpdateOrganisationCeilingInput, UploadInput, UploadReservation, UploadedPart, UsageDay, VariantFormat, VariantWidth, WebhookConfig } from './types.js';
|
|
3
3
|
export { ApiError, type ClientOptions, type ManagementClientOptions } from './transport.js';
|
|
4
4
|
export declare function createFilesClient(options: ClientOptions): {
|
|
5
5
|
createCollection: (name: string) => Promise<{
|
|
@@ -18,13 +18,24 @@ export declare function createFilesClient(options: ClientOptions): {
|
|
|
18
18
|
}[];
|
|
19
19
|
expiresAt: string;
|
|
20
20
|
}>;
|
|
21
|
-
|
|
21
|
+
/** `version`, when given, pins the read to that exact file version:
|
|
22
|
+
* `ApiError` with `status: 409` if the file has since moved on. */
|
|
23
|
+
getFile: (id: string, version?: number) => Promise<StoredFile>;
|
|
24
|
+
/** `version`, when given, pins the download to that exact file version,
|
|
25
|
+
* same as `getFile` -- only the current version's bytes exist in the
|
|
26
|
+
* backend at all, so a mismatch is always a 409, never a historical
|
|
27
|
+
* read. */
|
|
22
28
|
downloadFile: (id: string, options?: {
|
|
23
29
|
ttlSeconds?: number;
|
|
30
|
+
version?: number;
|
|
24
31
|
}) => Promise<{
|
|
25
32
|
url: string;
|
|
26
33
|
expiresIn: number;
|
|
27
34
|
}>;
|
|
35
|
+
getFileVariant: (id: string, width: VariantWidth, format: VariantFormat) => Promise<{
|
|
36
|
+
url: string;
|
|
37
|
+
expiresIn: number;
|
|
38
|
+
}>;
|
|
28
39
|
deleteFile: (id: string) => Promise<void>;
|
|
29
40
|
/** `path` lists only the files directly in that folder. */
|
|
30
41
|
listFiles: (collection: string, page?: {
|
package/dist/client.js
CHANGED
|
@@ -13,8 +13,26 @@ export function createFilesClient(options) {
|
|
|
13
13
|
from: String(from),
|
|
14
14
|
count: String(count),
|
|
15
15
|
})}`),
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/** `version`, when given, pins the read to that exact file version:
|
|
17
|
+
* `ApiError` with `status: 409` if the file has since moved on. */
|
|
18
|
+
getFile: (id, version) => call('GET', `/v1/files/${encodeURIComponent(id)}${version === undefined ? '' : `?version=${version}`}`),
|
|
19
|
+
/** `version`, when given, pins the download to that exact file version,
|
|
20
|
+
* same as `getFile` -- only the current version's bytes exist in the
|
|
21
|
+
* backend at all, so a mismatch is always a 409, never a historical
|
|
22
|
+
* read. */
|
|
23
|
+
downloadFile: (id, options = {}) => {
|
|
24
|
+
const params = new URLSearchParams();
|
|
25
|
+
if (options.ttlSeconds !== undefined)
|
|
26
|
+
params.set('ttl', String(options.ttlSeconds));
|
|
27
|
+
if (options.version !== undefined)
|
|
28
|
+
params.set('version', String(options.version));
|
|
29
|
+
const query = params.toString();
|
|
30
|
+
return call('GET', `/v1/files/${encodeURIComponent(id)}/download${query ? `?${query}` : ''}`);
|
|
31
|
+
},
|
|
32
|
+
// Lazily generated image variants (task gap-32): created on first
|
|
33
|
+
// request, served from a stored copy on every one after. `width` must be
|
|
34
|
+
// one of `VARIANT_WIDTHS`; the service answers 400 otherwise.
|
|
35
|
+
getFileVariant: (id, width, format) => call('GET', `/v1/files/${encodeURIComponent(id)}/variants/${width}.${format}`),
|
|
18
36
|
deleteFile: (id) => call('DELETE', `/v1/files/${encodeURIComponent(id)}`),
|
|
19
37
|
/** `path` lists only the files directly in that folder. */
|
|
20
38
|
listFiles: (collection, page = {}) => call('GET', `/v1/collections/${encodeURIComponent(collection)}/files?${new URLSearchParams({
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -39,9 +39,27 @@ export interface StoredFile {
|
|
|
39
39
|
* before this field existed. Derived from the storage backend's own etag
|
|
40
40
|
* for a single-part upload; not present for a multipart one. */
|
|
41
41
|
checksum: string | null;
|
|
42
|
+
/** `"sha256:<hex>"` of the confirmed bytes, computed directly from the
|
|
43
|
+
* bytes rather than derived from a backend etag. `null` when the storage
|
|
44
|
+
* backend exposed no byte access at confirm time, or for a file confirmed
|
|
45
|
+
* before this field existed. */
|
|
46
|
+
sha256: string | null;
|
|
42
47
|
/** The folder inside the collection; `''` is the root. */
|
|
43
48
|
path: string;
|
|
49
|
+
/** The principal (e.g. `"agent:ai-service"` or `"human:alice"`) whose
|
|
50
|
+
* upload confirmed this file at its current version, when that upload is
|
|
51
|
+
* still on record. `null` for a file at version 0 (never confirmed), or
|
|
52
|
+
* when the confirming upload can no longer be found. */
|
|
53
|
+
principalRef: string | null;
|
|
44
54
|
}
|
|
55
|
+
/** Lazily generated image variants (task gap-32), served through
|
|
56
|
+
* `getFileVariant`. A fixed allowlist -- not an arbitrary size -- so a
|
|
57
|
+
* caller cannot mint an unbounded number of billable objects per file.
|
|
58
|
+
* Variant bytes count against the same organisation (and key) byte quota an
|
|
59
|
+
* upload does. */
|
|
60
|
+
export declare const VARIANT_WIDTHS: readonly [64, 256, 1024];
|
|
61
|
+
export type VariantWidth = (typeof VARIANT_WIDTHS)[number];
|
|
62
|
+
export type VariantFormat = 'webp' | 'jpeg';
|
|
45
63
|
export type UploadReservation = {
|
|
46
64
|
uploadId: string;
|
|
47
65
|
fileId: string;
|
package/dist/types.js
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/** Lazily generated image variants (task gap-32), served through
|
|
2
|
+
* `getFileVariant`. A fixed allowlist -- not an arbitrary size -- so a
|
|
3
|
+
* caller cannot mint an unbounded number of billable objects per file.
|
|
4
|
+
* Variant bytes count against the same organisation (and key) byte quota an
|
|
5
|
+
* upload does. */
|
|
6
|
+
export const VARIANT_WIDTHS = [64, 256, 1024];
|