ccs-files-user-client changelog
Versions follow semver. For the package itself see ccs-files-user-client. The reference is at /sdks/ccs-files-user-client/reference/.
1.3.0 (2026-10-25)
Section titled “1.3.0 (2026-10-25)”Default endpoint. Source-compatible with 1.2.0.
FilesClientOptions.apiUrlis optional (core,createFilesin/angular,useFilesin/react): omitted, the production API,DEFAULT_API_URL(https://files.centralcodestation.com/api/v1, exported from the package root). Still zero runtime dependencies. A browser reads no environment: passapiUrlfor another environment, or keep usingFilesClient.fromTokenRoute(unchanged), whose backend sendsapi_urlfor the environment it runs in.
Changed
Section titled “Changed”- A blank
apiUrlthrows “apiUrl must not be blank (omit it for the production API)” instead of “apiUrl is required”.
1.2.0 (2026-10-24)
Section titled “1.2.0 (2026-10-24)”Application-managed folders, as the File Service now serves them. Source-compatible with 1.1.0.
- Application-managed folders.
FileandFoldergainmanaged(truefor a folder a tenant’s application manages and everything below it) andmanaged_by(ManagedBy:{ client_id, name, managed_folder_id, managed_at },nullwhen not managed; the nearest marked folder with nested marks). For people such items are read-only. isReadOnly(item)(core entry):truewhenitem.managed === true; decide the editing controls from it, not frommy_actions.folders.releaseManagement(folderId, { reason })(POST P/folders/:folder_id/release-management, input typeReleaseManagementInput) resolves with theFolder: the tenant owner’s emergency release of a mark, audited with the reason. Never retried.
Errors
Section titled “Errors”folder_managed(403, aFilesForbiddenErrorwithbody.managed_folder_id): a change people cannot make inside a managed folder (uploads, versions, rename, move, edits, copy in, trash, restore, purge, permissions, share links).FilesForbiddenError.managedFolderIdreads the managing folder id (nullon other codes) andisFolderManagedError(error)narrows to it.tenant_owner_required(403) answersfolders.releaseManagementfor anyone but the tenant owner; 400invalid_requestfor a folder that does not itself carry the mark.
1.1.0 (2026-10-23)
Section titled “1.1.0 (2026-10-23)”Legal hold, and the search wording brought in line with the service. Source-compatible with 1.0.0.
- Legal hold.
FileHold({ reason, placed_by, placed_at, until });File.holdisFileHold | null(1.0.0 typed it as an untyped record).files.hold.place(fileId, { reason, until? })(PUT P/files/:file_id/hold: places the hold, or replaces the reason and the end of the one in place) andfiles.hold.release(fileId, { reason? })(DELETE P/files/:file_id/hold, the reason kept in the audit log) resolve with theFile;holds.list({ placed_by, after, limit })(GET P/holds) pages the held files, newest hold first. Input typesPlaceHoldInput,ReleaseHoldInput,HoldsQuery; resource typesHoldResource,HoldsResource. They need thefiles.managepermission (403missing_capabilityotherwise).
Changed
Section titled “Changed”- Search documentation:
in: ['name']matches names that start with the query, case-insensitively (a prefix, not a substring);keywordsmatches whole words of the title, description, tags, category, department and custom values; the default falls back to the name prefix when no whole word matches.SearchResult.totalis exact up to 10,000 andnullabove.
Errors
Section titled “Errors”file_on_hold(409, aFilesConflictErrorwithbody.hold): purging a held file or deleting one of its versions (files.versions.delete) while the hold is in force.
1.0.0 (2026-10-23)
Section titled “1.0.0 (2026-10-23)”First release: the web user client of the File Service, for a signed-in user of a tenant’s web app.
- Token route:
createTokenProvider({ url, headers, credentials, method, fetch, expiryMarginSeconds })(cached until a minute before expiry, one request in flight,clear(),getConfig()for the route’s optionalapi_url,tenant_id,application_id) andFilesClient.fromTokenRoute(tokens, overrides). - Uploads:
client.upload(file, input, { concurrency, onProgress, signal })returns anUploadHandle(id,fileId,uploadId,state,progresswith bytes in flight and parts,done,pause(),resume(),cancel(),on('progress' | 'state' | 'error'),serialize()). Statescreating,uploading,paused,completing,done,failed,cancelled. A single PUT sends exactly the ticket’s headers; multipart sends 4 parts in flight (concurrency), gets part URLs beyond the ticket’s in batches of 100, retries each PUT 5 times with full-jitter backoff (1 s to 30 s) on network errors and 5xx, re-requests an expired part URL once on a 403, and completes with everyETag. A 413 or 422 on the ticket fails the upload before any byte is sent. A failed upload keeps its ticket:resume()continues it. - Resume after a reload:
client.resumeUpload(snapshot, file)continues an open multipart ticket from the parts the store holds (GET P/uploads/:upload_id), resolves a ticket that was completed meanwhile, and starts over otherwise; another file (size orlastModified) throwsUploadFileMismatchErrorat once. Client snapshots hold no signed URL. - Flow A: static
FilesClient.uploadFromTicket(ticketOrSnapshot, file, { partUrls, xhrFactory, fetch, concurrency, onProgress, signal })runs the same engine on a ticket your backend created, with no Files token;doneresolves with{ upload_id, file_id, method, parts: [{ part_number, etag }] }for the backend to complete. - Versions:
files.versions.upload(fileId, file, input, options)through the same engine;files.versionslist,get,restore,pin,delete;files.renditionslist,regenerate. - Browse and show:
folders(root,create,get,children,path,update,move,copy,delete,restore),files(get,update,move,copy,delete,restore,download({ navigate }),downloadUrl,myPermissions,waitUntilReady),preview(fileId, { version }),urls(fileIds, { rendition, disposition }),invalidate(fileId),search(query)(within: ['content']and highlights),tags(query),trash.list,me.capabilities(),settings.public(). Preview and download URLs are cached per file, rendition and disposition until a minute before they expire;playbackSources(preview)lists the readymp4_1080pandmp4_720prenditions and the original. - Sharing:
permissions(get,replace,grant,revoke,roles) andshares(create,list,revoke). - Lifecycle:
signOut()cancels the uploads, clears the caches and the token provider;dispose()pauses the uploads (their tickets stay resumable) and releases the client. - Requests: a 401 asks for a fresh token (
{ forceRefresh: true }) and replays once; 5xx (not 501) and network errors are retried (maxRetries, default 3) on reads, idempotent writes and the writes that create, which carry anIdempotency-Keyfixed before the first attempt;If-Matchthrough{ ifMatch }. - Errors:
FilesApiError(status,code,body,retryAfterSeconds),FilesUnauthorizedError,FilesForbiddenError,FilesNotFoundError,FilesConflictError,FilesPreconditionFailedError,FilesPayloadTooLargeError,FilesUnprocessableError,FilesRateLimitedError,FilesNotImplementedError,FilesContextError,FilesUploadError(partNumber,uploadId,cause),UploadFileMismatchErrorandUploadCancelledError. - Angular (
/angular):createFiles(optionsOrClient, destroyRef?)with theuploads()Signal. React (/react):useFiles(options),useUpload(client)({ start, resume, uploads }),usePreview(client, fileId, { version, refresh }). - Zero runtime dependencies; Angular and React are optional peer dependencies. ESM and CommonJS builds with declarations;
XMLHttpRequestfor upload progress (xhrFactory),fetchwhere there is none.