@qmuse/cloud-client 1.0.4 → 1.0.6-dev.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.
- package/README.md +51 -3
- package/dist/adapters.d.ts +17 -1
- package/dist/adapters.d.ts.map +1 -1
- package/dist/adapters.js +22 -2
- package/dist/adapters.js.map +1 -1
- package/dist/auth.d.ts +8 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +224 -51
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +86 -28
- package/dist/client.js.map +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js +23 -2
- package/dist/diagnostics.js.map +1 -1
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -1
- package/dist/files.d.ts +8 -2
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +197 -48
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/jobs.d.ts +11 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +124 -0
- package/dist/jobs.js.map +1 -0
- package/dist/miniapp.d.ts.map +1 -1
- package/dist/miniapp.js +24 -1
- package/dist/miniapp.js.map +1 -1
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/web-session-coordination.d.ts +15 -0
- package/dist/web-session-coordination.d.ts.map +1 -0
- package/dist/web-session-coordination.js +63 -0
- package/dist/web-session-coordination.js.map +1 -0
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +13 -3
- package/dist/web.js.map +1 -1
- package/docs/auth.md +29 -0
- package/docs/files.md +163 -0
- package/docs/jobs.md +66 -0
- package/package.json +1 -1
package/dist/web.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Account, Client, Functions } from 'appwrite';
|
|
2
2
|
import { createAppBaseAccountCapability, createAppBaseFunctionsCapability, createAppBaseWebCloudClient, } from './adapters.js';
|
|
3
3
|
import { QmuseCloudHttpError } from './errors.js';
|
|
4
|
+
import { coordinateWebSessionChanges } from './web-session-coordination.js';
|
|
4
5
|
import { createPreviewDiagnostics } from './preview-diagnostics.js';
|
|
5
6
|
import { initializeQMuseCloudClient, } from './singleton.js';
|
|
6
7
|
export function initQMuseCloudClient(options) {
|
|
@@ -11,8 +12,9 @@ export function initQMuseCloudClient(options) {
|
|
|
11
12
|
.setProject(config.projectId);
|
|
12
13
|
// Shared Hono services allocate a separate physical function ID for each application.
|
|
13
14
|
const diagnostics = createPreviewDiagnostics();
|
|
14
|
-
|
|
15
|
+
const client = createAppBaseWebCloudClient(createAppBaseFunctionsCapability(new Functions(sdk)), {
|
|
15
16
|
functionId: config.functionId,
|
|
17
|
+
fileScope: config,
|
|
16
18
|
...(diagnostics ? { onRequestFailure: diagnostics.report } : {}),
|
|
17
19
|
auth: { account: createAppBaseAccountCapability(new Account(sdk)) },
|
|
18
20
|
fileTransport: createWebFileTransport({
|
|
@@ -24,6 +26,8 @@ export function initQMuseCloudClient(options) {
|
|
|
24
26
|
observeResponseHeaders: session.observeResponseHeaders,
|
|
25
27
|
}),
|
|
26
28
|
});
|
|
29
|
+
coordinateWebSessionChanges(config, client.auth);
|
|
30
|
+
return client;
|
|
27
31
|
});
|
|
28
32
|
}
|
|
29
33
|
const FALLBACK_COOKIE_KEY = 'cookieFallback';
|
|
@@ -114,7 +118,7 @@ export function createWebFileTransport(capabilities) {
|
|
|
114
118
|
...(mimeType ? { mimeType } : {}),
|
|
115
119
|
};
|
|
116
120
|
},
|
|
117
|
-
async upload({ target, file, name, onProgress }) {
|
|
121
|
+
async upload({ target, file, name, onProgress, assertIdentity }) {
|
|
118
122
|
const source = requireBlob(file);
|
|
119
123
|
const chunkSize = target.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
120
124
|
if (!Number.isInteger(chunkSize) || chunkSize < 1)
|
|
@@ -138,6 +142,7 @@ export function createWebFileTransport(capabilities) {
|
|
|
138
142
|
if (!form.has('fileId'))
|
|
139
143
|
form.append('fileId', target.fileId);
|
|
140
144
|
form.append(target.fieldName ?? 'file', body, fileName(source, name));
|
|
145
|
+
assertIdentity?.();
|
|
141
146
|
const headers = withoutContentType({
|
|
142
147
|
...(capabilities.getSessionHeaders?.() ?? {}),
|
|
143
148
|
...(target.headers ?? {}),
|
|
@@ -150,8 +155,10 @@ export function createWebFileTransport(capabilities) {
|
|
|
150
155
|
headers,
|
|
151
156
|
body: form,
|
|
152
157
|
});
|
|
158
|
+
assertIdentity?.();
|
|
153
159
|
capabilities.observeResponseHeaders?.(response.headers);
|
|
154
160
|
metadata = await readJson(response);
|
|
161
|
+
assertIdentity?.();
|
|
155
162
|
if (!response.ok) {
|
|
156
163
|
throw new QmuseCloudHttpError({
|
|
157
164
|
status: response.status,
|
|
@@ -172,12 +179,14 @@ export function createWebFileTransport(capabilities) {
|
|
|
172
179
|
}
|
|
173
180
|
return { fileId: storageId ?? target.fileId, metadata };
|
|
174
181
|
},
|
|
175
|
-
async createReadableUrl({ url, headers }) {
|
|
182
|
+
async createReadableUrl({ url, headers, assertIdentity }) {
|
|
183
|
+
assertIdentity?.();
|
|
176
184
|
const response = await capabilities.fetch(url, {
|
|
177
185
|
method: 'GET',
|
|
178
186
|
credentials: 'include',
|
|
179
187
|
headers: { ...(capabilities.getSessionHeaders?.() ?? {}), ...(headers ?? {}) },
|
|
180
188
|
});
|
|
189
|
+
assertIdentity?.();
|
|
181
190
|
capabilities.observeResponseHeaders?.(response.headers);
|
|
182
191
|
if (!response.ok) {
|
|
183
192
|
throw new QmuseCloudHttpError({
|
|
@@ -187,6 +196,7 @@ export function createWebFileTransport(capabilities) {
|
|
|
187
196
|
});
|
|
188
197
|
}
|
|
189
198
|
const blob = await response.blob();
|
|
199
|
+
assertIdentity?.();
|
|
190
200
|
const createObjectURL = capabilities.createObjectURL ?? URL.createObjectURL.bind(URL);
|
|
191
201
|
const revokeObjectURL = capabilities.revokeObjectURL ?? URL.revokeObjectURL.bind(URL);
|
|
192
202
|
const objectUrl = createObjectURL(blob);
|
package/dist/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EACL,8BAA8B,EAC9B,gCAAgC,EAChC,2BAA2B,GAC5B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
|
package/docs/auth.md
CHANGED
|
@@ -23,9 +23,38 @@ export async function submitAuth(mode: 'login' | 'register', username: string, p
|
|
|
23
23
|
if (mode === 'register') await authService.register(input);
|
|
24
24
|
return authService.login(input);
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
// 仅当认证接口必须原生 HTTP 调用时使用;普通业务继续使用现有 facade。
|
|
28
|
+
import { createWebSessionBridge } from '@qmuse/cloud-client/web';
|
|
29
|
+
const sessionBridge = createWebSessionBridge();
|
|
30
|
+
export async function authHttpRequest(url: string, init: RequestInit): Promise<Response> {
|
|
31
|
+
const headers = new Headers(init.headers);
|
|
32
|
+
for (const [key, value] of Object.entries(sessionBridge.getSessionHeaders())) headers.set(key, value);
|
|
33
|
+
const response = await fetch(url, { ...init, headers, credentials: 'include' });
|
|
34
|
+
sessionBridge.observeResponseHeaders(response.headers);
|
|
35
|
+
return response;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 外部 HTTP 验码已建立 Session,响应凭证保存后强制重新读取账号。
|
|
39
|
+
// 首次读取失败时,重试按钮也只调用此函数,不再次提交验证码。
|
|
40
|
+
export const restoreAfterExternalAuth = (): Promise<CloudAuthUser | null> => authService.restoreSession();
|
|
26
41
|
```
|
|
27
42
|
|
|
28
43
|
- 页面启动先等待 `restoreUser()`;返回用户后才加载私有数据,返回 `null` 时展示登录表单。异常应展示服务错误,不等同于未登录。
|
|
29
44
|
- `register()` 只创建账号,不建立或替换 Session。只有 `submitAuth()` 登录成功后才更新已登录状态、加载私有数据;注册成功而登录失败时,提示账号已创建并引导登录,不自动重新注册。
|
|
30
45
|
- 退出成功后清空页面用户和私有数据缓存;恢复会话为空时同样清空旧状态。
|
|
31
46
|
- 请求失败通过异常返回,私有 API 的 401 按未登录处理;网络错误和 5xx 保留服务异常语义。不记录密码或 Session,不从页面传入角色或用户 ID 代替服务端鉴权。
|
|
47
|
+
- 刷新 Session 或刷新后的账号读取明确返回 401/404 时,SDK 清除缓存身份与过期时间,后续请求不再因旧身份自动反复刷新。429、网络错误和5xx保留缓存身份并将原异常交给调用方,不自动重试。页面仍须在未登录时停止私有请求、保留服务异常并控制人工重试;这个处理不能替代页面请求去重或退避。
|
|
48
|
+
- 部分 AppBase 实例对原生 Session 续期返回 `400 / project_provider_unsupported`。只有此明确类型且 Session 仍在有效期内时,自动刷新才保留现有会话继续业务请求,并停止重复探测该续期能力;其他400、429与服务异常继续抛出。已知不可续期的会话到期后返回401 `AUTH_SESSION_EXPIRED`并清理缓存,要求重新登录。显式 `refreshSession()` 仍保留服务端不支持的错误,不伪造续期成功。
|
|
49
|
+
- Function 完成并返回401 `UNAUTHORIZED`、`AUTH_REQUIRED`或`AUTH_SESSION_EXPIRED`时,SDK清理该次尝试所属的缓存身份,保留错误并且不重放业务请求;传输层401重试后的业务401也遵循此规则。旧请求的迟到401不能清理后来成功建立的身份,其他业务401不自动清理会话。
|
|
50
|
+
- 普通业务请求、文件元数据与访问链接在返回成功响应前核对身份边界;退出、登录、显式恢复会话,或续期发现账号/角色变化后,旧请求返回 `AUTH_STATE_CHANGED`;可信账号资料响应更新角色时同样适用。同账号同角色的正常续期保留合法的在途普通请求。传输层401只在发起身份保持一致时按原策略刷新并重试一次,发现身份变化则停止,不在新账号下重投。该错误不会撤销服务端已完成的写入,应先核对业务结果再决定是否重新提交;页面仍须清理旧用户数据并取消旧任务。此检查依据SDK已经观察到的身份变化,不替代服务端鉴权,也不能发现尚未通知SDK的所有原生Cookie变化。
|
|
51
|
+
- 登录(含第三方和小程序)、退出及退出全部会话一开始就关闭旧身份边界;完成前,新业务请求、会话恢复/刷新及第二次身份变更返回 `AUTH_STATE_CHANGED`。登录成功后开放新身份,退出成功后确认匿名状态并允许公共请求;变更失败时保留真实错误,并先显式恢复会话再提交新业务。会话恢复与刷新只提交自己开始读取时所属状态的结果;旧读取的迟到成功/失败不会恢复旧用户或清理新用户,旧单在途任务的结束也不会清掉新状态下的任务。用户数据不合法时仍返回 `AUTH_USER_INVALID`并清除无效缓存,不把自身清理误报成身份切换。
|
|
52
|
+
- Web 入口按 AppBase endpoint 与 Project 向同源标签页发送不含凭证的会话变更通知;另一个标签页登录、退出或退出全部会话时,清理本页缓存身份与在途请求边界,新业务请求返回 `AUTH_STATE_CHANGED`,直至显式 `restoreSession()` 成功或重新登录成功;`refreshSession()` 不能确认外部身份切换。页面需清空旧用户数据,并在恢复后加载当前用户数据;不自动恢复或重放旧请求。普通请求也携带内部预期账号条件(明确匿名使用非空 `@anonymous`,避免执行链路丢弃空 Header);公共文件入口在无 Session 时也核对条件,拒绝把旧账号意图变成匿名操作;原生核验发现账号不一致或服务端返回409 `AUTH_STATE_CHANGED`时同样要求显式恢复。跨源、存储不可用及绕过 QMuse 的原生会话变更仍需服务端核对预期账号;该条件不授予身份,也不会撤销服务端已执行的写入。
|
|
53
|
+
- 原生 HTTP 认证请求复用 `createWebSessionBridge()`:请求携带 `getSessionHeaders()`,响应到达后立即调用 `observeResponseHeaders(response.headers)`,完成后才恢复 SDK 会话、读取账号。保留 `credentials: 'include'`;无新兜底响应头时保留旧凭证,不读取 HttpOnly Cookie,不记录凭证。手机号验码已建立 Session,不再次创建 Session;验码成功但账号读取失败时只重试读取。
|
|
54
|
+
- 外部验码成功并保存响应凭证后,立即等待 `restoreAfterExternalAuth()`;返回账号才进入已登录状态,返回 `null` 展示登录表单,异常保留真实原因并提供只读取账号的重试。`user_session_already_exists` 同样先恢复已有账号,不自动删除会话。
|
|
55
|
+
- `restoreSession()` 重新读取账号和当前会话;`getCurrentUser()` 初始化后可能返回缓存,包括启动时的 `null`,不能作为外部验码后的首次读取。`refreshSession()` 用于刷新已有会话,不是外部验码后的恢复步骤;不得先刷新会话、忽略刷新异常再读取缓存。
|
|
56
|
+
- `username` 按“内部邮箱用户名 → trim 后的非空姓名 → user_ 加用户 ID 后八位”生成;空姓名允许登录,缺少有效用户 ID 仍拒绝。已有会话冲突时先恢复并读取已有账号,失败展示具体原因,不自动删除会话或宣称已切换账号。
|
|
57
|
+
- 页面实际使用 `user.avatarUrl` 渲染图片(如 `<img src={user.avatarUrl} alt="用户头像" />`);只有 URL 缺失或图片加载失败时才显示 `username` 首字母兜底。不能始终只渲染首字母,也不依赖平台用户头像。
|
|
58
|
+
- `setAvatar({ fileId })` 在请求前检查会话并按已有策略续期。请求期间退出、重新登录或重新恢复会话后,迟到响应返回 `AUTH_STATE_CHANGED`,不覆盖更新的用户缓存;同一用户 ID 也按会话版本区分。该错误不撤销服务端已完成的头像设置,应重新读取当前账号确认结果,不直接重投修改。
|
|
59
|
+
- 头像提交前会通过 Account 读取原生账号,SDK 缓存与原生账号不一致时返回 `AUTH_OWNER_CHANGED`、清理旧缓存并停止提交;读取暂时失败仍返回原错误,不把依赖故障当作退出。请求携带内部预期账号条件,部署端也必须核对它与已认证账号一致,才能覆盖原生核验之后的跨标签切换;该条件不授予身份或角色。
|
|
60
|
+
- 浏览器兜底凭证依赖当前 origin 的 localStorage。临时预览域名改变后不能读取旧域名的凭证,可能需要重新登录;Session 尚未过期不保证跨域名免登录。存储不可用时明确展示会话恢复失败,不以延长 Session 或自动登出规避。
|
package/docs/files.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# File upload recovery
|
|
2
|
+
|
|
3
|
+
This document describes the unreleased recovery candidate. Installing an older
|
|
4
|
+
SDK or upgrading a CLI does not update existing application file services.
|
|
5
|
+
|
|
6
|
+
`files.upload` creates one upload intent, sends bytes through the platform file
|
|
7
|
+
transport, and completes that same intent. A timeout does not prove that either
|
|
8
|
+
Storage or the Function stopped. The SDK therefore does not automatically cancel
|
|
9
|
+
an upload, repeat a file transfer, or refresh and repeat a lifecycle POST.
|
|
10
|
+
|
|
11
|
+
## Persist the original operation
|
|
12
|
+
|
|
13
|
+
Applications can provide an asynchronous `onUploadState` callback:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { QmuseCloudUploadError } from '@qmuse/cloud-client';
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const file = await cloudClient.files.upload({
|
|
20
|
+
resource: 'private-file',
|
|
21
|
+
file: selectedFile,
|
|
22
|
+
idempotencyKey: uploadKey,
|
|
23
|
+
onUploadState: state => privateUploadJournal.save(uploadKey, state),
|
|
24
|
+
});
|
|
25
|
+
await attachToBusinessRecord(file);
|
|
26
|
+
await privateUploadJournal.remove(uploadKey);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (!(error instanceof QmuseCloudUploadError)) throw error;
|
|
29
|
+
// Present a recovery action using error.reference; do not start upload again.
|
|
30
|
+
showUploadRecovery(error);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`privateUploadJournal`, the business attachment operation, and the recovery UI are
|
|
35
|
+
application responsibilities. The SDK does not create a browser or device store.
|
|
36
|
+
Use a key scoped to the application and initiating user, and use one idempotency
|
|
37
|
+
key for one file's bytes. Changing the file requires a new operation.
|
|
38
|
+
|
|
39
|
+
The callback is awaited at these phases:
|
|
40
|
+
|
|
41
|
+
| Phase | Next action |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `intent` | Submit the intent using the saved descriptor and idempotency key |
|
|
44
|
+
| `prepared` | An intent/reference has been received; no bytes have been sent |
|
|
45
|
+
| `uploading` | Start the platform transfer |
|
|
46
|
+
| `uploaded` | The transport returned a receipt for the expected file ID |
|
|
47
|
+
| `completing` | Complete the original upload through the Function |
|
|
48
|
+
|
|
49
|
+
If a checkpoint fails, the next action does not start. A saved `uploading` or
|
|
50
|
+
`completing` state can still represent an unknown outcome after a crash; it is
|
|
51
|
+
not evidence that the associated action failed. An application that omits the
|
|
52
|
+
callback has no SDK-provided durable journal.
|
|
53
|
+
|
|
54
|
+
The reference includes the endpoint, project, physical Function, initiating
|
|
55
|
+
identity and upload/file IDs. Web and mini-program initialization provide this
|
|
56
|
+
context automatically. Custom host adapters must provide `fileScope` and an
|
|
57
|
+
Account capability to restore references in a new client. Unbound custom
|
|
58
|
+
capabilities support references only in the original client instance and reject
|
|
59
|
+
serialized references rather than guessing their destination or owner.
|
|
60
|
+
|
|
61
|
+
## Recover without another upload
|
|
62
|
+
|
|
63
|
+
After restoring the correct application and user, read the saved state and use
|
|
64
|
+
its original reference:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
async function resumeUpload(uploadKey: string) {
|
|
68
|
+
const saved = await privateUploadJournal.read(uploadKey);
|
|
69
|
+
if (!saved?.reference) {
|
|
70
|
+
// Reconcile the original intent submission using its saved input/key.
|
|
71
|
+
return showUnconfirmedIntent(saved);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const file = await cloudClient.files.completeUpload(saved.reference);
|
|
75
|
+
await attachToBusinessRecord(file);
|
|
76
|
+
await privateUploadJournal.remove(uploadKey);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`completeUpload` never creates an intent or sends Storage bytes. The backend
|
|
81
|
+
checks that the existing object is complete and satisfies its file policy.
|
|
82
|
+
Business attachment persistence must also be idempotent: receiving a file record
|
|
83
|
+
does not prove that a separate order, profile, or document update succeeded.
|
|
84
|
+
|
|
85
|
+
Restoring another application, user, or physical Function is rejected before a
|
|
86
|
+
Function mutation. The client verifies native identity and sends an expected-user
|
|
87
|
+
condition; compatible Hono authentication must enforce that condition against
|
|
88
|
+
the verified principal. This condition grants no identity or role. Existing
|
|
89
|
+
create-once backends need an explicit migration; a new SDK alone does not add
|
|
90
|
+
the server check or file lifecycle coordination.
|
|
91
|
+
|
|
92
|
+
The built-in Web and mini-program transports check the upload's Session
|
|
93
|
+
generation before sending each chunk and before accepting its response. An
|
|
94
|
+
observed logout, account change, or Session replacement stops unsent chunks;
|
|
95
|
+
stale responses cannot update fallback Session storage or report new progress.
|
|
96
|
+
Mini-program chunks created before the change are still removed locally. Custom
|
|
97
|
+
transports must honor the optional `assertIdentity` hook at the same boundaries.
|
|
98
|
+
The original reference is retained; the SDK does not automatically cancel or
|
|
99
|
+
retransmit the upload.
|
|
100
|
+
|
|
101
|
+
These checks do not atomically freeze a browser cookie or a native Storage
|
|
102
|
+
request across tabs. In-flight Storage identity changes and transport-specific
|
|
103
|
+
resumption need separate platform validation. An error/reference is not proof
|
|
104
|
+
that a partially uploaded object has been deleted.
|
|
105
|
+
|
|
106
|
+
File access requests also retain their request identity until the returned URL
|
|
107
|
+
is ready. For `authenticated-url` access, the built-in Web transport checks again
|
|
108
|
+
before reading Storage, accepting its Session headers, and creating a Blob URL.
|
|
109
|
+
A custom transport's late result is disposed before an identity rejection.
|
|
110
|
+
Same-user, same-role Session renewal preserves an in-flight read; logout,
|
|
111
|
+
explicit restore, a different user, or an observed role change invalidates it.
|
|
112
|
+
Custom readable transports must honor their optional `assertIdentity` hook.
|
|
113
|
+
These checks do not revoke a remote public or token URL already returned to the
|
|
114
|
+
application.
|
|
115
|
+
|
|
116
|
+
## Explicit preparation and cancellation
|
|
117
|
+
|
|
118
|
+
Applications that separate preparation from transfer can use:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
const prepared = await cloudClient.files.prepareUpload({
|
|
122
|
+
resource: 'private-file',
|
|
123
|
+
name: 'document.pdf',
|
|
124
|
+
size: documentSize,
|
|
125
|
+
mimeType: 'application/pdf',
|
|
126
|
+
idempotencyKey: uploadKey,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// If no transfer was started and the user abandons this intent:
|
|
130
|
+
await cloudClient.files.cancelUpload(prepared.reference);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`cancelUpload` is an explicit decision. It does not abort a Storage request and
|
|
134
|
+
must not be used as automatic cleanup after a network error. Observe or stop
|
|
135
|
+
outstanding transport work first; reconcile unknown completion using the
|
|
136
|
+
original reference. A compatible backend must coordinate completion and
|
|
137
|
+
cancellation transactionally. Legacy independent read/write implementations can
|
|
138
|
+
still race even when SDK automatic cancellation has been removed.
|
|
139
|
+
|
|
140
|
+
Cancellation failure is returned to the caller. The SDK does not swallow it or
|
|
141
|
+
treat every 404 as proof of physical Storage absence. A metadata expiry only
|
|
142
|
+
limits completion credentials; file/orphan cleanup requires a separate backend
|
|
143
|
+
mechanism.
|
|
144
|
+
|
|
145
|
+
## Anonymous credentials and errors
|
|
146
|
+
|
|
147
|
+
An anonymous `public-file` reference contains its completion credential. Store it
|
|
148
|
+
only in private scoped storage; do not log or send it to diagnostic observers.
|
|
149
|
+
The SDK does not create a guest Session. Anonymous completion can resume once a
|
|
150
|
+
reference has been received, within the backend's credential lifetime. Protected
|
|
151
|
+
delete/cancel is unavailable to anonymous callers.
|
|
152
|
+
|
|
153
|
+
The current backend generates the anonymous credential in the intent response.
|
|
154
|
+
If that first response is lost, the idempotency key alone cannot recover it.
|
|
155
|
+
This candidate does not promise anonymous recovery for that boundary, automatic
|
|
156
|
+
orphan deletion, or a browser/device persistence implementation.
|
|
157
|
+
|
|
158
|
+
`QmuseCloudUploadError` preserves `code`, a known HTTP `status`, `phase`,
|
|
159
|
+
`reference` and the intent descriptor. Known business rejections retain their
|
|
160
|
+
public message; unknown/native failures use a generic message. Recovery fields
|
|
161
|
+
are non-enumerable, and the original `cause` is available on explicit access
|
|
162
|
+
rather than dumped by ordinary JSON/Node error inspection. Explicitly serializing
|
|
163
|
+
a reference or cause remains a private-data operation.
|
package/docs/jobs.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Authenticated async Cloud API jobs
|
|
2
|
+
|
|
3
|
+
`client.jobs.start(request)` submits one native async Function execution and returns
|
|
4
|
+
`{ executionId, ownerId }`. `client.jobs.get<T>(job)` reads that same execution once.
|
|
5
|
+
Polling and durable business intent storage belong to the application.
|
|
6
|
+
|
|
7
|
+
The official Web and miniapp adapters bind both methods to the configured physical
|
|
8
|
+
Function. They expose no database client, project key, alternate Function selector
|
|
9
|
+
or caller-supplied ownership grant. Older custom adapters without explicit async
|
|
10
|
+
and execution-read capabilities return `JOBS_UNAVAILABLE`; synchronous `request`
|
|
11
|
+
behavior remains available.
|
|
12
|
+
|
|
13
|
+
Before submitting, persist a business idempotency key and exact content hash and
|
|
14
|
+
atomically claim the intent across tabs. Save the returned reference as soon as
|
|
15
|
+
the acknowledgement arrives. Store the reference under its deployment context
|
|
16
|
+
and user; an execution ID is not an authorization token.
|
|
17
|
+
|
|
18
|
+
`start` validates native Session ownership before sending the request. It never
|
|
19
|
+
automatically retries the submission, including on transport 401/504 or a missing
|
|
20
|
+
execution ID. `JOB_NOT_SUBMITTED` and preflight `JOB_OWNER_MISMATCH` occur before
|
|
21
|
+
the submission transport is called. A transport failure or missing acknowledgement
|
|
22
|
+
may follow an accepted operation: reconcile authoritative business state before a
|
|
23
|
+
user explicitly retries the same intent, key and content.
|
|
24
|
+
|
|
25
|
+
`get` returns:
|
|
26
|
+
|
|
27
|
+
- `pending` for native `waiting` or `processing`. Some deployments retain
|
|
28
|
+
`waiting` throughout execution; it does not prove a queue position or progress.
|
|
29
|
+
- `completed` with the normal HTTP response for a successful business result.
|
|
30
|
+
- `failed` with `failure.kind = http` for a completed business rejection, or
|
|
31
|
+
`failure.kind = execution` for a native execution failure. A failed execution
|
|
32
|
+
does not prove that its business transaction did not commit.
|
|
33
|
+
|
|
34
|
+
Execution results are immutable snapshots of that operation, not the latest
|
|
35
|
+
business record. For example, a recovered submission can still return
|
|
36
|
+
`submitted` at version 1 after the record has advanced to `approved` at version 4.
|
|
37
|
+
Keep the execution receipt separate from the screen's current record. After
|
|
38
|
+
recovery, read the owner-scoped business API when the screen needs current state;
|
|
39
|
+
where the business exposes a monotonic version, do not overwrite a newer record
|
|
40
|
+
with an older receipt. Reading an old result must never start a replacement job.
|
|
41
|
+
|
|
42
|
+
Native polling 401 may refresh the Session once and repeat only GET for the same
|
|
43
|
+
ID. A polling 404 checks native identity to detect a Session changed in another
|
|
44
|
+
tab; it does not start a replacement execution. When native identity differs,
|
|
45
|
+
the stale local identity is cleared. Authentication changes while a request is
|
|
46
|
+
in flight prevent its result from crossing into another user's state.
|
|
47
|
+
|
|
48
|
+
Every `start` also attaches the SDK-owned `x-qmuse-expected-user-id` condition.
|
|
49
|
+
The updated Hono Function authentication helper compares it with the verified
|
|
50
|
+
native principal before creating database capabilities or running business code.
|
|
51
|
+
This closes the gap when another tab changes the Session after the pre-submit
|
|
52
|
+
identity read. The condition cannot select a user or grant access. A mismatch
|
|
53
|
+
returns `409 AUTH_STATE_CHANGED`; polling clears only the initiating SDK's stale
|
|
54
|
+
local identity, without deleting the other tab's native Session or resubmitting.
|
|
55
|
+
Server enforcement requires the updated Function helper: the SDK alone cannot
|
|
56
|
+
make an older deployed Function enforce this condition.
|
|
57
|
+
|
|
58
|
+
For batch imports, the business success marker must commit in the same transaction
|
|
59
|
+
as every inventory change. On missing execution records, worker failure or a lost
|
|
60
|
+
acknowledgement, query that owner-scoped marker with the original key and content
|
|
61
|
+
hash. No marker means **not confirmed**, rather than safely failed. Reloads and
|
|
62
|
+
polling failures must never generate a new idempotency key or resubmit by themselves.
|
|
63
|
+
|
|
64
|
+
These APIs are an unpublished candidate until the package is released. A frozen
|
|
65
|
+
SDK copy in a synthetic DEV acceptance application proves only that candidate;
|
|
66
|
+
it does not upgrade existing applications or the main sandbox runtime.
|